Added VBALink to the SVN code. Note that this is completely untested

This commit is contained in:
mudlord 2007-10-30 19:04:22 +00:00
commit 8bda069b3b
361 changed files with 194240 additions and 0 deletions

406
Gb_Apu/Blip_Buffer.cpp Normal file
View File

@ -0,0 +1,406 @@
// Blip_Buffer 0.4.0. http://www.slack.net/~ant/
#include "Blip_Buffer.h"
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
/* Copyright (C) 2003-2006 Shay Green. This module 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
module 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 module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
int const buffer_extra = blip_widest_impulse_ + 2;
Blip_Buffer::Blip_Buffer()
{
factor_ = LONG_MAX;
offset_ = 0;
buffer_ = 0;
buffer_size_ = 0;
sample_rate_ = 0;
reader_accum = 0;
bass_shift = 0;
clock_rate_ = 0;
bass_freq_ = 16;
length_ = 0;
// assumptions code makes about implementation-defined features
#ifndef NDEBUG
// right shift of negative value preserves sign
buf_t_ i = -0x7FFFFFFE;
assert( (i >> 1) == -0x3FFFFFFF );
// casting to short truncates to 16 bits and sign-extends
i = 0x18000;
assert( (short) i == -0x8000 );
#endif
}
Blip_Buffer::~Blip_Buffer()
{
free( buffer_ );
}
void Blip_Buffer::clear( int entire_buffer )
{
offset_ = 0;
reader_accum = 0;
if ( buffer_ )
{
long count = (entire_buffer ? buffer_size_ : samples_avail());
memset( buffer_, 0, (count + buffer_extra) * sizeof (buf_t_) );
}
}
Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
{
// start with maximum length that resampled time can represent
long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - buffer_extra - 64;
if ( msec != blip_max_length )
{
long s = (new_rate * (msec + 1) + 999) / 1000;
if ( s < new_size )
new_size = s;
else
assert( 0 ); // fails if requested buffer length exceeds limit
}
if ( buffer_size_ != new_size )
{
void* p = realloc( buffer_, (new_size + buffer_extra) * sizeof *buffer_ );
if ( !p )
return "Out of memory";
buffer_ = (buf_t_*) p;
}
buffer_size_ = new_size;
// update things based on the sample rate
sample_rate_ = new_rate;
length_ = new_size * 1000 / new_rate - 1;
if ( msec )
assert( length_ == msec ); // ensure length is same as that passed in
if ( clock_rate_ )
clock_rate( clock_rate_ );
bass_freq( bass_freq_ );
clear();
return 0; // success
}
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long clock_rate ) const
{
double ratio = (double) sample_rate_ / clock_rate;
long factor = (long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
return (blip_resampled_time_t) factor;
}
void Blip_Buffer::bass_freq( int freq )
{
bass_freq_ = freq;
int shift = 31;
if ( freq > 0 )
{
shift = 13;
long f = (freq << 16) / sample_rate_;
while ( (f >>= 1) && --shift ) { }
}
bass_shift = shift;
}
void Blip_Buffer::end_frame( blip_time_t t )
{
offset_ += t * factor_;
assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length
}
void Blip_Buffer::remove_silence( long count )
{
assert( count <= samples_avail() ); // tried to remove more samples than available
offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
}
long Blip_Buffer::count_samples( blip_time_t t ) const
{
unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
return (long) (last_sample - first_sample);
}
blip_time_t Blip_Buffer::count_clocks( long count ) const
{
if ( count > buffer_size_ )
count = buffer_size_;
blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
}
void Blip_Buffer::remove_samples( long count )
{
if ( count )
{
remove_silence( count );
// copy remaining samples to beginning and clear old samples
long remain = samples_avail() + buffer_extra;
memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
memset( buffer_ + remain, 0, count * sizeof *buffer_ );
}
}
// Blip_Synth_
Blip_Synth_::Blip_Synth_( short* p, int w ) :
impulses( p ),
width( w )
{
volume_unit_ = 0.0;
kernel_unit = 0;
buf = 0;
last_amp = 0;
delta_factor = 0;
}
static double const pi = 3.1415926535897932384626433832795029;
static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
{
if ( cutoff >= 0.999 )
cutoff = 0.999;
if ( treble < -300.0 )
treble = -300.0;
if ( treble > 5.0 )
treble = 5.0;
double const maxh = 4096.0;
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
double const to_angle = pi / 2 / maxh / oversample;
for ( int i = 0; i < count; i++ )
{
double angle = ((i - count) * 2 + 1) * to_angle;
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
double cos_nc_angle = cos( maxh * cutoff * angle );
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
double cos_angle = cos( angle );
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
double b = 2.0 - cos_angle - cos_angle;
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
}
}
void blip_eq_t::generate( float* out, int count ) const
{
// lower cutoff freq for narrow kernels with their wider transition band
// (8 points->1.49, 16 points->1.15)
double oversample = blip_res * 2.25 / count + 0.85;
double half_rate = sample_rate * 0.5;
if ( cutoff_freq )
oversample = half_rate / cutoff_freq;
double cutoff = rolloff_freq * oversample / half_rate;
gen_sinc( out, count, blip_res * oversample, treble, cutoff );
// apply (half of) hamming window
double to_fraction = pi / (count - 1);
for ( int i = count; i--; )
out [i] *= 0.54 - 0.46 * cos( i * to_fraction );
}
void Blip_Synth_::adjust_impulse()
{
// sum pairs for each phase and add error correction to end of first half
int const size = impulses_size();
for ( int p = blip_res; p-- >= blip_res / 2; )
{
int p2 = blip_res - 2 - p;
long error = kernel_unit;
for ( int i = 1; i < size; i += blip_res )
{
error -= impulses [i + p ];
error -= impulses [i + p2];
}
if ( p == p2 )
error /= 2; // phase = 0.5 impulse uses same half for both sides
impulses [size - blip_res + p] += error;
//printf( "error: %ld\n", error );
}
//for ( int i = blip_res; i--; printf( "\n" ) )
// for ( int j = 0; j < width / 2; j++ )
// printf( "%5ld,", impulses [j * blip_res + i + 1] );
}
void Blip_Synth_::treble_eq( blip_eq_t const& eq )
{
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
int const half_size = blip_res / 2 * (width - 1);
eq.generate( &fimpulse [blip_res], half_size );
int i;
// need mirror slightly past center for calculation
for ( i = blip_res; i--; )
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
// starts at 0
for ( i = 0; i < blip_res; i++ )
fimpulse [i] = 0.0f;
// find rescale factor
double total = 0.0;
for ( i = 0; i < half_size; i++ )
total += fimpulse [blip_res + i];
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
//double const base_unit = 37888.0; // allows treble to +5 dB
double const base_unit = 32768.0; // necessary for blip_unscaled to work
double rescale = base_unit / 2 / total;
kernel_unit = (long) base_unit;
// integrate, first difference, rescale, convert to int
double sum = 0.0;
double next = 0.0;
int const impulses_size = this->impulses_size();
for ( i = 0; i < impulses_size; i++ )
{
impulses [i] = (short) floor( (next - sum) * rescale + 0.5 );
sum += fimpulse [i];
next += fimpulse [i + blip_res];
}
adjust_impulse();
// volume might require rescaling
double vol = volume_unit_;
if ( vol )
{
volume_unit_ = 0.0;
volume_unit( vol );
}
}
void Blip_Synth_::volume_unit( double new_unit )
{
if ( new_unit != volume_unit_ )
{
// use default eq if it hasn't been set yet
if ( !kernel_unit )
treble_eq( -8.0 );
volume_unit_ = new_unit;
double factor = new_unit * (1L << blip_sample_bits) / kernel_unit;
if ( factor > 0.0 )
{
int shift = 0;
// if unit is really small, might need to attenuate kernel
while ( factor < 2.0 )
{
shift++;
factor *= 2.0;
}
if ( shift )
{
kernel_unit >>= shift;
assert( kernel_unit > 0 ); // fails if volume unit is too low
// keep values positive to avoid round-towards-zero of sign-preserving
// right shift for negative values
long offset = 0x8000 + (1 << (shift - 1));
long offset2 = 0x8000 >> shift;
for ( int i = impulses_size(); i--; )
impulses [i] = (short) (((impulses [i] + offset) >> shift) - offset2);
adjust_impulse();
}
}
delta_factor = (int) floor( factor + 0.5 );
//printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit );
}
}
long Blip_Buffer::read_samples( blip_sample_t* out, long max_samples, int stereo )
{
long count = samples_avail();
if ( count > max_samples )
count = max_samples;
if ( count )
{
int const sample_shift = blip_sample_bits - 16;
int const bass_shift = this->bass_shift;
long accum = reader_accum;
buf_t_* in = buffer_;
if ( !stereo )
{
for ( long n = count; n--; )
{
long s = accum >> sample_shift;
accum -= accum >> bass_shift;
accum += *in++;
*out++ = (blip_sample_t) s;
// clamp sample
if ( (blip_sample_t) s != s )
out [-1] = (blip_sample_t) (0x7FFF - (s >> 24));
}
}
else
{
for ( long n = count; n--; )
{
long s = accum >> sample_shift;
accum -= accum >> bass_shift;
accum += *in++;
*out = (blip_sample_t) s;
out += 2;
// clamp sample
if ( (blip_sample_t) s != s )
out [-2] = (blip_sample_t) (0x7FFF - (s >> 24));
}
}
reader_accum = accum;
remove_samples( count );
}
return count;
}
void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
{
buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
int const sample_shift = blip_sample_bits - 16;
int prev = 0;
while ( count-- )
{
long s = (long) *in++ << sample_shift;
*out += s - prev;
prev = s;
++out;
}
*out -= prev;
}

354
Gb_Apu/Blip_Buffer.h Normal file
View File

@ -0,0 +1,354 @@
// Band-limited sound synthesis and buffering
// Blip_Buffer 0.4.0
#ifndef BLIP_BUFFER_H
#define BLIP_BUFFER_H
// Time unit at source clock rate
typedef long blip_time_t;
// Output samples are 16-bit signed, with a range of -32768 to 32767
typedef short blip_sample_t;
enum { blip_sample_max = 32767 };
class Blip_Buffer {
public:
typedef const char* blargg_err_t;
// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
// isn't enough memory, returns error without affecting current buffer setup.
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
// Set number of source time units per second
void clock_rate( long );
// End current time frame of specified duration and make its samples available
// (along with any still-unread samples) for reading with read_samples(). Begins
// a new time frame at the end of the current frame.
void end_frame( blip_time_t time );
// Read at most 'max_samples' out of buffer into 'dest', removing them from from
// the buffer. Returns number of samples actually read and removed. If stereo is
// true, increments 'dest' one extra time after writing each sample, to allow
// easy interleving of two channels into a stereo output buffer.
long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
// Additional optional features
// Current output sample rate
long sample_rate() const;
// Length of buffer, in milliseconds
int length() const;
// Number of source time units per second
long clock_rate() const;
// Set frequency high-pass filter frequency, where higher values reduce bass more
void bass_freq( int frequency );
// Number of samples delay from synthesis to samples read out
int output_latency() const;
// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
// false, just clears out any samples waiting rather than the entire buffer.
void clear( int entire_buffer = 1 );
// Number of samples available for reading with read_samples()
long samples_avail() const;
// Remove 'count' samples from those waiting to be read
void remove_samples( long count );
// Experimental features
// Number of raw samples that can be mixed within frame of specified duration.
long count_samples( blip_time_t duration ) const;
// Mix 'count' samples from 'buf' into buffer.
void mix_samples( blip_sample_t const* buf, long count );
// Count number of clocks needed until 'count' samples will be available.
// If buffer can't even hold 'count' samples, returns number of clocks until
// buffer becomes full.
blip_time_t count_clocks( long count ) const;
// not documented yet
typedef unsigned long blip_resampled_time_t;
void remove_silence( long count );
blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
public:
Blip_Buffer();
~Blip_Buffer();
// Deprecated
typedef blip_resampled_time_t resampled_time_t;
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
private:
// noncopyable
Blip_Buffer( const Blip_Buffer& );
Blip_Buffer& operator = ( const Blip_Buffer& );
public:
typedef long buf_t_;
unsigned long factor_;
blip_resampled_time_t offset_;
buf_t_* buffer_;
long buffer_size_;
private:
long reader_accum;
int bass_shift;
long sample_rate_;
long clock_rate_;
int bass_freq_;
int length_;
friend class Blip_Reader;
};
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
// but reduce maximum buffer size.
#ifndef BLIP_BUFFER_ACCURACY
#define BLIP_BUFFER_ACCURACY 16
#endif
// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
// noticeable broadband noise when synthesizing high frequency square waves.
// Affects size of Blip_Synth objects since they store the waveform directly.
#ifndef BLIP_PHASE_BITS
#define BLIP_PHASE_BITS 6
#endif
// Internal
typedef unsigned long blip_resampled_time_t;
int const blip_widest_impulse_ = 16;
int const blip_res = 1 << BLIP_PHASE_BITS;
class blip_eq_t;
class Blip_Synth_ {
double volume_unit_;
short* const impulses;
int const width;
long kernel_unit;
int impulses_size() const { return blip_res / 2 * width + 1; }
void adjust_impulse();
public:
Blip_Buffer* buf;
int last_amp;
int delta_factor;
Blip_Synth_( short* impulses, int width );
void treble_eq( blip_eq_t const& );
void volume_unit( double );
};
// Quality level. Start with blip_good_quality.
const int blip_med_quality = 8;
const int blip_good_quality = 12;
const int blip_high_quality = 16;
// Range specifies the greatest expected change in amplitude. Calculate it
// by finding the difference between the maximum and minimum expected
// amplitudes (max - min).
template<int quality,int range>
class Blip_Synth {
public:
// Set overall volume of waveform
void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
// Configure low-pass filter (see notes.txt)
void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
// Get/set Blip_Buffer used for output
Blip_Buffer* output() const { return impl.buf; }
void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
// Update amplitude of waveform at given time. Using this requires a separate
// Blip_Synth for each waveform.
void update( blip_time_t time, int amplitude );
// Low-level interface
// Add an amplitude transition of specified delta, optionally into specified buffer
// rather than the one set with output(). Delta can be positive or negative.
// The actual change in amplitude is delta * (volume / range)
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
// Works directly in terms of fractional output samples. Contact author for more.
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
// Same as offset(), except code is inlined for higher performance
void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}
void offset_inline( blip_time_t t, int delta ) const {
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}
public:
Blip_Synth() : impl( impulses, quality ) { }
private:
typedef short imp_t;
imp_t impulses [blip_res * (quality / 2) + 1];
Blip_Synth_ impl;
};
// Low-pass equalization parameters
class blip_eq_t {
public:
// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
// treble, small positive values (0 to 5.0) increase treble.
blip_eq_t( double treble_db = 0 );
// See notes.txt
blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
private:
double treble;
long rolloff_freq;
long sample_rate;
long cutoff_freq;
void generate( float* out, int count ) const;
friend class Blip_Synth_;
};
int const blip_sample_bits = 30;
// Optimized inline sample reader for custom sample formats and mixing of Blip_Buffer samples
class Blip_Reader {
public:
// Begin reading samples from buffer. Returns value to pass to next() (can
// be ignored if default bass_freq is acceptable).
int begin( Blip_Buffer& );
// Current sample
long read() const { return accum >> (blip_sample_bits - 16); }
// Current raw sample in full internal resolution
long read_raw() const { return accum; }
// Advance to next sample
void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
// End reading samples from buffer. The number of samples read must now be removed
// using Blip_Buffer::remove_samples().
void end( Blip_Buffer& b ) { b.reader_accum = accum; }
private:
const Blip_Buffer::buf_t_* buf;
long accum;
};
// End of public interface
#include <assert.h>
// Compatibility with older version
const long blip_unscaled = 65535;
const int blip_low_quality = blip_med_quality;
const int blip_best_quality = blip_high_quality;
#define BLIP_FWD( i ) { \
long t0 = i0 * delta + buf [fwd + i]; \
long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i]; \
i0 = imp [blip_res * (i + 2)]; \
buf [fwd + i] = t0; \
buf [fwd + 1 + i] = t1; }
#define BLIP_REV( r ) { \
long t0 = i0 * delta + buf [rev - r]; \
long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r]; \
i0 = imp [blip_res * (r - 1)]; \
buf [rev - r] = t0; \
buf [rev + 1 - r] = t1; }
template<int quality,int range>
inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
int delta, Blip_Buffer* blip_buf ) const
{
// Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
// need for a longer buffer as set by set_sample_rate().
assert( (long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
delta *= impl.delta_factor;
int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
imp_t const* imp = impulses + blip_res - phase;
long* buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
long i0 = *imp;
int const fwd = (blip_widest_impulse_ - quality) / 2;
int const rev = fwd + quality - 2;
BLIP_FWD( 0 )
if ( quality > 8 ) BLIP_FWD( 2 )
if ( quality > 12 ) BLIP_FWD( 4 )
{
int const mid = quality / 2 - 1;
long t0 = i0 * delta + buf [fwd + mid - 1];
long t1 = imp [blip_res * mid] * delta + buf [fwd + mid];
imp = impulses + phase;
i0 = imp [blip_res * mid];
buf [fwd + mid - 1] = t0;
buf [fwd + mid] = t1;
}
if ( quality > 12 ) BLIP_REV( 6 )
if ( quality > 8 ) BLIP_REV( 4 )
BLIP_REV( 2 )
long t0 = i0 * delta + buf [rev];
long t1 = *imp * delta + buf [rev + 1];
buf [rev] = t0;
buf [rev + 1] = t1;
}
#undef BLIP_FWD
#undef BLIP_REV
template<int quality,int range>
void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
{
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}
template<int quality,int range>
void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
{
int delta = amp - impl.last_amp;
impl.last_amp = amp;
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}
inline blip_eq_t::blip_eq_t( double t ) :
treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
inline int Blip_Buffer::length() const { return length_; }
inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
inline long Blip_Buffer::sample_rate() const { return sample_rate_; }
inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
inline long Blip_Buffer::clock_rate() const { return clock_rate_; }
inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
{
buf = blip_buf.buffer_;
accum = blip_buf.reader_accum;
return blip_buf.bass_shift;
}
int const blip_max_length = 0;
int const blip_default_length = 250;
#endif

204
Gb_Apu/Blip_Synth.h Normal file
View File

@ -0,0 +1,204 @@
// Blip_Synth and Blip_Wave are waveform transition synthesizers for adding
// waveforms to a Blip_Buffer.
// Blip_Buffer 0.3.3. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
#ifndef BLIP_SYNTH_H
#define BLIP_SYNTH_H
#ifndef BLIP_BUFFER_H
#include "Blip_Buffer.h"
#endif
// Quality level. Higher levels are slower, and worse in a few cases.
// Use blip_good_quality as a starting point.
const int blip_low_quality = 1;
const int blip_med_quality = 2;
const int blip_good_quality = 3;
const int blip_high_quality = 4;
// Blip_Synth is a transition waveform synthesizer which adds band-limited
// offsets (transitions) into a Blip_Buffer. For a simpler interface, use
// Blip_Wave (below).
//
// Range specifies the greatest expected offset that will occur. For a
// waveform that goes between +amp and -amp, range should be amp * 2 (half
// that if it only goes between +amp and 0). When range is large, a higher
// accuracy scheme is used; to force this even when range is small, pass
// the negative of range (i.e. -range).
template<int quality,int range>
class Blip_Synth {
BOOST_STATIC_ASSERT( 1 <= quality && quality <= 5 );
BOOST_STATIC_ASSERT( -32768 <= range && range <= 32767 );
enum {
abs_range = (range < 0) ? -range : range,
fine_mode = (range > 512 || range < 0),
width = (quality < 5 ? quality * 4 : Blip_Buffer::widest_impulse_),
res = 1 << blip_res_bits_,
impulse_size = width / 2 * (fine_mode + 1),
base_impulses_size = width / 2 * (res / 2 + 1),
fine_bits = (fine_mode ? (abs_range <= 64 ? 2 : abs_range <= 128 ? 3 :
abs_range <= 256 ? 4 : abs_range <= 512 ? 5 : abs_range <= 1024 ? 6 :
abs_range <= 2048 ? 7 : 8) : 0)
};
blip_pair_t_ impulses [impulse_size * res * 2 + base_impulses_size];
Blip_Impulse_ impulse;
public:
Blip_Synth() { impulse.init( impulses, width, res, fine_bits ); }
// Configure low-pass filter (see notes.txt). Not optimized for real-time control
void treble_eq( const blip_eq_t& eq ) { impulse.treble_eq( eq ); }
// Set volume of a transition at amplitude 'range' by setting volume_unit
// to v / range
void volume( double v ) { impulse.volume_unit( v * (1.0 / abs_range) ); }
// Set base volume unit of transitions, where 1.0 is a full swing between the
// positive and negative extremes. Not optimized for real-time control.
void volume_unit( double unit ) { impulse.volume_unit( unit ); }
// Default Blip_Buffer used for output when none is specified for a given call
Blip_Buffer* output() const { return impulse.buf; }
void output( Blip_Buffer* b ) { impulse.buf = b; }
// Add an amplitude offset (transition) with an amplitude of delta * volume_unit
// into the specified buffer (default buffer if none specified) at the
// specified source time. Amplitude can be positive or negative. To increase
// performance by inlining code at the call site, use offset_inline().
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
void offset_resampled( blip_resampled_time_t t, int o ) const {
offset_resampled( t, o, impulse.buf );
}
void offset( blip_time_t t, int delta ) const {
offset( t, delta, impulse.buf );
}
void offset_inline( blip_time_t time, int delta, Blip_Buffer* buf ) const {
offset_resampled( time * buf->factor_ + buf->offset_, delta, buf );
}
void offset_inline( blip_time_t time, int delta ) const {
offset_inline( time, delta, impulse.buf );
}
};
// Blip_Wave is a synthesizer for adding a *single* waveform to a Blip_Buffer.
// A wave is built from a series of delays and new amplitudes. This provides a
// simpler interface than Blip_Synth.
template<int quality,int range>
class Blip_Wave {
Blip_Synth<quality,range> synth;
blip_time_t time_;
int last_amp;
public:
// Start wave at time 0 and amplitude 0
Blip_Wave() : time_( 0 ), last_amp( 0 ) { }
// See Blip_Synth for description
void volume( double v ) { synth.volume( v ); }
void volume_unit( double v ) { synth.volume_unit( v ); }
void treble_eq( const blip_eq_t& eq){ synth.treble_eq( eq ); }
Blip_Buffer* output() const { return synth.output(); }
void output( Blip_Buffer* b ) { synth.output( b ); if ( !b ) time_ = last_amp = 0; }
// Current time in frame
blip_time_t time() const { return time_; }
void time( blip_time_t t ) { time_ = t; }
// Current amplitude of wave
int amplitude() const { return last_amp; }
void amplitude( int );
// Move forward by 't' time units
void delay( blip_time_t t ) { time_ += t; }
// End time frame of specified duration. Localize time to new frame.
void end_frame( blip_time_t duration ) {
assert(( "Blip_Wave::end_frame(): Wave hadn't yet been run for entire frame",
duration <= time_ ));
time_ -= duration;
}
};
// End of public interface
template<int quality,int range>
void Blip_Wave<quality,range>::amplitude( int amp ) {
int delta = amp - last_amp;
last_amp = amp;
synth.offset_inline( time_, delta );
}
template<int quality,int range>
inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
int delta, Blip_Buffer* blip_buf ) const
{
typedef blip_pair_t_ pair_t;
unsigned sample_index = (time >> BLIP_BUFFER_ACCURACY) & ~1;
assert(( "Blip_Synth/Blip_wave: Went past end of buffer",
sample_index < blip_buf->buffer_size_ ));
enum { const_offset = Blip_Buffer::widest_impulse_ / 2 - width / 2 };
pair_t* buf = (pair_t*) &blip_buf->buffer_ [const_offset + sample_index];
enum { shift = BLIP_BUFFER_ACCURACY - blip_res_bits_ };
enum { mask = res * 2 - 1 };
const pair_t* imp = &impulses [((time >> shift) & mask) * impulse_size];
pair_t offset = impulse.offset * delta;
if ( !fine_bits )
{
// normal mode
for ( int n = width / 4; n; --n )
{
pair_t t0 = buf [0] - offset;
pair_t t1 = buf [1] - offset;
t0 += imp [0] * delta;
t1 += imp [1] * delta;
imp += 2;
buf [0] = t0;
buf [1] = t1;
buf += 2;
}
}
else
{
// fine mode
enum { sub_range = 1 << fine_bits };
delta += sub_range / 2;
int delta2 = (delta & (sub_range - 1)) - sub_range / 2;
delta >>= fine_bits;
for ( int n = width / 4; n; --n )
{
pair_t t0 = buf [0] - offset;
pair_t t1 = buf [1] - offset;
t0 += imp [0] * delta2;
t0 += imp [1] * delta;
t1 += imp [2] * delta2;
t1 += imp [3] * delta;
imp += 4;
buf [0] = t0;
buf [1] = t1;
buf += 2;
}
}
}
template<int quality,int range>
void Blip_Synth<quality,range>::offset( blip_time_t time, int delta, Blip_Buffer* buf ) const {
offset_resampled( time * buf->factor_ + buf->offset_, delta, buf );
}
#endif

504
Gb_Apu/COPYING Normal file
View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
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 and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, 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 library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete 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 distribute a copy of this License along with the
Library.
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 Library or any portion
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
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 Library, 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 Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you 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.
If distribution of 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 satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be 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.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library 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.
9. 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 Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
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 with
this License.
11. 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 Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library 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 Library.
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.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library 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.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
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 Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
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
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. 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 LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. 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 library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library 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 library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

318
Gb_Apu/Gb_Apu.cpp Normal file
View File

@ -0,0 +1,318 @@
// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
#include "Gb_Apu.h"
#include <string.h>
/* Copyright (C) 2003-2006 Shay Green. This module 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
module 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 module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include BLARGG_SOURCE_BEGIN
int const vol_reg = 0xFF24;
int const status_reg = 0xFF26;
Gb_Apu::Gb_Apu()
{
square1.synth = &square_synth;
square2.synth = &square_synth;
wave.synth = &other_synth;
noise.synth = &other_synth;
oscs [0] = &square1;
oscs [1] = &square2;
oscs [2] = &wave;
oscs [3] = &noise;
for ( int i = 0; i < osc_count; i++ )
{
Gb_Osc& osc = *oscs [i];
osc.regs = &regs [i * 5];
osc.output = NULL;
osc.outputs [0] = NULL;
osc.outputs [1] = NULL;
osc.outputs [2] = NULL;
osc.outputs [3] = NULL;
}
volume( 1.0 );
reset();
}
Gb_Apu::~Gb_Apu()
{
}
void Gb_Apu::treble_eq( const blip_eq_t& eq )
{
square_synth.treble_eq( eq );
other_synth.treble_eq( eq );
}
void Gb_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
{
require( (unsigned) index < osc_count );
require( (center && left && right) || (!center && !left && !right) );
Gb_Osc& osc = *oscs [index];
osc.outputs [1] = right;
osc.outputs [2] = left;
osc.outputs [3] = center;
osc.output = osc.outputs [osc.output_select];
}
void Gb_Apu::output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
{
for ( int i = 0; i < osc_count; i++ )
osc_output( i, center, left, right );
}
void Gb_Apu::update_volume()
{
// to do: doesn't handle differing left/right global volume
int data = regs [vol_reg - start_addr];
double vol = (max( data & 7, data >> 4 & 7 ) + 1) * volume_unit;
square_synth.volume( vol );
other_synth.volume( vol );
}
static unsigned char const powerup_regs [0x30] = {
0x80,0x3F,0x00,0xFF,0xBF, // square 1
0xFF,0x3F,0x00,0xFF,0xBF, // square 2
0x7F,0xFF,0x9F,0xFF,0xBF, // wave
0xFF,0xFF,0x00,0x00,0xBF, // noise
0x00, // left/right enables
0x77, // master volume
0x80, // power
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table
0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA
};
void Gb_Apu::reset(bool igba)
{
next_frame_time = 0;
last_time = 0;
frame_count = 0;
stereo_found = false;
square1.reset();
square2.reset();
wave.reset(gba = igba);
noise.reset();
noise.bits = 1;
wave.wave_pos = 0;
// avoid click at beginning
regs [vol_reg - start_addr] = 0x77;
update_volume();
regs [status_reg - start_addr] = 0x01; // force power
write_register( 0, status_reg, 0x00 );
}
// to do: remove
//static unsigned long abs_time;
void Gb_Apu::run_until( gb_time_t end_time )
{
require( end_time >= last_time ); // end_time must not be before previous time
if ( end_time == last_time )
return;
while ( true )
{
gb_time_t time = next_frame_time;
if ( time > end_time )
time = end_time;
// run oscillators
for ( int i = 0; i < osc_count; ++i )
{
Gb_Osc& osc = *oscs [i];
if ( osc.output )
{
int playing = false;
if ( osc.enabled && osc.volume &&
(!(osc.regs [4] & osc.len_enabled_mask) || osc.length) )
playing = -1;
if ( osc.output != osc.outputs [3] )
stereo_found = true;
switch ( i )
{
case 0: square1.run( last_time, time, playing ); break;
case 1: square2.run( last_time, time, playing ); break;
case 2: wave .run( last_time, time, playing ); break;
case 3: noise .run( last_time, time, playing ); break;
}
}
}
last_time = time;
if ( time == end_time )
break;
next_frame_time += 4194304 / 256; // 256 Hz
// 256 Hz actions
square1.clock_length();
square2.clock_length();
wave.clock_length();
noise.clock_length();
frame_count = (frame_count + 1) & 3;
if ( frame_count == 0 )
{
// 64 Hz actions
square1.clock_envelope();
square2.clock_envelope();
noise.clock_envelope();
}
if ( frame_count & 1 )
square1.clock_sweep(); // 128 Hz action
}
}
bool Gb_Apu::end_frame( gb_time_t end_time )
{
if ( end_time > last_time )
run_until( end_time );
//abs_time += end_time;
assert( next_frame_time >= end_time );
next_frame_time -= end_time;
assert( last_time >= end_time );
last_time -= end_time;
bool result = stereo_found;
stereo_found = false;
return result;
}
void Gb_Apu::write_register( gb_time_t time, gb_addr_t addr, int data )
{
require( (unsigned) data < 0x100 );
int reg = addr - start_addr;
if ( (unsigned) reg >= register_count )
return;
run_until( time );
int old_reg = regs [reg];
regs [reg] = data;
if ( addr < vol_reg )
{
write_osc( reg / 5, reg, data );
}
else if ( addr == vol_reg && data != old_reg ) // global volume
{
// return all oscs to 0
for ( int i = 0; i < osc_count; i++ )
{
Gb_Osc& osc = *oscs [i];
int amp = osc.last_amp;
osc.last_amp = 0;
if ( amp && osc.enabled && osc.output )
other_synth.offset( time, -amp, osc.output );
}
if ( wave.outputs [3] )
other_synth.offset( time, 30, wave.outputs [3] );
update_volume();
if ( wave.outputs [3] )
other_synth.offset( time, -30, wave.outputs [3] );
// oscs will update with new amplitude when next run
}
else if ( addr == 0xFF25 || addr == status_reg )
{
int mask = (regs [status_reg - start_addr] & 0x80) ? ~0 : 0;
int flags = regs [0xFF25 - start_addr] & mask;
// left/right assignments
for ( int i = 0; i < osc_count; i++ )
{
Gb_Osc& osc = *oscs [i];
osc.enabled &= mask;
int bits = flags >> i;
Blip_Buffer* old_output = osc.output;
osc.output_select = (bits >> 3 & 2) | (bits & 1);
osc.output = osc.outputs [osc.output_select];
if ( osc.output != old_output )
{
int amp = osc.last_amp;
osc.last_amp = 0;
if ( amp && old_output )
other_synth.offset( time, -amp, old_output );
}
}
if ( addr == status_reg && data != old_reg )
{
if ( !(data & 0x80) )
{
for ( int i = 0; i < (int) sizeof powerup_regs; i++ )
{
if ( i != status_reg - start_addr )
write_register( time, i + start_addr, powerup_regs [i] );
}
}
else
{
//dprintf( "APU powered on\n" );
}
}
}
else if ( addr >= 0xFF30 )
{
int bank;
if (gba) bank = (wave.wave_bank ^ 0x20);
else bank = 0;
int index = (addr & 0x0F) * 2 + bank;
wave.wave [index] = data >> 4;
wave.wave [index + 1] = data & 0x0F;
}
}
int Gb_Apu::read_register( gb_time_t time, gb_addr_t addr )
{
run_until( time );
int index = addr - start_addr;
require( (unsigned) index < register_count );
int data = regs [index];
if ( addr == status_reg )
{
data = (data & 0x80) | 0x70;
for ( int i = 0; i < osc_count; i++ )
{
const Gb_Osc& osc = *oscs [i];
if ( osc.enabled && (osc.length || !(osc.regs [4] & osc.len_enabled_mask)) )
data |= 1 << i;
}
} else if ( gba && addr >= 0xff30 ) {
int bank = (wave.wave_bank ^ 0x20);
int index = (addr & 0x0f) * 2;
data = wave.wave [bank + index] << 4;
data |= wave.wave [bank + index + 1];
}
return data;
}

99
Gb_Apu/Gb_Apu.h Normal file
View File

@ -0,0 +1,99 @@
// Nintendo Game Boy PAPU sound chip emulator
// Gb_Snd_Emu 0.1.4
#ifndef GB_APU_H
#define GB_APU_H
typedef long gb_time_t; // clock cycle count
typedef unsigned gb_addr_t; // 16-bit address
#include "Gb_Oscs.h"
class Gb_Apu {
public:
// Set overall volume of all oscillators, where 1.0 is full volume
void volume( double );
// Set treble equalization
void treble_eq( const blip_eq_t& );
// Outputs can be assigned to a single buffer for mono output, or to three
// buffers for stereo output (using Stereo_Buffer to do the mixing).
// Assign all oscillator outputs to specified buffer(s). If buffer
// is NULL, silences all oscillators.
void output( Blip_Buffer* mono );
void output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right );
// Assign single oscillator output to buffer(s). Valid indicies are 0 to 3,
// which refer to Square 1, Square 2, Wave, and Noise. If buffer is NULL,
// silences oscillator.
enum { osc_count = 4 };
void osc_output( int index, Blip_Buffer* mono );
void osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right );
// Reset oscillators and internal state
void reset(bool gba = false);
// Reads and writes at addr must satisfy start_addr <= addr <= end_addr
enum { start_addr = 0xFF10 };
enum { end_addr = 0xFF3f };
enum { register_count = end_addr - start_addr + 1 };
// Write 'data' to address at specified time
void write_register( gb_time_t, gb_addr_t, int data );
// Read from address at specified time
int read_register( gb_time_t, gb_addr_t );
// Run all oscillators up to specified time, end current time frame, then
// start a new frame at time 0. Returns true if any oscillators added
// sound to one of the left/right buffers, false if they only added
// to the center buffer.
bool end_frame( gb_time_t );
public:
Gb_Apu();
~Gb_Apu();
private:
// noncopyable
Gb_Apu( const Gb_Apu& );
Gb_Apu& operator = ( const Gb_Apu& );
Gb_Osc* oscs [osc_count];
gb_time_t next_frame_time;
gb_time_t last_time;
double volume_unit;
int frame_count;
bool stereo_found;
Gb_Square square1;
Gb_Square square2;
Gb_Wave wave;
Gb_Noise noise;
BOOST::uint8_t regs [register_count];
Gb_Square::Synth square_synth; // used by squares
Gb_Wave::Synth other_synth; // used by wave and noise
bool gba; // enable GBA extensions to wave channel
void update_volume();
void run_until( gb_time_t );
void write_osc( int index, int reg, int data );
};
inline void Gb_Apu::output( Blip_Buffer* b ) { output( b, b, b ); }
inline void Gb_Apu::osc_output( int i, Blip_Buffer* b ) { osc_output( i, b, b, b ); }
inline void Gb_Apu::volume( double vol )
{
volume_unit = 0.60 / osc_count / 15 /*steps*/ / 2 /*?*/ / 8 /*master vol range*/ * vol;
update_volume();
}
#endif

360
Gb_Apu/Gb_Oscs.cpp Normal file
View File

@ -0,0 +1,360 @@
// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
#include "Gb_Apu.h"
#include <string.h>
/* Copyright (C) 2003-2006 Shay Green. This module 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
module 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 module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include BLARGG_SOURCE_BEGIN
// Gb_Osc
void Gb_Osc::reset()
{
delay = 0;
last_amp = 0;
length = 0;
output_select = 3;
output = outputs [output_select];
}
void Gb_Osc::clock_length()
{
if ( (regs [4] & len_enabled_mask) && length )
length--;
}
// Gb_Env
void Gb_Env::clock_envelope()
{
if ( env_delay && !--env_delay )
{
env_delay = regs [2] & 7;
int v = volume - 1 + (regs [2] >> 2 & 2);
if ( (unsigned) v < 15 )
volume = v;
}
}
bool Gb_Env::write_register( int reg, int data )
{
switch ( reg )
{
case 1:
length = 64 - (regs [1] & 0x3f);
break;
case 2:
if ( !(data >> 4) )
enabled = false;
break;
case 4:
if ( data & trigger )
{
env_delay = regs [2] & 7;
volume = regs [2] >> 4;
enabled = true;
if ( length == 0 )
length = 64;
return true;
}
}
return false;
}
// Gb_Square
void Gb_Square::reset()
{
phase = 0;
sweep_freq = 0;
sweep_delay = 0;
Gb_Env::reset();
}
void Gb_Square::clock_sweep()
{
int sweep_period = (regs [0] & period_mask) >> 4;
if ( sweep_period && sweep_delay && !--sweep_delay )
{
sweep_delay = sweep_period;
regs [3] = sweep_freq & 0xFF;
regs [4] = (regs [4] & ~0x07) | (sweep_freq >> 8 & 0x07);
int offset = sweep_freq >> (regs [0] & shift_mask);
if ( regs [0] & 0x08 )
offset = -offset;
sweep_freq += offset;
if ( sweep_freq < 0 )
{
sweep_freq = 0;
}
else if ( sweep_freq >= 2048 )
{
sweep_delay = 0; // don't modify channel frequency any further
sweep_freq = 2048; // silence sound immediately
}
}
}
void Gb_Square::run( gb_time_t time, gb_time_t end_time, int playing )
{
if ( sweep_freq == 2048 )
playing = false;
static unsigned char const table [4] = { 1, 2, 4, 6 };
int const duty = table [regs [1] >> 6];
int amp = volume & playing;
if ( phase >= duty )
amp = -amp;
int frequency = this->frequency();
if ( unsigned (frequency - 1) > 2040 ) // frequency < 1 || frequency > 2041
{
// really high frequency results in DC at half volume
amp = volume >> 1;
playing = false;
}
int delta = amp - last_amp;
if ( delta )
{
last_amp = amp;
synth->offset( time, delta, output );
}
time += delay;
if ( !playing )
time = end_time;
if ( time < end_time )
{
int const period = (2048 - frequency) * 4;
Blip_Buffer* const output = this->output;
int phase = this->phase;
int delta = amp * 2;
do
{
phase = (phase + 1) & 7;
if ( phase == 0 || phase == duty )
{
delta = -delta;
synth->offset_inline( time, delta, output );
}
time += period;
}
while ( time < end_time );
this->phase = phase;
last_amp = delta >> 1;
}
delay = time - end_time;
}
// Gb_Noise
#include BLARGG_ENABLE_OPTIMIZER
void Gb_Noise::run( gb_time_t time, gb_time_t end_time, int playing )
{
int amp = volume & playing;
int tap = 13 - (regs [3] & 8);
if ( bits >> tap & 2 )
amp = -amp;
int delta = amp - last_amp;
if ( delta )
{
last_amp = amp;
synth->offset( time, delta, output );
}
time += delay;
if ( !playing )
time = end_time;
if ( time < end_time )
{
static unsigned char const table [8] = { 8, 16, 32, 48, 64, 80, 96, 112 };
int period = table [regs [3] & 7] << (regs [3] >> 4);
// keep parallel resampled time to eliminate time conversion in the loop
Blip_Buffer* const output = this->output;
const blip_resampled_time_t resampled_period =
output->resampled_duration( period );
blip_resampled_time_t resampled_time = output->resampled_time( time );
unsigned bits = this->bits;
int delta = amp * 2;
do
{
unsigned changed = (bits >> tap) + 1;
time += period;
bits <<= 1;
if ( changed & 2 )
{
delta = -delta;
bits |= 1;
synth->offset_resampled( resampled_time, delta, output );
}
resampled_time += resampled_period;
}
while ( time < end_time );
this->bits = bits;
last_amp = delta >> 1;
}
delay = time - end_time;
}
// Gb_Wave
void Gb_Wave::reset(bool gba)
{
volume_forced = 0;
wave_pos = 0;
wave_mode = gba;
wave_size = 32;
wave_bank = 0;
memset( wave, 0, sizeof wave );
Gb_Osc::reset();
}
inline void Gb_Wave::write_register( int reg, int data )
{
switch ( reg )
{
case 0:
if ( !(data & 0x80) )
enabled = false;
if (wave_mode)
{
wave_bank = (data & 0x40) >> 1;
wave_size = (data & 0x20) + 32;
}
if (wave_pos > wave_size) wave_pos %= wave_size;
break;
case 1:
length = 256 - regs [1];
break;
case 2:
volume = data >> 5 & 3;
if (wave_mode) volume_forced = data & 0x80;
if (volume_forced) volume = -1;
break;
case 4:
if ( data & trigger & regs [0] )
{
wave_pos = 0;
enabled = true;
if ( length == 0 )
length = 256;
}
}
}
void Gb_Wave::run( gb_time_t time, gb_time_t end_time, int playing )
{
int volume_shift = (volume - 1) & 7; // volume = 0 causes shift = 7
int amp = (wave_size == 32) ? wave [wave_bank + wave_pos] : wave [wave_pos];
if (volume_forced) amp = ((amp >> 1) + amp) >> 1;
else amp >>= volume_shift;
amp = (amp & playing) * 2;
int frequency = this->frequency();
if ( unsigned (frequency - 1) > 2044 ) // frequency < 1 || frequency > 2045
{
if (volume_forced) amp = ((30 >> 1) + 30) >> 1;
else amp = 30 >> volume_shift;
amp &= playing;
playing = false;
}
int delta = amp - last_amp;
if ( delta )
{
last_amp = amp;
synth->offset( time, delta, output );
}
time += delay;
if ( !playing )
time = end_time;
if ( time < end_time )
{
Blip_Buffer* const output = this->output;
int const period = (2048 - frequency) * 2;
int wave_pos = (this->wave_pos + 1) & (wave_size - 1);
do
{
int amp = (wave_size == 32) ? wave [wave_bank + wave_pos] : wave [wave_pos];
if (volume_forced) amp = ((amp >> 1) + amp) >> 1;
else amp >>= volume_shift;
amp *= 2;
wave_pos = (wave_pos + 1) & (wave_size - 1);
int delta = amp - last_amp;
if ( delta )
{
last_amp = amp;
synth->offset_inline( time, delta, output );
}
time += period;
}
while ( time < end_time );
this->wave_pos = (wave_pos - 1) & (wave_size - 1);
}
delay = time - end_time;
}
// Gb_Apu::write_osc
void Gb_Apu::write_osc( int index, int reg, int data )
{
reg -= index * 5;
Gb_Square* sq = &square2;
switch ( index )
{
case 0:
sq = &square1;
case 1:
if ( sq->write_register( reg, data ) && index == 0 )
{
square1.sweep_freq = square1.frequency();
if ( (regs [0] & sq->period_mask) && (regs [0] & sq->shift_mask) )
{
square1.sweep_delay = 1; // cause sweep to recalculate now
square1.clock_sweep();
}
}
break;
case 2:
wave.write_register( reg, data );
break;
case 3:
if ( noise.write_register( reg, data ) )
noise.bits = 0x7FFF;
}
}

90
Gb_Apu/Gb_Oscs.h Normal file
View File

@ -0,0 +1,90 @@
// Private oscillators used by Gb_Apu
// Gb_Snd_Emu 0.1.4
#ifndef GB_OSCS_H
#define GB_OSCS_H
#include "blargg_common.h"
#include "Blip_Buffer.h"
struct Gb_Osc
{
enum { trigger = 0x80 };
enum { len_enabled_mask = 0x40 };
Blip_Buffer* outputs [4]; // NULL, right, left, center
Blip_Buffer* output;
int output_select;
BOOST::uint8_t* regs; // osc's 5 registers
int delay;
int last_amp;
int volume;
int length;
bool enabled;
void reset();
void clock_length();
int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; }
};
struct Gb_Env : Gb_Osc
{
int env_delay;
void reset();
void clock_envelope();
bool write_register( int, int );
};
struct Gb_Square : Gb_Env
{
enum { period_mask = 0x70 };
enum { shift_mask = 0x07 };
typedef Blip_Synth<blip_good_quality,1> Synth;
Synth const* synth;
int sweep_delay;
int sweep_freq;
int phase;
void reset();
void clock_sweep();
void run( gb_time_t, gb_time_t, int playing );
};
struct Gb_Noise : Gb_Env
{
typedef Blip_Synth<blip_med_quality,1> Synth;
Synth const* synth;
unsigned bits;
void run( gb_time_t, gb_time_t, int playing );
};
struct Gb_Wave : Gb_Osc
{
typedef Blip_Synth<blip_med_quality,1> Synth;
Synth const* synth;
int volume_forced;
int wave_pos;
unsigned wave_mode;
unsigned wave_size;
unsigned wave_bank;
BOOST::uint8_t wave [32 * 2];
void reset(bool gba = false);
void write_register( int, int );
void run( gb_time_t, gb_time_t, int playing );
};
inline void Gb_Env::reset()
{
env_delay = 0;
Gb_Osc::reset();
}
#endif

215
Gb_Apu/Multi_Buffer.cpp Normal file
View File

@ -0,0 +1,215 @@
// Blip_Buffer 0.4.0. http://www.slack.net/~ant/
#include "Multi_Buffer.h"
/* Copyright (C) 2003-2006 Shay Green. This module 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
module 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 module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include BLARGG_SOURCE_BEGIN
Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf )
{
length_ = 0;
sample_rate_ = 0;
channels_changed_count_ = 1;
}
blargg_err_t Multi_Buffer::set_channel_count( int )
{
return blargg_success;
}
Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 )
{
}
Mono_Buffer::~Mono_Buffer()
{
}
blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec )
{
BLARGG_RETURN_ERR( buf.set_sample_rate( rate, msec ) );
return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() );
}
// Silent_Buffer
Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse
{
chan.left = NULL;
chan.center = NULL;
chan.right = NULL;
}
// Mono_Buffer
Mono_Buffer::channel_t Mono_Buffer::channel( int )
{
channel_t ch;
ch.center = &buf;
ch.left = &buf;
ch.right = &buf;
return ch;
}
void Mono_Buffer::end_frame( blip_time_t t, bool )
{
buf.end_frame( t );
}
// Stereo_Buffer
Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 )
{
chan.center = &bufs [0];
chan.left = &bufs [1];
chan.right = &bufs [2];
}
Stereo_Buffer::~Stereo_Buffer()
{
}
blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec )
{
for ( int i = 0; i < buf_count; i++ )
BLARGG_RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );
return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() );
}
void Stereo_Buffer::clock_rate( long rate )
{
for ( int i = 0; i < buf_count; i++ )
bufs [i].clock_rate( rate );
}
void Stereo_Buffer::bass_freq( int bass )
{
for ( unsigned i = 0; i < buf_count; i++ )
bufs [i].bass_freq( bass );
}
void Stereo_Buffer::clear()
{
stereo_added = false;
was_stereo = false;
for ( int i = 0; i < buf_count; i++ )
bufs [i].clear();
}
void Stereo_Buffer::end_frame( blip_time_t clock_count, bool stereo )
{
for ( unsigned i = 0; i < buf_count; i++ )
bufs [i].end_frame( clock_count );
stereo_added |= stereo;
}
long Stereo_Buffer::read_samples( blip_sample_t* out, long count )
{
require( !(count & 1) ); // count must be even
count = (unsigned) count / 2;
long avail = bufs [0].samples_avail();
if ( count > avail )
count = avail;
if ( count )
{
if ( stereo_added || was_stereo )
{
mix_stereo( out, count );
bufs [0].remove_samples( count );
bufs [1].remove_samples( count );
bufs [2].remove_samples( count );
}
else
{
mix_mono( out, count );
bufs [0].remove_samples( count );
bufs [1].remove_silence( count );
bufs [2].remove_silence( count );
}
// to do: this might miss opportunities for optimization
if ( !bufs [0].samples_avail() ) {
was_stereo = stereo_added;
stereo_added = false;
}
}
return count * 2;
}
#include BLARGG_ENABLE_OPTIMIZER
void Stereo_Buffer::mix_stereo( blip_sample_t* out, long count )
{
Blip_Reader left;
Blip_Reader right;
Blip_Reader center;
left.begin( bufs [1] );
right.begin( bufs [2] );
int bass = center.begin( bufs [0] );
while ( count-- )
{
int c = center.read();
long l = c + left.read();
long r = c + right.read();
center.next( bass );
out [0] = l;
out [1] = r;
out += 2;
if ( (BOOST::int16_t) l != l )
out [-2] = 0x7FFF - (l >> 24);
left.next( bass );
right.next( bass );
if ( (BOOST::int16_t) r != r )
out [-1] = 0x7FFF - (r >> 24);
}
center.end( bufs [0] );
right.end( bufs [2] );
left.end( bufs [1] );
}
void Stereo_Buffer::mix_mono( blip_sample_t* out, long count )
{
Blip_Reader in;
int bass = in.begin( bufs [0] );
while ( count-- )
{
long s = in.read();
in.next( bass );
out [0] = s;
out [1] = s;
out += 2;
if ( (BOOST::int16_t) s != s ) {
s = 0x7FFF - (s >> 24);
out [-2] = s;
out [-1] = s;
}
}
in.end( bufs [0] );
}

175
Gb_Apu/Multi_Buffer.h Normal file
View File

@ -0,0 +1,175 @@
// Multi-channel sound buffer interface, and basic mono and stereo buffers
// Blip_Buffer 0.4.0
#ifndef MULTI_BUFFER_H
#define MULTI_BUFFER_H
#include "blargg_common.h"
#include "Blip_Buffer.h"
// Interface to one or more Blip_Buffers mapped to one or more channels
// consisting of left, center, and right buffers.
class Multi_Buffer {
public:
Multi_Buffer( int samples_per_frame );
virtual ~Multi_Buffer() { }
// Set the number of channels available
virtual blargg_err_t set_channel_count( int );
// Get indexed channel, from 0 to channel count - 1
struct channel_t {
Blip_Buffer* center;
Blip_Buffer* left;
Blip_Buffer* right;
};
virtual channel_t channel( int index ) = 0;
// See Blip_Buffer.h
virtual blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ) = 0;
virtual void clock_rate( long ) = 0;
virtual void bass_freq( int ) = 0;
virtual void clear() = 0;
long sample_rate() const;
// Length of buffer, in milliseconds
int length() const;
// See Blip_Buffer.h. For optimal operation, pass false for 'added_stereo'
// if nothing was added to the left and right buffers of any channel for
// this time frame.
virtual void end_frame( blip_time_t, bool added_stereo = true ) = 0;
// Number of samples per output frame (1 = mono, 2 = stereo)
int samples_per_frame() const;
// Count of changes to channel configuration. Incremented whenever
// a change is made to any of the Blip_Buffers for any channel.
unsigned channels_changed_count() { return channels_changed_count_; }
// See Blip_Buffer.h
virtual long read_samples( blip_sample_t*, long ) = 0;
virtual long samples_avail() const = 0;
protected:
void channels_changed() { channels_changed_count_++; }
private:
// noncopyable
Multi_Buffer( const Multi_Buffer& );
Multi_Buffer& operator = ( const Multi_Buffer& );
unsigned channels_changed_count_;
long sample_rate_;
int length_;
int const samples_per_frame_;
};
// Uses a single buffer and outputs mono samples.
class Mono_Buffer : public Multi_Buffer {
Blip_Buffer buf;
public:
Mono_Buffer();
~Mono_Buffer();
// Buffer used for all channels
Blip_Buffer* center() { return &buf; }
// See Multi_Buffer
blargg_err_t set_sample_rate( long rate, int msec = blip_default_length );
void clock_rate( long );
void bass_freq( int );
void clear();
channel_t channel( int );
void end_frame( blip_time_t, bool unused = true );
long samples_avail() const;
long read_samples( blip_sample_t*, long );
};
// Uses three buffers (one for center) and outputs stereo sample pairs.
class Stereo_Buffer : public Multi_Buffer {
public:
Stereo_Buffer();
~Stereo_Buffer();
// Buffers used for all channels
Blip_Buffer* center() { return &bufs [0]; }
Blip_Buffer* left() { return &bufs [1]; }
Blip_Buffer* right() { return &bufs [2]; }
// See Multi_Buffer
blargg_err_t set_sample_rate( long, int msec = blip_default_length );
void clock_rate( long );
void bass_freq( int );
void clear();
channel_t channel( int index );
void end_frame( blip_time_t, bool added_stereo = true );
long samples_avail() const;
long read_samples( blip_sample_t*, long );
private:
enum { buf_count = 3 };
Blip_Buffer bufs [buf_count];
channel_t chan;
bool stereo_added;
bool was_stereo;
void mix_stereo( blip_sample_t*, long );
void mix_mono( blip_sample_t*, long );
};
// Silent_Buffer generates no samples, useful where no sound is wanted
class Silent_Buffer : public Multi_Buffer {
channel_t chan;
public:
Silent_Buffer();
blargg_err_t set_sample_rate( long rate, int msec = blip_default_length );
void clock_rate( long ) { }
void bass_freq( int ) { }
void clear() { }
channel_t channel( int ) { return chan; }
void end_frame( blip_time_t, bool unused = true ) { }
long samples_avail() const { return 0; }
long read_samples( blip_sample_t*, long ) { return 0; }
};
// End of public interface
inline blargg_err_t Multi_Buffer::set_sample_rate( long rate, int msec )
{
sample_rate_ = rate;
length_ = msec;
return blargg_success;
}
inline blargg_err_t Silent_Buffer::set_sample_rate( long rate, int msec )
{
return Multi_Buffer::set_sample_rate( rate, msec );
}
inline int Multi_Buffer::samples_per_frame() const { return samples_per_frame_; }
inline long Stereo_Buffer::samples_avail() const { return bufs [0].samples_avail() * 2; }
inline Stereo_Buffer::channel_t Stereo_Buffer::channel( int ) { return chan; }
inline long Multi_Buffer::sample_rate() const { return sample_rate_; }
inline int Multi_Buffer::length() const { return length_; }
inline void Mono_Buffer::clock_rate( long rate ) { buf.clock_rate( rate ); }
inline void Mono_Buffer::clear() { buf.clear(); }
inline void Mono_Buffer::bass_freq( int freq ) { buf.bass_freq( freq ); }
inline long Mono_Buffer::read_samples( blip_sample_t* p, long s ) { return buf.read_samples( p, s ); }
inline long Mono_Buffer::samples_avail() const { return buf.samples_avail(); }
#endif

242
Gb_Apu/blargg_common.h Normal file
View File

@ -0,0 +1,242 @@
// Sets up common environment for Shay Green's libraries.
//
// To change configuration options, modify blargg_config.h, not this file.
#ifndef BLARGG_COMMON_H
#define BLARGG_COMMON_H
// HAVE_CONFIG_H: If defined, include user's "config.h" first (which *can*
// re-include blargg_common.h if it needs to)
#ifdef HAVE_CONFIG_H
#undef BLARGG_COMMON_H
#include "config.h"
#define BLARGG_COMMON_H
#endif
// BLARGG_NONPORTABLE: If defined to 1, platform-specific (and possibly non-portable)
// optimizations are used. Defaults to off. Report any problems that occur only when
// this is enabled.
#ifndef BLARGG_NONPORTABLE
#define BLARGG_NONPORTABLE 0
#endif
// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
// one must be #defined to 1. Only needed if something actually depends on byte order.
#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
#if defined (MSB_FIRST) || defined (__powerc) || defined (macintosh) || \
defined (WORDS_BIGENDIAN) || defined (__BIG_ENDIAN__)
#define BLARGG_BIG_ENDIAN 1
#else
#define BLARGG_LITTLE_ENDIAN 1
#endif
#endif
// Determine compiler's language support
// Metrowerks CodeWarrior
#if defined (__MWERKS__)
#define BLARGG_COMPILER_HAS_NAMESPACE 1
#if !__option(bool)
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
#define STATIC_CAST(T,expr) static_cast< T > (expr)
// Microsoft Visual C++
#elif defined (_MSC_VER)
#if _MSC_VER < 1100
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
// GNU C++
#elif defined (__GNUC__)
#if __GNUC__ > 2
#define BLARGG_COMPILER_HAS_NAMESPACE 1
#endif
// Mingw
#elif defined (__MINGW32__)
// empty
// Pre-ISO C++ compiler
#elif __cplusplus < 199711
#ifndef BLARGG_COMPILER_HAS_BOOL
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
#endif
/* BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compilers.
If errors occur here, add the following line to your config.h file:
#define BLARGG_COMPILER_HAS_BOOL 0
*/
#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
typedef int bool;
const bool true = 1;
const bool false = 0;
#endif
// BLARGG_USE_NAMESPACE: If 1, use <cxxx> headers rather than <xxxx.h>
#if BLARGG_USE_NAMESPACE || (!defined (BLARGG_USE_NAMESPACE) && BLARGG_COMPILER_HAS_NAMESPACE)
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <climits>
#define STD std
#else
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#define STD
#endif
// BLARGG_NEW is used in place of 'new' to create objects. By default, plain new is used.
// To prevent an exception if out of memory, #define BLARGG_NEW new (std::nothrow)
#ifndef BLARGG_NEW
#define BLARGG_NEW new
#endif
// BOOST::int8_t etc.
// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
#if defined (HAVE_STDINT_H)
#include <stdint.h>
#define BOOST
// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
#elif defined (HAVE_INTTYPES_H)
#include <inttypes.h>
#define BOOST
#else
struct BOOST
{
#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
typedef signed char int8_t;
typedef unsigned char uint8_t;
#else
// No suitable 8-bit type available
typedef struct see_blargg_common_h int8_t;
typedef struct see_blargg_common_h uint8_t;
#endif
#if USHRT_MAX == 0xFFFF
typedef short int16_t;
typedef unsigned short uint16_t;
#else
// No suitable 16-bit type available
typedef struct see_blargg_common_h int16_t;
typedef struct see_blargg_common_h uint16_t;
#endif
#if ULONG_MAX == 0xFFFFFFFF
typedef long int32_t;
typedef unsigned long uint32_t;
#elif UINT_MAX == 0xFFFFFFFF
typedef int int32_t;
typedef unsigned int uint32_t;
#else
// No suitable 32-bit type available
typedef struct see_blargg_common_h int32_t;
typedef struct see_blargg_common_h uint32_t;
#endif
};
#endif
// BLARGG_SOURCE_BEGIN: Library sources #include this after other #includes.
#ifndef BLARGG_SOURCE_BEGIN
#define BLARGG_SOURCE_BEGIN "blargg_source.h"
#endif
// BLARGG_ENABLE_OPTIMIZER: Library sources #include this for speed-critical code
#ifndef BLARGG_ENABLE_OPTIMIZER
#define BLARGG_ENABLE_OPTIMIZER "blargg_common.h"
#endif
// BLARGG_CPU_*: Used to select between some optimizations
#if !defined (BLARGG_CPU_POWERPC) && !defined (BLARGG_CPU_X86)
#if defined (__powerc)
#define BLARGG_CPU_POWERPC 1
#elif defined (_MSC_VER) && defined (_M_IX86)
#define BLARGG_CPU_X86 1
#endif
#endif
// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
#ifndef BOOST_STATIC_ASSERT
#ifdef _MSC_VER
// MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
#define BOOST_STATIC_ASSERT( expr ) \
void blargg_failed_( int (*arg) [2 / ((expr) ? 1 : 0) - 1] )
#else
// Some other compilers fail when declaring same function multiple times in class,
// so differentiate them by line
#define BOOST_STATIC_ASSERT( expr ) \
void blargg_failed_( int (*arg) [2 / ((expr) ? 1 : 0) - 1] [__LINE__] )
#endif
#endif
// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
#ifndef STATIC_CAST
#define STATIC_CAST(T,expr) ((T) (expr))
#endif
// blargg_err_t (NULL on success, otherwise error string)
#ifndef blargg_err_t
typedef const char* blargg_err_t;
#endif
const char* const blargg_success = 0;
// blargg_vector: Simple array that does *not* work for types with a constructor (non-POD).
template<class T>
class blargg_vector {
T* begin_;
STD::size_t size_;
public:
blargg_vector() : begin_( 0 ), size_( 0 ) { }
~blargg_vector() { STD::free( begin_ ); }
typedef STD::size_t size_type;
blargg_err_t resize( size_type n )
{
void* p = STD::realloc( begin_, n * sizeof (T) );
if ( !p && n )
return "Out of memory";
begin_ = (T*) p;
size_ = n;
return 0;
}
void clear()
{
void* p = begin_;
begin_ = 0;
size_ = 0;
STD::free( p );
}
size_type size() const { return size_; }
T* begin() { return begin_; }
T* end() { return begin_ + size_; }
const T* begin() const { return begin_; }
const T* end() const { return begin_ + size_; }
T& operator [] ( size_type n )
{
assert( n <= size_ ); // allow for past-the-end value
return begin_ [n];
}
const T& operator [] ( size_type n ) const
{
assert( n <= size_ ); // allow for past-the-end value
return begin_ [n];
}
};
#endif

156
Gb_Apu/blargg_endian.h Normal file
View File

@ -0,0 +1,156 @@
// CPU Byte Order Utilities
// Game_Music_Emu 0.3.0
#ifndef BLARGG_ENDIAN
#define BLARGG_ENDIAN
#include "blargg_common.h"
#if 0
// Read 16/32-bit little-endian integer from memory
unsigned GET_LE16( void const* );
unsigned long GET_LE32( void const* );
// Read 16/32-bit big-endian integer from memory
unsigned GET_BE16( void const* );
unsigned long GET_BE32( void const* );
// Write 16/32-bit integer to memory in little-endian format
void SET_LE16( void*, unsigned );
void SET_LE32( void*, unsigned );
// Write 16/32-bit integer to memory in big-endian format
void SET_BE16( void*, unsigned long );
void SET_BE32( void*, unsigned long );
#endif
inline unsigned get_le16( void const* p )
{
return ((unsigned char*) p) [1] * 0x100 +
((unsigned char*) p) [0];
}
inline unsigned get_be16( void const* p )
{
return ((unsigned char*) p) [0] * 0x100 +
((unsigned char*) p) [1];
}
inline unsigned long get_le32( void const* p )
{
return ((unsigned char*) p) [3] * 0x01000000 +
((unsigned char*) p) [2] * 0x00010000 +
((unsigned char*) p) [1] * 0x00000100 +
((unsigned char*) p) [0];
}
inline unsigned long get_be32( void const* p )
{
return ((unsigned char*) p) [0] * 0x01000000 +
((unsigned char*) p) [1] * 0x00010000 +
((unsigned char*) p) [2] * 0x00000100 +
((unsigned char*) p) [3];
}
inline void set_le16( void* p, unsigned n )
{
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
((unsigned char*) p) [0] = (unsigned char) n;
}
inline void set_be16( void* p, unsigned n )
{
((unsigned char*) p) [0] = (unsigned char) (n >> 8);
((unsigned char*) p) [1] = (unsigned char) n;
}
inline void set_le32( void* p, unsigned long n )
{
((unsigned char*) p) [3] = (unsigned char) (n >> 24);
((unsigned char*) p) [2] = (unsigned char) (n >> 16);
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
((unsigned char*) p) [0] = (unsigned char) n;
}
inline void set_be32( void* p, unsigned long n )
{
((unsigned char*) p) [0] = (unsigned char) (n >> 24);
((unsigned char*) p) [1] = (unsigned char) (n >> 16);
((unsigned char*) p) [2] = (unsigned char) (n >> 8);
((unsigned char*) p) [3] = (unsigned char) n;
}
#ifndef GET_LE16
// Optimized implementation if byte order is known
#if BLARGG_NONPORTABLE && BLARGG_LITTLE_ENDIAN
#define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
#define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
#define SET_LE16( addr, data ) (void (*(BOOST::uint16_t*) (addr) = (data)))
#define SET_LE32( addr, data ) (void (*(BOOST::uint32_t*) (addr) = (data)))
#elif BLARGG_NONPORTABLE && BLARGG_CPU_POWERPC
// PowerPC has special byte-reversed instructions
// to do: assumes that PowerPC is running in big-endian mode
#define GET_LE16( addr ) (__lhbrx( (addr), 0 ))
#define GET_LE32( addr ) (__lwbrx( (addr), 0 ))
#define SET_LE16( addr, data ) (__sthbrx( (data), (addr), 0 ))
#define SET_LE32( addr, data ) (__stwbrx( (data), (addr), 0 ))
#define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
#define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
#define SET_BE16( addr, data ) (void (*(BOOST::uint16_t*) (addr) = (data)))
#define SET_BE32( addr, data ) (void (*(BOOST::uint32_t*) (addr) = (data)))
#endif
#endif
#ifndef GET_LE16
#define GET_LE16( addr ) get_le16( addr )
#endif
#ifndef GET_LE32
#define GET_LE32( addr ) get_le32( addr )
#endif
#ifndef SET_LE16
#define SET_LE16( addr, data ) set_le16( addr, data )
#endif
#ifndef SET_LE32
#define SET_LE32( addr, data ) set_le32( addr, data )
#endif
#ifndef GET_BE16
#define GET_BE16( addr ) get_be16( addr )
#endif
#ifndef GET_BE32
#define GET_BE32( addr ) get_be32( addr )
#endif
#ifndef SET_BE16
#define SET_BE16( addr, data ) set_be16( addr, data )
#endif
#ifndef SET_BE32
#define SET_BE32( addr, data ) set_be32( addr, data )
#endif
// auto-selecting versions
inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
inline void set_le( BOOST::uint32_t* p, unsigned long n ) { SET_LE32( p, n ); }
inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
inline void set_be( BOOST::uint32_t* p, unsigned long n ) { SET_BE32( p, n ); }
inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
inline unsigned long get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
inline unsigned long get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
#endif

76
Gb_Apu/blargg_source.h Normal file
View File

@ -0,0 +1,76 @@
// By default, #included at beginning of library source files.
// Can be overridden by #defining BLARGG_SOURCE_BEGIN to path of alternate file.
// Copyright (C) 2005 Shay Green.
#ifndef BLARGG_SOURCE_H
#define BLARGG_SOURCE_H
// If debugging is enabled, abort program if expr is false. Meant for checking
// internal state and consistency. A failed assertion indicates a bug in the module.
// void assert( bool expr );
#include <assert.h>
// If debugging is enabled and expr is false, abort program. Meant for checking
// caller-supplied parameters and operations that are outside the control of the
// module. A failed requirement indicates a bug outside the module.
// void require( bool expr );
#undef require
#define require( expr ) assert( expr )
// Like printf() except output goes to debug log file. Might be defined to do
// nothing (not even evaluate its arguments).
// void dprintf( const char* format, ... );
#undef dprintf
#ifdef BLARGG_DPRINTF
#define dprintf BLARGG_DPRINTF
#else
inline void blargg_dprintf_( const char*, ... ) { }
#define dprintf (1) ? (void) 0 : blargg_dprintf_
#endif
// If enabled, evaluate expr and if false, make debug log entry with source file
// and line. Meant for finding situations that should be examined further, but that
// don't indicate a problem. In all cases, execution continues normally.
#undef check
#ifdef BLARGG_CHECK
#define check( expr ) BLARGG_CHECK( expr )
#else
#define check( expr ) ((void) 0)
#endif
// If expr returns non-NULL error string, return it from current function, otherwise continue.
#define BLARGG_RETURN_ERR( expr ) do { \
blargg_err_t blargg_return_err_ = (expr); \
if ( blargg_return_err_ ) return blargg_return_err_; \
} while ( 0 )
// If ptr is NULL, return out of memory error string.
#define BLARGG_CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 )
// Avoid any macros which evaluate their arguments multiple times
#undef min
#undef max
// using const references generates crappy code, and I am currenly only using these
// for built-in types, so they take arguments by value
template<class T>
inline T min( T x, T y )
{
if ( x < y )
return x;
return y;
}
template<class T>
inline T max( T x, T y )
{
if ( x < y )
return y;
return x;
}
#endif

13
Gb_Apu/boost/config.hpp Normal file
View File

@ -0,0 +1,13 @@
// Boost substitute. For full boost library see http://boost.org
#ifndef BOOST_CONFIG_HPP
#define BOOST_CONFIG_HPP
#define BOOST_MINIMAL 1
#define BLARGG_BEGIN_NAMESPACE( name )
#define BLARGG_END_NAMESPACE
#endif

42
Gb_Apu/boost/cstdint.hpp Normal file
View File

@ -0,0 +1,42 @@
// Boost substitute. For full boost library see http://boost.org
#ifndef BOOST_CSTDINT_HPP
#define BOOST_CSTDINT_HPP
#if BLARGG_USE_NAMESPACE
#include <climits>
#else
#include <limits.h>
#endif
BLARGG_BEGIN_NAMESPACE( boost )
#if UCHAR_MAX != 0xFF || SCHAR_MAX != 0x7F
# error "No suitable 8-bit type available"
#endif
typedef unsigned char uint8_t;
typedef signed char int8_t;
#if USHRT_MAX != 0xFFFF
# error "No suitable 16-bit type available"
#endif
typedef short int16_t;
typedef unsigned short uint16_t;
#if ULONG_MAX == 0xFFFFFFFF
typedef long int32_t;
typedef unsigned long uint32_t;
#elif UINT_MAX == 0xFFFFFFFF
typedef int int32_t;
typedef unsigned int uint32_t;
#else
# error "No suitable 32-bit type available"
#endif
BLARGG_END_NAMESPACE
#endif

View File

@ -0,0 +1,22 @@
// Boost substitute. For full boost library see http://boost.org
#ifndef BOOST_STATIC_ASSERT_HPP
#define BOOST_STATIC_ASSERT_HPP
#if defined (_MSC_VER) && _MSC_VER <= 1200
// MSVC6 can't handle the ##line concatenation
#define BOOST_STATIC_ASSERT( expr ) struct { int n [1 / ((expr) ? 1 : 0)]; }
#else
#define BOOST_STATIC_ASSERT3( expr, line ) \
typedef int boost_static_assert_##line [1 / ((expr) ? 1 : 0)]
#define BOOST_STATIC_ASSERT2( expr, line ) BOOST_STATIC_ASSERT3( expr, line )
#define BOOST_STATIC_ASSERT( expr ) BOOST_STATIC_ASSERT2( expr, __LINE__ )
#endif
#endif

BIN
SDL.dll Normal file

Binary file not shown.

45
VBA.sln Normal file
View File

@ -0,0 +1,45 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VisualBoyAdvance", "VBA.vcproj", "{6D4C5EC8-933F-4C05-A1BF-498E658576DF}"
ProjectSection(ProjectDependencies) = postProject
{664BE444-CCED-4C81-9724-7057ECBAAC82} = {664BE444-CCED-4C81-9724-7057ECBAAC82}
{34DC39BF-F93A-4573-85BF-789B90B63179} = {34DC39BF-F93A-4573-85BF-789B90B63179}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcproj", "{34DC39BF-F93A-4573-85BF-789B90B63179}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "libpng\libpng.vcproj", "{664BE444-CCED-4C81-9724-7057ECBAAC82}"
ProjectSection(ProjectDependencies) = postProject
{34DC39BF-F93A-4573-85BF-789B90B63179} = {34DC39BF-F93A-4573-85BF-789B90B63179}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Optimized|Win32 = Optimized|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|Win32.ActiveCfg = Debug|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug|Win32.Build.0 = Debug|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Optimized|Win32.ActiveCfg = Optimized|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Optimized|Win32.Build.0 = Optimized|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|Win32.ActiveCfg = Release|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release|Win32.Build.0 = Release|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Debug|Win32.ActiveCfg = Debug|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Debug|Win32.Build.0 = Debug|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Optimized|Win32.ActiveCfg = Release|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Optimized|Win32.Build.0 = Release|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Release|Win32.ActiveCfg = Release|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Release|Win32.Build.0 = Release|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Debug|Win32.ActiveCfg = Debug|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Debug|Win32.Build.0 = Debug|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Optimized|Win32.ActiveCfg = Release|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Optimized|Win32.Build.0 = Release|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Release|Win32.ActiveCfg = Release|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

47
VBA.sln.old Normal file
View File

@ -0,0 +1,47 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VisualBoyAdvance", "VBA.vcproj", "{6D4C5EC8-933F-4C05-A1BF-498E658576DF}"
ProjectSection(ProjectDependencies) = postProject
{664BE444-CCED-4C81-9724-7057ECBAAC82} = {664BE444-CCED-4C81-9724-7057ECBAAC82}
{34DC39BF-F93A-4573-85BF-789B90B63179} = {34DC39BF-F93A-4573-85BF-789B90B63179}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcproj", "{34DC39BF-F93A-4573-85BF-789B90B63179}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "libpng\libpng.vcproj", "{664BE444-CCED-4C81-9724-7057ECBAAC82}"
ProjectSection(ProjectDependencies) = postProject
{34DC39BF-F93A-4573-85BF-789B90B63179} = {34DC39BF-F93A-4573-85BF-789B90B63179}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Optimized = Optimized
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug.ActiveCfg = Debug|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Debug.Build.0 = Debug|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Optimized.ActiveCfg = Optimized|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Optimized.Build.0 = Optimized|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release.ActiveCfg = Release|Win32
{6D4C5EC8-933F-4C05-A1BF-498E658576DF}.Release.Build.0 = Release|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Debug.ActiveCfg = Debug|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Debug.Build.0 = Debug|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Optimized.ActiveCfg = Release|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Optimized.Build.0 = Release|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Release.ActiveCfg = Release|Win32
{34DC39BF-F93A-4573-85BF-789B90B63179}.Release.Build.0 = Release|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Debug.ActiveCfg = Debug|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Debug.Build.0 = Debug|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Optimized.ActiveCfg = Release|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Optimized.Build.0 = Release|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Release.ActiveCfg = Release|Win32
{664BE444-CCED-4C81-9724-7057ECBAAC82}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

BIN
VBA.suo Normal file

Binary file not shown.

1580
VBA.vcproj Normal file

File diff suppressed because it is too large Load Diff

1116
VBA.vcproj.7.10.old Normal file

File diff suppressed because it is too large Load Diff

227
gbafilter.cpp Normal file
View File

@ -0,0 +1,227 @@
#include "gbafilter.h"
#include <math.h>
extern int systemColorDepth;
extern int systemRedShift;
extern int systemGreenShift;
extern int systemBlueShift;
extern u16 systemColorMap16[0x10000];
extern u32 systemColorMap32[0x10000];
static const unsigned char curve[32] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x10, 0x12,
0x14, 0x16, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38,
0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x80,
0x88, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0};
// output R G B
static const unsigned char influence[3 * 3] = { 16, 4, 4, // red
8, 16, 8, // green
0, 8, 16};// blue
inline void swap(short & a, short & b)
{
short temp = a;
a = b;
b = temp;
}
void gbafilter_pal(u16 * buf, int count)
{
short temp[3 * 3], s;
unsigned pix;
u8 red, green, blue;
while (count--)
{
pix = *buf;
s = curve[(pix >> systemGreenShift) & 0x1f];
temp[3] = s * influence[3];
temp[4] = s * influence[4];
temp[5] = s * influence[5];
s = curve[(pix >> systemRedShift) & 0x1f];
temp[0] = s * influence[0];
temp[1] = s * influence[1];
temp[2] = s * influence[2];
s = curve[(pix >> systemBlueShift) & 0x1f];
temp[6] = s * influence[6];
temp[7] = s * influence[7];
temp[8] = s * influence[8];
if (temp[0] < temp[3]) swap(temp[0], temp[3]);
if (temp[0] < temp[6]) swap(temp[0], temp[6]);
if (temp[3] < temp[6]) swap(temp[3], temp[6]);
temp[3] <<= 1;
temp[0] <<= 2;
temp[0] += temp[3] + temp[6];
red = ((int(temp[0]) * 160) >> 17) + 4;
if (red > 31) red = 31;
if (temp[2] < temp[5]) swap(temp[2], temp[5]);
if (temp[2] < temp[8]) swap(temp[2], temp[8]);
if (temp[5] < temp[8]) swap(temp[5], temp[8]);
temp[5] <<= 1;
temp[2] <<= 2;
temp[2] += temp[5] + temp[8];
blue = ((int(temp[2]) * 160) >> 17) + 4;
if (blue > 31) blue = 31;
if (temp[1] < temp[4]) swap(temp[1], temp[4]);
if (temp[1] < temp[7]) swap(temp[1], temp[7]);
if (temp[4] < temp[7]) swap(temp[4], temp[7]);
temp[4] <<= 1;
temp[1] <<= 2;
temp[1] += temp[4] + temp[7];
green = ((int(temp[1]) * 160) >> 17) + 4;
if (green > 31) green = 31;
pix = red << systemRedShift;
pix += green << systemGreenShift;
pix += blue << systemBlueShift;
*buf++ = pix;
}
}
void gbafilter_pal32(u32 * buf, int count)
{
short temp[3 * 3], s;
unsigned pix;
u8 red, green, blue;
while (count--)
{
pix = *buf;
s = curve[(pix >> systemGreenShift) & 0x1f];
temp[3] = s * influence[3];
temp[4] = s * influence[4];
temp[5] = s * influence[5];
s = curve[(pix >> systemRedShift) & 0x1f];
temp[0] = s * influence[0];
temp[1] = s * influence[1];
temp[2] = s * influence[2];
s = curve[(pix >> systemBlueShift) & 0x1f];
temp[6] = s * influence[6];
temp[7] = s * influence[7];
temp[8] = s * influence[8];
if (temp[0] < temp[3]) swap(temp[0], temp[3]);
if (temp[0] < temp[6]) swap(temp[0], temp[6]);
if (temp[3] < temp[6]) swap(temp[3], temp[6]);
temp[3] <<= 1;
temp[0] <<= 2;
temp[0] += temp[3] + temp[6];
//red = ((int(temp[0]) * 160) >> 17) + 4;
red = ((int(temp[0]) * 160) >> 14) + 32;
if (temp[2] < temp[5]) swap(temp[2], temp[5]);
if (temp[2] < temp[8]) swap(temp[2], temp[8]);
if (temp[5] < temp[8]) swap(temp[5], temp[8]);
temp[5] <<= 1;
temp[2] <<= 2;
temp[2] += temp[5] + temp[8];
//blue = ((int(temp[2]) * 160) >> 17) + 4;
blue = ((int(temp[2]) * 160) >> 14) + 32;
if (temp[1] < temp[4]) swap(temp[1], temp[4]);
if (temp[1] < temp[7]) swap(temp[1], temp[7]);
if (temp[4] < temp[7]) swap(temp[4], temp[7]);
temp[4] <<= 1;
temp[1] <<= 2;
temp[1] += temp[4] + temp[7];
//green = ((int(temp[1]) * 160) >> 17) + 4;
green = ((int(temp[1]) * 160) >> 14) + 32;
//pix = red << redshift;
//pix += green << greenshift;
//pix += blue << blueshift;
pix = red << (systemRedShift - 3);
pix += green << (systemGreenShift - 3);
pix += blue << (systemBlueShift - 3);
*buf++ = pix;
}
}
// for palette mode to work with the three spoony filters in 32bpp depth
void gbafilter_pad(u8 * buf, int count)
{
union
{
struct
{
u8 r;
u8 g;
u8 b;
u8 a;
} part;
unsigned whole;
}
mask;
mask.whole = 0x1f << systemRedShift;
mask.whole += 0x1f << systemGreenShift;
mask.whole += 0x1f << systemBlueShift;
switch (systemColorDepth)
{
case 24:
while (count--)
{
*buf++ &= mask.part.r;
*buf++ &= mask.part.g;
*buf++ &= mask.part.b;
}
break;
case 32:
while (count--)
{
*((u32*)buf) &= mask.whole;
buf += 4;
}
}
}
/*
void UpdateSystemColorMaps(int lcd)
{
switch(systemColorDepth) {
case 16:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd == 1) gbafilter_pal(systemColorMap16, 0x10000);
}
break;
case 24:
case 32:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd == 1) gbafilter_pal32(systemColorMap32, 0x10000);
}
break;
}
}
*/

5
gbafilter.h Normal file
View File

@ -0,0 +1,5 @@
#include "System.h"
void gbafilter_pal(u16 * buf, int count);
void gbafilter_pal32(u32 * buf, int count);
void gbafilter_pad(u8 * buf, int count);

226
libpng/libpng.vcproj Normal file
View File

@ -0,0 +1,226 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="libpng"
ProjectGUID="{664BE444-CCED-4C81-9724-7057ECBAAC82}"
RootNamespace="libpng"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(SolutionDir)zlib&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/libpng.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(SolutionDir)zlib&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
CompileAs="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/libpng.lib"
IgnoreAllDefaultLibraries="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\png.c"
>
</File>
<File
RelativePath=".\png.h"
>
</File>
<File
RelativePath=".\pngconf.h"
>
</File>
<File
RelativePath=".\pngerror.c"
>
</File>
<File
RelativePath=".\pngget.c"
>
</File>
<File
RelativePath=".\pngmem.c"
>
</File>
<File
RelativePath=".\pngpread.c"
>
</File>
<File
RelativePath=".\pngread.c"
>
</File>
<File
RelativePath=".\pngrio.c"
>
</File>
<File
RelativePath=".\pngrtran.c"
>
</File>
<File
RelativePath=".\pngrutil.c"
>
</File>
<File
RelativePath=".\pngset.c"
>
</File>
<File
RelativePath=".\pngtrans.c"
>
</File>
<File
RelativePath=".\pngvcrd.c"
>
</File>
<File
RelativePath=".\pngwio.c"
>
</File>
<File
RelativePath=".\pngwrite.c"
>
</File>
<File
RelativePath=".\pngwtran.c"
>
</File>
<File
RelativePath=".\pngwutil.c"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="libpng"
ProjectGUID="{664BE444-CCED-4C81-9724-7057ECBAAC82}"
RootNamespace="libpng"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(SolutionDir)zlib&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/libpng.lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(SolutionDir)zlib&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
CompileAs="1"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/libpng.lib"
IgnoreAllDefaultLibraries="TRUE"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\png.c">
</File>
<File
RelativePath=".\png.h">
</File>
<File
RelativePath=".\pngconf.h">
</File>
<File
RelativePath=".\pngerror.c">
</File>
<File
RelativePath=".\pngget.c">
</File>
<File
RelativePath=".\pngmem.c">
</File>
<File
RelativePath=".\pngpread.c">
</File>
<File
RelativePath=".\pngread.c">
</File>
<File
RelativePath=".\pngrio.c">
</File>
<File
RelativePath=".\pngrtran.c">
</File>
<File
RelativePath=".\pngrutil.c">
</File>
<File
RelativePath=".\pngset.c">
</File>
<File
RelativePath=".\pngtrans.c">
</File>
<File
RelativePath=".\pngvcrd.c">
</File>
<File
RelativePath=".\pngwio.c">
</File>
<File
RelativePath=".\pngwrite.c">
</File>
<File
RelativePath=".\pngwtran.c">
</File>
<File
RelativePath=".\pngwutil.c">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

828
libpng/png.c Normal file
View File

@ -0,0 +1,828 @@
/* png.c - location for general purpose libpng functions
*
* libpng version 1.2.8 - December 3, 2004
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1998-2004 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*/
#define PNG_INTERNAL
#define PNG_NO_EXTERN
#include "png.h"
/* Generate a compiler error if there is an old png.h in the search path. */
typedef version_1_2_8 Your_png_h_is_not_version_1_2_8;
/* Version information for C files. This had better match the version
* string defined in png.h. */
#ifdef PNG_USE_GLOBAL_ARRAYS
/* png_libpng_ver was changed to a function in version 1.0.5c */
const char png_libpng_ver[18] = PNG_LIBPNG_VER_STRING;
/* png_sig was changed to a function in version 1.0.5c */
/* Place to hold the signature string for a PNG file. */
const png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
/* Invoke global declarations for constant strings for known chunk types */
PNG_IHDR;
PNG_IDAT;
PNG_IEND;
PNG_PLTE;
PNG_bKGD;
PNG_cHRM;
PNG_gAMA;
PNG_hIST;
PNG_iCCP;
PNG_iTXt;
PNG_oFFs;
PNG_pCAL;
PNG_sCAL;
PNG_pHYs;
PNG_sBIT;
PNG_sPLT;
PNG_sRGB;
PNG_tEXt;
PNG_tIME;
PNG_tRNS;
PNG_zTXt;
/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* start of interlace block */
const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
/* offset to next interlace block */
const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
/* start of interlace block in the y direction */
const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
/* offset to next interlace block in the y direction */
const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
/* width of interlace block (used in assembler routines only) */
#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW
const int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1};
#endif
/* Height of interlace block. This is not currently used - if you need
* it, uncomment it here and in png.h
const int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
*/
/* Mask to determine which pixels are valid in a pass */
const int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
/* Mask to determine which pixels to overwrite while displaying */
const int FARDATA png_pass_dsp_mask[]
= {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
#endif /* PNG_USE_GLOBAL_ARRAYS */
/* Tells libpng that we have already handled the first "num_bytes" bytes
* of the PNG file signature. If the PNG data is embedded into another
* stream we can set num_bytes = 8 so that libpng will not attempt to read
* or write any of the magic bytes before it starts on the IHDR.
*/
void PNGAPI
png_set_sig_bytes(png_structp png_ptr, int num_bytes)
{
png_debug(1, "in png_set_sig_bytes\n");
if (num_bytes > 8)
png_error(png_ptr, "Too many bytes for PNG signature.");
png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
}
/* Checks whether the supplied bytes match the PNG signature. We allow
* checking less than the full 8-byte signature so that those apps that
* already read the first few bytes of a file to determine the file type
* can simply check the remaining bytes for extra assurance. Returns
* an integer less than, equal to, or greater than zero if sig is found,
* respectively, to be less than, to match, or be greater than the correct
* PNG signature (this is the same behaviour as strcmp, memcmp, etc).
*/
int PNGAPI
png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check)
{
png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
if (num_to_check > 8)
num_to_check = 8;
else if (num_to_check < 1)
return (0);
if (start > 7)
return (0);
if (start + num_to_check > 8)
num_to_check = 8 - start;
return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check)));
}
/* (Obsolete) function to check signature bytes. It does not allow one
* to check a partial signature. This function might be removed in the
* future - use png_sig_cmp(). Returns true (nonzero) if the file is a PNG.
*/
int PNGAPI
png_check_sig(png_bytep sig, int num)
{
return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num));
}
/* Function to allocate memory for zlib and clear it to 0. */
#ifdef PNG_1_0_X
voidpf PNGAPI
#else
voidpf /* private */
#endif
png_zalloc(voidpf png_ptr, uInt items, uInt size)
{
png_voidp ptr;
png_structp p=png_ptr;
png_uint_32 save_flags=p->flags;
png_uint_32 num_bytes;
if (items > PNG_UINT_32_MAX/size)
{
png_warning (png_ptr, "Potential overflow in png_zalloc()");
return (NULL);
}
num_bytes = (png_uint_32)items * size;
p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes);
p->flags=save_flags;
#if defined(PNG_1_0_X) && !defined(PNG_NO_ZALLOC_ZERO)
if (ptr == NULL)
return ((voidpf)ptr);
if (num_bytes > (png_uint_32)0x8000L)
{
png_memset(ptr, 0, (png_size_t)0x8000L);
png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0,
(png_size_t)(num_bytes - (png_uint_32)0x8000L));
}
else
{
png_memset(ptr, 0, (png_size_t)num_bytes);
}
#endif
return ((voidpf)ptr);
}
/* function to free memory for zlib */
#ifdef PNG_1_0_X
void PNGAPI
#else
void /* private */
#endif
png_zfree(voidpf png_ptr, voidpf ptr)
{
png_free((png_structp)png_ptr, (png_voidp)ptr);
}
/* Reset the CRC variable to 32 bits of 1's. Care must be taken
* in case CRC is > 32 bits to leave the top bits 0.
*/
void /* PRIVATE */
png_reset_crc(png_structp png_ptr)
{
png_ptr->crc = crc32(0, Z_NULL, 0);
}
/* Calculate the CRC over a section of data. We can only pass as
* much data to this routine as the largest single buffer size. We
* also check that this data will actually be used before going to the
* trouble of calculating it.
*/
void /* PRIVATE */
png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length)
{
int need_crc = 1;
if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
{
if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
(PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
need_crc = 0;
}
else /* critical */
{
if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
need_crc = 0;
}
if (need_crc)
png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
}
/* Allocate the memory for an info_struct for the application. We don't
* really need the png_ptr, but it could potentially be useful in the
* future. This should be used in favour of malloc(png_sizeof(png_info))
* and png_info_init() so that applications that want to use a shared
* libpng don't have to be recompiled if png_info changes size.
*/
png_infop PNGAPI
png_create_info_struct(png_structp png_ptr)
{
png_infop info_ptr;
png_debug(1, "in png_create_info_struct\n");
if(png_ptr == NULL) return (NULL);
#ifdef PNG_USER_MEM_SUPPORTED
info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO,
png_ptr->malloc_fn, png_ptr->mem_ptr);
#else
info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
#endif
if (info_ptr != NULL)
png_info_init_3(&info_ptr, png_sizeof(png_info));
return (info_ptr);
}
/* This function frees the memory associated with a single info struct.
* Normally, one would use either png_destroy_read_struct() or
* png_destroy_write_struct() to free an info struct, but this may be
* useful for some applications.
*/
void PNGAPI
png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
{
png_infop info_ptr = NULL;
png_debug(1, "in png_destroy_info_struct\n");
if (info_ptr_ptr != NULL)
info_ptr = *info_ptr_ptr;
if (info_ptr != NULL)
{
png_info_destroy(png_ptr, info_ptr);
#ifdef PNG_USER_MEM_SUPPORTED
png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn,
png_ptr->mem_ptr);
#else
png_destroy_struct((png_voidp)info_ptr);
#endif
*info_ptr_ptr = NULL;
}
}
/* Initialize the info structure. This is now an internal function (0.89)
* and applications using it are urged to use png_create_info_struct()
* instead.
*/
#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
#undef png_info_init
void PNGAPI
png_info_init(png_infop info_ptr)
{
/* We only come here via pre-1.0.12-compiled applications */
png_info_init_3(&info_ptr, 0);
}
#endif
void PNGAPI
png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
{
png_infop info_ptr = *ptr_ptr;
png_debug(1, "in png_info_init_3\n");
if(png_sizeof(png_info) > png_info_struct_size)
{
png_destroy_struct(info_ptr);
info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
*ptr_ptr = info_ptr;
}
/* set everything to 0 */
png_memset(info_ptr, 0, png_sizeof (png_info));
}
#ifdef PNG_FREE_ME_SUPPORTED
void PNGAPI
png_data_freer(png_structp png_ptr, png_infop info_ptr,
int freer, png_uint_32 mask)
{
png_debug(1, "in png_data_freer\n");
if (png_ptr == NULL || info_ptr == NULL)
return;
if(freer == PNG_DESTROY_WILL_FREE_DATA)
info_ptr->free_me |= mask;
else if(freer == PNG_USER_WILL_FREE_DATA)
info_ptr->free_me &= ~mask;
else
png_warning(png_ptr,
"Unknown freer parameter in png_data_freer.");
}
#endif
void PNGAPI
png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
int num)
{
png_debug(1, "in png_free_data\n");
if (png_ptr == NULL || info_ptr == NULL)
return;
#if defined(PNG_TEXT_SUPPORTED)
/* free text item num or (if num == -1) all text items */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
#else
if (mask & PNG_FREE_TEXT)
#endif
{
if (num != -1)
{
if (info_ptr->text && info_ptr->text[num].key)
{
png_free(png_ptr, info_ptr->text[num].key);
info_ptr->text[num].key = NULL;
}
}
else
{
int i;
for (i = 0; i < info_ptr->num_text; i++)
png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
png_free(png_ptr, info_ptr->text);
info_ptr->text = NULL;
info_ptr->num_text=0;
}
}
#endif
#if defined(PNG_tRNS_SUPPORTED)
/* free any tRNS entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
#else
if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS))
#endif
{
png_free(png_ptr, info_ptr->trans);
info_ptr->valid &= ~PNG_INFO_tRNS;
#ifndef PNG_FREE_ME_SUPPORTED
png_ptr->flags &= ~PNG_FLAG_FREE_TRNS;
#endif
info_ptr->trans = NULL;
}
#endif
#if defined(PNG_sCAL_SUPPORTED)
/* free any sCAL entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
#else
if (mask & PNG_FREE_SCAL)
#endif
{
#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
png_free(png_ptr, info_ptr->scal_s_width);
png_free(png_ptr, info_ptr->scal_s_height);
info_ptr->scal_s_width = NULL;
info_ptr->scal_s_height = NULL;
#endif
info_ptr->valid &= ~PNG_INFO_sCAL;
}
#endif
#if defined(PNG_pCAL_SUPPORTED)
/* free any pCAL entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
#else
if (mask & PNG_FREE_PCAL)
#endif
{
png_free(png_ptr, info_ptr->pcal_purpose);
png_free(png_ptr, info_ptr->pcal_units);
info_ptr->pcal_purpose = NULL;
info_ptr->pcal_units = NULL;
if (info_ptr->pcal_params != NULL)
{
int i;
for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
{
png_free(png_ptr, info_ptr->pcal_params[i]);
info_ptr->pcal_params[i]=NULL;
}
png_free(png_ptr, info_ptr->pcal_params);
info_ptr->pcal_params = NULL;
}
info_ptr->valid &= ~PNG_INFO_pCAL;
}
#endif
#if defined(PNG_iCCP_SUPPORTED)
/* free any iCCP entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
#else
if (mask & PNG_FREE_ICCP)
#endif
{
png_free(png_ptr, info_ptr->iccp_name);
png_free(png_ptr, info_ptr->iccp_profile);
info_ptr->iccp_name = NULL;
info_ptr->iccp_profile = NULL;
info_ptr->valid &= ~PNG_INFO_iCCP;
}
#endif
#if defined(PNG_sPLT_SUPPORTED)
/* free a given sPLT entry, or (if num == -1) all sPLT entries */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
#else
if (mask & PNG_FREE_SPLT)
#endif
{
if (num != -1)
{
if(info_ptr->splt_palettes)
{
png_free(png_ptr, info_ptr->splt_palettes[num].name);
png_free(png_ptr, info_ptr->splt_palettes[num].entries);
info_ptr->splt_palettes[num].name = NULL;
info_ptr->splt_palettes[num].entries = NULL;
}
}
else
{
if(info_ptr->splt_palettes_num)
{
int i;
for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
png_free(png_ptr, info_ptr->splt_palettes);
info_ptr->splt_palettes = NULL;
info_ptr->splt_palettes_num = 0;
}
info_ptr->valid &= ~PNG_INFO_sPLT;
}
}
#endif
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
#else
if (mask & PNG_FREE_UNKN)
#endif
{
if (num != -1)
{
if(info_ptr->unknown_chunks)
{
png_free(png_ptr, info_ptr->unknown_chunks[num].data);
info_ptr->unknown_chunks[num].data = NULL;
}
}
else
{
int i;
if(info_ptr->unknown_chunks_num)
{
for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++)
png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
png_free(png_ptr, info_ptr->unknown_chunks);
info_ptr->unknown_chunks = NULL;
info_ptr->unknown_chunks_num = 0;
}
}
}
#endif
#if defined(PNG_hIST_SUPPORTED)
/* free any hIST entry */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_HIST) & info_ptr->free_me)
#else
if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST))
#endif
{
png_free(png_ptr, info_ptr->hist);
info_ptr->hist = NULL;
info_ptr->valid &= ~PNG_INFO_hIST;
#ifndef PNG_FREE_ME_SUPPORTED
png_ptr->flags &= ~PNG_FLAG_FREE_HIST;
#endif
}
#endif
/* free any PLTE entry that was internally allocated */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
#else
if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE))
#endif
{
png_zfree(png_ptr, info_ptr->palette);
info_ptr->palette = NULL;
info_ptr->valid &= ~PNG_INFO_PLTE;
#ifndef PNG_FREE_ME_SUPPORTED
png_ptr->flags &= ~PNG_FLAG_FREE_PLTE;
#endif
info_ptr->num_palette = 0;
}
#if defined(PNG_INFO_IMAGE_SUPPORTED)
/* free any image bits attached to the info structure */
#ifdef PNG_FREE_ME_SUPPORTED
if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
#else
if (mask & PNG_FREE_ROWS)
#endif
{
if(info_ptr->row_pointers)
{
int row;
for (row = 0; row < (int)info_ptr->height; row++)
{
png_free(png_ptr, info_ptr->row_pointers[row]);
info_ptr->row_pointers[row]=NULL;
}
png_free(png_ptr, info_ptr->row_pointers);
info_ptr->row_pointers=NULL;
}
info_ptr->valid &= ~PNG_INFO_IDAT;
}
#endif
#ifdef PNG_FREE_ME_SUPPORTED
if(num == -1)
info_ptr->free_me &= ~mask;
else
info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL);
#endif
}
/* This is an internal routine to free any memory that the info struct is
* pointing to before re-using it or freeing the struct itself. Recall
* that png_free() checks for NULL pointers for us.
*/
void /* PRIVATE */
png_info_destroy(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_info_destroy\n");
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
if (png_ptr->num_chunk_list)
{
png_free(png_ptr, png_ptr->chunk_list);
png_ptr->chunk_list=NULL;
png_ptr->num_chunk_list=0;
}
#endif
png_info_init_3(&info_ptr, png_sizeof(png_info));
}
/* This function returns a pointer to the io_ptr associated with the user
* functions. The application should free any memory associated with this
* pointer before png_write_destroy() or png_read_destroy() are called.
*/
png_voidp PNGAPI
png_get_io_ptr(png_structp png_ptr)
{
return (png_ptr->io_ptr);
}
#if !defined(PNG_NO_STDIO)
/* Initialize the default input/output functions for the PNG file. If you
* use your own read or write routines, you can call either png_set_read_fn()
* or png_set_write_fn() instead of png_init_io(). If you have defined
* PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't
* necessarily available.
*/
void PNGAPI
png_init_io(png_structp png_ptr, png_FILE_p fp)
{
png_debug(1, "in png_init_io\n");
png_ptr->io_ptr = (png_voidp)fp;
}
#endif
#if defined(PNG_TIME_RFC1123_SUPPORTED)
/* Convert the supplied time into an RFC 1123 string suitable for use in
* a "Creation Time" or other text-based time string.
*/
png_charp PNGAPI
png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime)
{
static PNG_CONST char short_months[12][4] =
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
if (png_ptr->time_buffer == NULL)
{
png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29*
png_sizeof(char)));
}
#if defined(_WIN32_WCE)
{
wchar_t time_buf[29];
wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"),
ptime->day % 32, short_months[(ptime->month - 1) % 12],
ptime->year, ptime->hour % 24, ptime->minute % 60,
ptime->second % 61);
WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, 29,
NULL, NULL);
}
#else
#ifdef USE_FAR_KEYWORD
{
char near_time_buf[29];
sprintf(near_time_buf, "%d %s %d %02d:%02d:%02d +0000",
ptime->day % 32, short_months[(ptime->month - 1) % 12],
ptime->year, ptime->hour % 24, ptime->minute % 60,
ptime->second % 61);
png_memcpy(png_ptr->time_buffer, near_time_buf,
29*png_sizeof(char));
}
#else
sprintf(png_ptr->time_buffer, "%d %s %d %02d:%02d:%02d +0000",
ptime->day % 32, short_months[(ptime->month - 1) % 12],
ptime->year, ptime->hour % 24, ptime->minute % 60,
ptime->second % 61);
#endif
#endif /* _WIN32_WCE */
return ((png_charp)png_ptr->time_buffer);
}
#endif /* PNG_TIME_RFC1123_SUPPORTED */
#if 0
/* Signature string for a PNG file. */
png_bytep PNGAPI
png_sig_bytes(void)
{
return ((png_bytep)"\211\120\116\107\015\012\032\012");
}
#endif
png_charp PNGAPI
png_get_copyright(png_structp png_ptr)
{
if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */
return ((png_charp) "\n libpng version 1.2.8 - December 3, 2004\n\
Copyright (c) 1998-2004 Glenn Randers-Pehrson\n\
Copyright (c) 1996-1997 Andreas Dilger\n\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n");
return ((png_charp) "");
}
/* The following return the library version as a short string in the
* format 1.0.0 through 99.99.99zz. To get the version of *.h files
* used with your application, print out PNG_LIBPNG_VER_STRING, which
* is defined in png.h.
* Note: now there is no difference between png_get_libpng_ver() and
* png_get_header_ver(). Due to the version_nn_nn_nn typedef guard,
* it is guaranteed that png.c uses the correct version of png.h.
*/
png_charp PNGAPI
png_get_libpng_ver(png_structp png_ptr)
{
/* Version of *.c files used when building libpng */
if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */
return ((png_charp) PNG_LIBPNG_VER_STRING);
return ((png_charp) "");
}
png_charp PNGAPI
png_get_header_ver(png_structp png_ptr)
{
/* Version of *.h files used when building libpng */
if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */
return ((png_charp) PNG_LIBPNG_VER_STRING);
return ((png_charp) "");
}
png_charp PNGAPI
png_get_header_version(png_structp png_ptr)
{
/* Returns longer string containing both version and date */
if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */
return ((png_charp) PNG_HEADER_VERSION_STRING);
return ((png_charp) "");
}
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
int PNGAPI
png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name)
{
/* check chunk_name and return "keep" value if it's on the list, else 0 */
int i;
png_bytep p;
if((png_ptr == NULL && chunk_name == NULL) || png_ptr->num_chunk_list<=0)
return 0;
p=png_ptr->chunk_list+png_ptr->num_chunk_list*5-5;
for (i = png_ptr->num_chunk_list; i; i--, p-=5)
if (!png_memcmp(chunk_name, p, 4))
return ((int)*(p+4));
return 0;
}
#endif
/* This function, added to libpng-1.0.6g, is untested. */
int PNGAPI
png_reset_zstream(png_structp png_ptr)
{
return (inflateReset(&png_ptr->zstream));
}
/* This function was added to libpng-1.0.7 */
png_uint_32 PNGAPI
png_access_version_number(void)
{
/* Version of *.c files used when building libpng */
return((png_uint_32) PNG_LIBPNG_VER);
}
#if !defined(PNG_1_0_X)
#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
/* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */
/* this INTERNAL function was added to libpng 1.2.0 */
void /* PRIVATE */
png_init_mmx_flags (png_structp png_ptr)
{
png_ptr->mmx_rowbytes_threshold = 0;
png_ptr->mmx_bitdepth_threshold = 0;
# if (defined(PNG_USE_PNGVCRD) || defined(PNG_USE_PNGGCCRD))
png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_COMPILED;
if (png_mmx_support() > 0) {
png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU
# ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW
| PNG_ASM_FLAG_MMX_READ_COMBINE_ROW
# endif
# ifdef PNG_HAVE_ASSEMBLER_READ_INTERLACE
| PNG_ASM_FLAG_MMX_READ_INTERLACE
# endif
# ifndef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
;
# else
| PNG_ASM_FLAG_MMX_READ_FILTER_SUB
| PNG_ASM_FLAG_MMX_READ_FILTER_UP
| PNG_ASM_FLAG_MMX_READ_FILTER_AVG
| PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
png_ptr->mmx_rowbytes_threshold = PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT;
png_ptr->mmx_bitdepth_threshold = PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT;
# endif
} else {
png_ptr->asm_flags &= ~( PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU
| PNG_MMX_READ_FLAGS
| PNG_MMX_WRITE_FLAGS );
}
# else /* !((PNGVCRD || PNGGCCRD) && PNG_ASSEMBLER_CODE_SUPPORTED)) */
/* clear all MMX flags; no support is compiled in */
png_ptr->asm_flags &= ~( PNG_MMX_FLAGS );
# endif /* ?(PNGVCRD || PNGGCCRD) */
}
#endif /* !(PNG_ASSEMBLER_CODE_SUPPORTED) */
/* this function was added to libpng 1.2.0 */
#if !defined(PNG_USE_PNGGCCRD) && \
!(defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD))
int PNGAPI
png_mmx_support(void)
{
return -1;
}
#endif
#endif /* PNG_1_0_X */
#ifdef PNG_SIZE_T
/* Added at libpng version 1.2.6 */
PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
png_size_t PNGAPI
png_convert_size(size_t size)
{
if (size > (png_size_t)-1)
PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */
return ((png_size_t)size);
}
#endif /* PNG_SIZE_T */

3419
libpng/png.h Normal file

File diff suppressed because it is too large Load Diff

1437
libpng/pngconf.h Normal file

File diff suppressed because it is too large Load Diff

295
libpng/pngerror.c Normal file
View File

@ -0,0 +1,295 @@
/* pngerror.c - stub functions for i/o and memory allocation
*
* libpng version 1.2.8 - December 3, 2004
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1998-2004 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This file provides a location for all error handling. Users who
* need special error handling are expected to write replacement functions
* and use png_set_error_fn() to use those functions. See the instructions
* at each function.
*/
#define PNG_INTERNAL
#include "png.h"
static void /* PRIVATE */
png_default_error PNGARG((png_structp png_ptr,
png_const_charp error_message));
static void /* PRIVATE */
png_default_warning PNGARG((png_structp png_ptr,
png_const_charp warning_message));
/* This function is called whenever there is a fatal error. This function
* should not be changed. If there is a need to handle errors differently,
* you should supply a replacement error function and use png_set_error_fn()
* to replace the error function at run-time.
*/
void PNGAPI
png_error(png_structp png_ptr, png_const_charp error_message)
{
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
char msg[16];
if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
{
if (*error_message == '#')
{
int offset;
for (offset=1; offset<15; offset++)
if (*(error_message+offset) == ' ')
break;
if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
{
int i;
for (i=0; i<offset-1; i++)
msg[i]=error_message[i+1];
msg[i]='\0';
error_message=msg;
}
else
error_message+=offset;
}
else
{
if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
{
msg[0]='0';
msg[1]='\0';
error_message=msg;
}
}
}
#endif
if (png_ptr != NULL && png_ptr->error_fn != NULL)
(*(png_ptr->error_fn))(png_ptr, error_message);
/* If the custom handler doesn't exist, or if it returns,
use the default handler, which will not return. */
png_default_error(png_ptr, error_message);
}
/* This function is called whenever there is a non-fatal error. This function
* should not be changed. If there is a need to handle warnings differently,
* you should supply a replacement warning function and use
* png_set_error_fn() to replace the warning function at run-time.
*/
void PNGAPI
png_warning(png_structp png_ptr, png_const_charp warning_message)
{
int offset = 0;
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
#endif
{
if (*warning_message == '#')
{
for (offset=1; offset<15; offset++)
if (*(warning_message+offset) == ' ')
break;
}
}
if (png_ptr != NULL && png_ptr->warning_fn != NULL)
(*(png_ptr->warning_fn))(png_ptr, warning_message+offset);
else
png_default_warning(png_ptr, warning_message+offset);
}
/* These utilities are used internally to build an error message that relates
* to the current chunk. The chunk name comes from png_ptr->chunk_name,
* this is used to prefix the message. The message is limited in length
* to 63 bytes, the name characters are output as hex digits wrapped in []
* if the character is invalid.
*/
#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
static PNG_CONST char png_digit[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'
};
static void /* PRIVATE */
png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp
error_message)
{
int iout = 0, iin = 0;
while (iin < 4)
{
int c = png_ptr->chunk_name[iin++];
if (isnonalpha(c))
{
buffer[iout++] = '[';
buffer[iout++] = png_digit[(c & 0xf0) >> 4];
buffer[iout++] = png_digit[c & 0x0f];
buffer[iout++] = ']';
}
else
{
buffer[iout++] = (png_byte)c;
}
}
if (error_message == NULL)
buffer[iout] = 0;
else
{
buffer[iout++] = ':';
buffer[iout++] = ' ';
png_strncpy(buffer+iout, error_message, 63);
buffer[iout+63] = 0;
}
}
void PNGAPI
png_chunk_error(png_structp png_ptr, png_const_charp error_message)
{
char msg[18+64];
png_format_buffer(png_ptr, msg, error_message);
png_error(png_ptr, msg);
}
void PNGAPI
png_chunk_warning(png_structp png_ptr, png_const_charp warning_message)
{
char msg[18+64];
png_format_buffer(png_ptr, msg, warning_message);
png_warning(png_ptr, msg);
}
/* This is the default error handling function. Note that replacements for
* this function MUST NOT RETURN, or the program will likely crash. This
* function is used by default, or if the program supplies NULL for the
* error function pointer in png_set_error_fn().
*/
static void /* PRIVATE */
png_default_error(png_structp png_ptr, png_const_charp error_message)
{
#ifndef PNG_NO_CONSOLE_IO
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
if (*error_message == '#')
{
int offset;
char error_number[16];
for (offset=0; offset<15; offset++)
{
error_number[offset] = *(error_message+offset+1);
if (*(error_message+offset) == ' ')
break;
}
if((offset > 1) && (offset < 15))
{
error_number[offset-1]='\0';
fprintf(stderr, "libpng error no. %s: %s\n", error_number,
error_message+offset);
}
else
fprintf(stderr, "libpng error: %s, offset=%d\n", error_message,offset);
}
else
#endif
fprintf(stderr, "libpng error: %s\n", error_message);
#endif
#ifdef PNG_SETJMP_SUPPORTED
# ifdef USE_FAR_KEYWORD
{
jmp_buf jmpbuf;
png_memcpy(jmpbuf,png_ptr->jmpbuf,png_sizeof(jmp_buf));
longjmp(jmpbuf, 1);
}
# else
longjmp(png_ptr->jmpbuf, 1);
# endif
#else
/* make compiler happy */ ;
if (png_ptr)
PNG_ABORT();
#endif
#ifdef PNG_NO_CONSOLE_IO
/* make compiler happy */ ;
if (&error_message != NULL)
return;
#endif
}
/* This function is called when there is a warning, but the library thinks
* it can continue anyway. Replacement functions don't have to do anything
* here if you don't want them to. In the default configuration, png_ptr is
* not used, but it is passed in case it may be useful.
*/
static void /* PRIVATE */
png_default_warning(png_structp png_ptr, png_const_charp warning_message)
{
#ifndef PNG_NO_CONSOLE_IO
# ifdef PNG_ERROR_NUMBERS_SUPPORTED
if (*warning_message == '#')
{
int offset;
char warning_number[16];
for (offset=0; offset<15; offset++)
{
warning_number[offset]=*(warning_message+offset+1);
if (*(warning_message+offset) == ' ')
break;
}
if((offset > 1) && (offset < 15))
{
warning_number[offset-1]='\0';
fprintf(stderr, "libpng warning no. %s: %s\n", warning_number,
warning_message+offset);
}
else
fprintf(stderr, "libpng warning: %s\n", warning_message);
}
else
# endif
fprintf(stderr, "libpng warning: %s\n", warning_message);
#else
/* make compiler happy */ ;
if (warning_message)
return;
#endif
/* make compiler happy */ ;
if (png_ptr)
return;
}
/* This function is called when the application wants to use another method
* of handling errors and warnings. Note that the error function MUST NOT
* return to the calling routine or serious problems will occur. The return
* method used in the default routine calls longjmp(png_ptr->jmpbuf, 1)
*/
void PNGAPI
png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
png_error_ptr error_fn, png_error_ptr warning_fn)
{
png_ptr->error_ptr = error_ptr;
png_ptr->error_fn = error_fn;
png_ptr->warning_fn = warning_fn;
}
/* This function returns a pointer to the error_ptr associated with the user
* functions. The application should free any memory associated with this
* pointer before png_write_destroy and png_read_destroy are called.
*/
png_voidp PNGAPI
png_get_error_ptr(png_structp png_ptr)
{
return ((png_voidp)png_ptr->error_ptr);
}
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
void PNGAPI
png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode)
{
if(png_ptr != NULL)
{
png_ptr->flags &=
((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
}
}
#endif

934
libpng/pngget.c Normal file
View File

@ -0,0 +1,934 @@
/* pngget.c - retrieval of values from info struct
*
* libpng 1.2.8 - December 3, 2004
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1998-2004 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*/
#define PNG_INTERNAL
#include "png.h"
png_uint_32 PNGAPI
png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag)
{
if (png_ptr != NULL && info_ptr != NULL)
return(info_ptr->valid & flag);
else
return(0);
}
png_uint_32 PNGAPI
png_get_rowbytes(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
return(info_ptr->rowbytes);
else
return(0);
}
#if defined(PNG_INFO_IMAGE_SUPPORTED)
png_bytepp PNGAPI
png_get_rows(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
return(info_ptr->row_pointers);
else
return(0);
}
#endif
#ifdef PNG_EASY_ACCESS_SUPPORTED
/* easy access to info, added in libpng-0.99 */
png_uint_32 PNGAPI
png_get_image_width(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
{
return info_ptr->width;
}
return (0);
}
png_uint_32 PNGAPI
png_get_image_height(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
{
return info_ptr->height;
}
return (0);
}
png_byte PNGAPI
png_get_bit_depth(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
{
return info_ptr->bit_depth;
}
return (0);
}
png_byte PNGAPI
png_get_color_type(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
{
return info_ptr->color_type;
}
return (0);
}
png_byte PNGAPI
png_get_filter_type(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
{
return info_ptr->filter_type;
}
return (0);
}
png_byte PNGAPI
png_get_interlace_type(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
{
return info_ptr->interlace_type;
}
return (0);
}
png_byte PNGAPI
png_get_compression_type(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
{
return info_ptr->compression_type;
}
return (0);
}
png_uint_32 PNGAPI
png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
#if defined(PNG_pHYs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_pHYs)
{
png_debug1(1, "in %s retrieval function\n", "png_get_x_pixels_per_meter");
if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
return (0);
else return (info_ptr->x_pixels_per_unit);
}
#else
return (0);
#endif
return (0);
}
png_uint_32 PNGAPI
png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
#if defined(PNG_pHYs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_pHYs)
{
png_debug1(1, "in %s retrieval function\n", "png_get_y_pixels_per_meter");
if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
return (0);
else return (info_ptr->y_pixels_per_unit);
}
#else
return (0);
#endif
return (0);
}
png_uint_32 PNGAPI
png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
#if defined(PNG_pHYs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_pHYs)
{
png_debug1(1, "in %s retrieval function\n", "png_get_pixels_per_meter");
if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER ||
info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit)
return (0);
else return (info_ptr->x_pixels_per_unit);
}
#else
return (0);
#endif
return (0);
}
#ifdef PNG_FLOATING_POINT_SUPPORTED
float PNGAPI
png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
#if defined(PNG_pHYs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_pHYs)
{
png_debug1(1, "in %s retrieval function\n", "png_get_aspect_ratio");
if (info_ptr->x_pixels_per_unit == 0)
return ((float)0.0);
else
return ((float)((float)info_ptr->y_pixels_per_unit
/(float)info_ptr->x_pixels_per_unit));
}
#else
return (0.0);
#endif
return ((float)0.0);
}
#endif
png_int_32 PNGAPI
png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
#if defined(PNG_oFFs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_oFFs)
{
png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
return (0);
else return (info_ptr->x_offset);
}
#else
return (0);
#endif
return (0);
}
png_int_32 PNGAPI
png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
#if defined(PNG_oFFs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_oFFs)
{
png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
return (0);
else return (info_ptr->y_offset);
}
#else
return (0);
#endif
return (0);
}
png_int_32 PNGAPI
png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
#if defined(PNG_oFFs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_oFFs)
{
png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
return (0);
else return (info_ptr->x_offset);
}
#else
return (0);
#endif
return (0);
}
png_int_32 PNGAPI
png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
#if defined(PNG_oFFs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_oFFs)
{
png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
return (0);
else return (info_ptr->y_offset);
}
#else
return (0);
#endif
return (0);
}
#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED)
png_uint_32 PNGAPI
png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
{
return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr)
*.0254 +.5));
}
png_uint_32 PNGAPI
png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
{
return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr)
*.0254 +.5));
}
png_uint_32 PNGAPI
png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
{
return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr)
*.0254 +.5));
}
float PNGAPI
png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr)
{
return ((float)png_get_x_offset_microns(png_ptr, info_ptr)
*.00003937);
}
float PNGAPI
png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr)
{
return ((float)png_get_y_offset_microns(png_ptr, info_ptr)
*.00003937);
}
#if defined(PNG_pHYs_SUPPORTED)
png_uint_32 PNGAPI
png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr,
png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
{
png_uint_32 retval = 0;
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
{
png_debug1(1, "in %s retrieval function\n", "pHYs");
if (res_x != NULL)
{
*res_x = info_ptr->x_pixels_per_unit;
retval |= PNG_INFO_pHYs;
}
if (res_y != NULL)
{
*res_y = info_ptr->y_pixels_per_unit;
retval |= PNG_INFO_pHYs;
}
if (unit_type != NULL)
{
*unit_type = (int)info_ptr->phys_unit_type;
retval |= PNG_INFO_pHYs;
if(*unit_type == 1)
{
if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50);
if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50);
}
}
}
return (retval);
}
#endif /* PNG_pHYs_SUPPORTED */
#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */
/* png_get_channels really belongs in here, too, but it's been around longer */
#endif /* PNG_EASY_ACCESS_SUPPORTED */
png_byte PNGAPI
png_get_channels(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
return(info_ptr->channels);
else
return (0);
}
png_bytep PNGAPI
png_get_signature(png_structp png_ptr, png_infop info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
return(info_ptr->signature);
else
return (NULL);
}
#if defined(PNG_bKGD_SUPPORTED)
png_uint_32 PNGAPI
png_get_bKGD(png_structp png_ptr, png_infop info_ptr,
png_color_16p *background)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)
&& background != NULL)
{
png_debug1(1, "in %s retrieval function\n", "bKGD");
*background = &(info_ptr->background);
return (PNG_INFO_bKGD);
}
return (0);
}
#endif
#if defined(PNG_cHRM_SUPPORTED)
#ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_cHRM(png_structp png_ptr, png_infop info_ptr,
double *white_x, double *white_y, double *red_x, double *red_y,
double *green_x, double *green_y, double *blue_x, double *blue_y)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
{
png_debug1(1, "in %s retrieval function\n", "cHRM");
if (white_x != NULL)
*white_x = (double)info_ptr->x_white;
if (white_y != NULL)
*white_y = (double)info_ptr->y_white;
if (red_x != NULL)
*red_x = (double)info_ptr->x_red;
if (red_y != NULL)
*red_y = (double)info_ptr->y_red;
if (green_x != NULL)
*green_x = (double)info_ptr->x_green;
if (green_y != NULL)
*green_y = (double)info_ptr->y_green;
if (blue_x != NULL)
*blue_x = (double)info_ptr->x_blue;
if (blue_y != NULL)
*blue_y = (double)info_ptr->y_blue;
return (PNG_INFO_cHRM);
}
return (0);
}
#endif
#ifdef PNG_FIXED_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr,
png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x,
png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y,
png_fixed_point *blue_x, png_fixed_point *blue_y)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
{
png_debug1(1, "in %s retrieval function\n", "cHRM");
if (white_x != NULL)
*white_x = info_ptr->int_x_white;
if (white_y != NULL)
*white_y = info_ptr->int_y_white;
if (red_x != NULL)
*red_x = info_ptr->int_x_red;
if (red_y != NULL)
*red_y = info_ptr->int_y_red;
if (green_x != NULL)
*green_x = info_ptr->int_x_green;
if (green_y != NULL)
*green_y = info_ptr->int_y_green;
if (blue_x != NULL)
*blue_x = info_ptr->int_x_blue;
if (blue_y != NULL)
*blue_y = info_ptr->int_y_blue;
return (PNG_INFO_cHRM);
}
return (0);
}
#endif
#endif
#if defined(PNG_gAMA_SUPPORTED)
#ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
&& file_gamma != NULL)
{
png_debug1(1, "in %s retrieval function\n", "gAMA");
*file_gamma = (double)info_ptr->gamma;
return (PNG_INFO_gAMA);
}
return (0);
}
#endif
#ifdef PNG_FIXED_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr,
png_fixed_point *int_file_gamma)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
&& int_file_gamma != NULL)
{
png_debug1(1, "in %s retrieval function\n", "gAMA");
*int_file_gamma = info_ptr->int_gamma;
return (PNG_INFO_gAMA);
}
return (0);
}
#endif
#endif
#if defined(PNG_sRGB_SUPPORTED)
png_uint_32 PNGAPI
png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)
&& file_srgb_intent != NULL)
{
png_debug1(1, "in %s retrieval function\n", "sRGB");
*file_srgb_intent = (int)info_ptr->srgb_intent;
return (PNG_INFO_sRGB);
}
return (0);
}
#endif
#if defined(PNG_iCCP_SUPPORTED)
png_uint_32 PNGAPI
png_get_iCCP(png_structp png_ptr, png_infop info_ptr,
png_charpp name, int *compression_type,
png_charpp profile, png_uint_32 *proflen)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)
&& name != NULL && profile != NULL && proflen != NULL)
{
png_debug1(1, "in %s retrieval function\n", "iCCP");
*name = info_ptr->iccp_name;
*profile = info_ptr->iccp_profile;
/* compression_type is a dummy so the API won't have to change
if we introduce multiple compression types later. */
*proflen = (int)info_ptr->iccp_proflen;
*compression_type = (int)info_ptr->iccp_compression;
return (PNG_INFO_iCCP);
}
return (0);
}
#endif
#if defined(PNG_sPLT_SUPPORTED)
png_uint_32 PNGAPI
png_get_sPLT(png_structp png_ptr, png_infop info_ptr,
png_sPLT_tpp spalettes)
{
if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL)
*spalettes = info_ptr->splt_palettes;
return ((png_uint_32)info_ptr->splt_palettes_num);
}
#endif
#if defined(PNG_hIST_SUPPORTED)
png_uint_32 PNGAPI
png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)
&& hist != NULL)
{
png_debug1(1, "in %s retrieval function\n", "hIST");
*hist = info_ptr->hist;
return (PNG_INFO_hIST);
}
return (0);
}
#endif
png_uint_32 PNGAPI
png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
png_uint_32 *width, png_uint_32 *height, int *bit_depth,
int *color_type, int *interlace_type, int *compression_type,
int *filter_type)
{
if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL &&
bit_depth != NULL && color_type != NULL)
{
png_debug1(1, "in %s retrieval function\n", "IHDR");
*width = info_ptr->width;
*height = info_ptr->height;
*bit_depth = info_ptr->bit_depth;
if (info_ptr->bit_depth < 1 || info_ptr->bit_depth > 16)
png_error(png_ptr, "Invalid bit depth");
*color_type = info_ptr->color_type;
if (info_ptr->color_type > 6)
png_error(png_ptr, "Invalid color type");
if (compression_type != NULL)
*compression_type = info_ptr->compression_type;
if (filter_type != NULL)
*filter_type = info_ptr->filter_type;
if (interlace_type != NULL)
*interlace_type = info_ptr->interlace_type;
/* check for potential overflow of rowbytes */
if (*width == 0 || *width > PNG_UINT_31_MAX)
png_error(png_ptr, "Invalid image width");
if (*height == 0 || *height > PNG_UINT_31_MAX)
png_error(png_ptr, "Invalid image height");
if (info_ptr->width > (PNG_UINT_32_MAX
>> 3) /* 8-byte RGBA pixels */
- 64 /* bigrowbuf hack */
- 1 /* filter byte */
- 7*8 /* rounding of width to multiple of 8 pixels */
- 8) /* extra max_pixel_depth pad */
{
png_warning(png_ptr,
"Width too large for libpng to process image data.");
}
return (1);
}
return (0);
}
#if defined(PNG_oFFs_SUPPORTED)
png_uint_32 PNGAPI
png_get_oFFs(png_structp png_ptr, png_infop info_ptr,
png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)
&& offset_x != NULL && offset_y != NULL && unit_type != NULL)
{
png_debug1(1, "in %s retrieval function\n", "oFFs");
*offset_x = info_ptr->x_offset;
*offset_y = info_ptr->y_offset;
*unit_type = (int)info_ptr->offset_unit_type;
return (PNG_INFO_oFFs);
}
return (0);
}
#endif
#if defined(PNG_pCAL_SUPPORTED)
png_uint_32 PNGAPI
png_get_pCAL(png_structp png_ptr, png_infop info_ptr,
png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,
png_charp *units, png_charpp *params)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)
&& purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&
nparams != NULL && units != NULL && params != NULL)
{
png_debug1(1, "in %s retrieval function\n", "pCAL");
*purpose = info_ptr->pcal_purpose;
*X0 = info_ptr->pcal_X0;
*X1 = info_ptr->pcal_X1;
*type = (int)info_ptr->pcal_type;
*nparams = (int)info_ptr->pcal_nparams;
*units = info_ptr->pcal_units;
*params = info_ptr->pcal_params;
return (PNG_INFO_pCAL);
}
return (0);
}
#endif
#if defined(PNG_sCAL_SUPPORTED)
#ifdef PNG_FLOATING_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_sCAL(png_structp png_ptr, png_infop info_ptr,
int *unit, double *width, double *height)
{
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_sCAL))
{
*unit = info_ptr->scal_unit;
*width = info_ptr->scal_pixel_width;
*height = info_ptr->scal_pixel_height;
return (PNG_INFO_sCAL);
}
return(0);
}
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
png_uint_32 PNGAPI
png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr,
int *unit, png_charpp width, png_charpp height)
{
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_sCAL))
{
*unit = info_ptr->scal_unit;
*width = info_ptr->scal_s_width;
*height = info_ptr->scal_s_height;
return (PNG_INFO_sCAL);
}
return(0);
}
#endif
#endif
#endif
#if defined(PNG_pHYs_SUPPORTED)
png_uint_32 PNGAPI
png_get_pHYs(png_structp png_ptr, png_infop info_ptr,
png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
{
png_uint_32 retval = 0;
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_pHYs))
{
png_debug1(1, "in %s retrieval function\n", "pHYs");
if (res_x != NULL)
{
*res_x = info_ptr->x_pixels_per_unit;
retval |= PNG_INFO_pHYs;
}
if (res_y != NULL)
{
*res_y = info_ptr->y_pixels_per_unit;
retval |= PNG_INFO_pHYs;
}
if (unit_type != NULL)
{
*unit_type = (int)info_ptr->phys_unit_type;
retval |= PNG_INFO_pHYs;
}
}
return (retval);
}
#endif
png_uint_32 PNGAPI
png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette,
int *num_palette)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE)
&& palette != NULL)
{
png_debug1(1, "in %s retrieval function\n", "PLTE");
*palette = info_ptr->palette;
*num_palette = info_ptr->num_palette;
png_debug1(3, "num_palette = %d\n", *num_palette);
return (PNG_INFO_PLTE);
}
return (0);
}
#if defined(PNG_sBIT_SUPPORTED)
png_uint_32 PNGAPI
png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)
&& sig_bit != NULL)
{
png_debug1(1, "in %s retrieval function\n", "sBIT");
*sig_bit = &(info_ptr->sig_bit);
return (PNG_INFO_sBIT);
}
return (0);
}
#endif
#if defined(PNG_TEXT_SUPPORTED)
png_uint_32 PNGAPI
png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr,
int *num_text)
{
if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)
{
png_debug1(1, "in %s retrieval function\n",
(png_ptr->chunk_name[0] == '\0' ? "text"
: (png_const_charp)png_ptr->chunk_name));
if (text_ptr != NULL)
*text_ptr = info_ptr->text;
if (num_text != NULL)
*num_text = info_ptr->num_text;
return ((png_uint_32)info_ptr->num_text);
}
if (num_text != NULL)
*num_text = 0;
return(0);
}
#endif
#if defined(PNG_tIME_SUPPORTED)
png_uint_32 PNGAPI
png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time)
{
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)
&& mod_time != NULL)
{
png_debug1(1, "in %s retrieval function\n", "tIME");
*mod_time = &(info_ptr->mod_time);
return (PNG_INFO_tIME);
}
return (0);
}
#endif
#if defined(PNG_tRNS_SUPPORTED)
png_uint_32 PNGAPI
png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
png_bytep *trans, int *num_trans, png_color_16p *trans_values)
{
png_uint_32 retval = 0;
if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
{
png_debug1(1, "in %s retrieval function\n", "tRNS");
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (trans != NULL)
{
*trans = info_ptr->trans;
retval |= PNG_INFO_tRNS;
}
if (trans_values != NULL)
*trans_values = &(info_ptr->trans_values);
}
else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */
{
if (trans_values != NULL)
{
*trans_values = &(info_ptr->trans_values);
retval |= PNG_INFO_tRNS;
}
if(trans != NULL)
*trans = NULL;
}
if(num_trans != NULL)
{
*num_trans = info_ptr->num_trans;
retval |= PNG_INFO_tRNS;
}
}
return (retval);
}
#endif
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
png_uint_32 PNGAPI
png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr,
png_unknown_chunkpp unknowns)
{
if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL)
*unknowns = info_ptr->unknown_chunks;
return ((png_uint_32)info_ptr->unknown_chunks_num);
}
#endif
#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
png_byte PNGAPI
png_get_rgb_to_gray_status (png_structp png_ptr)
{
return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0);
}
#endif
#if defined(PNG_USER_CHUNKS_SUPPORTED)
png_voidp PNGAPI
png_get_user_chunk_ptr(png_structp png_ptr)
{
return (png_ptr? png_ptr->user_chunk_ptr : NULL);
}
#endif
#ifdef PNG_WRITE_SUPPORTED
png_uint_32 PNGAPI
png_get_compression_buffer_size(png_structp png_ptr)
{
return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L);
}
#endif
#ifndef PNG_1_0_X
#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
/* this function was added to libpng 1.2.0 and should exist by default */
png_uint_32 PNGAPI
png_get_asm_flags (png_structp png_ptr)
{
return (png_uint_32)(png_ptr? png_ptr->asm_flags : 0L);
}
/* this function was added to libpng 1.2.0 and should exist by default */
png_uint_32 PNGAPI
png_get_asm_flagmask (int flag_select)
{
png_uint_32 settable_asm_flags = 0;
if (flag_select & PNG_SELECT_READ)
settable_asm_flags |=
PNG_ASM_FLAG_MMX_READ_COMBINE_ROW |
PNG_ASM_FLAG_MMX_READ_INTERLACE |
PNG_ASM_FLAG_MMX_READ_FILTER_SUB |
PNG_ASM_FLAG_MMX_READ_FILTER_UP |
PNG_ASM_FLAG_MMX_READ_FILTER_AVG |
PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
/* no non-MMX flags yet */
#if 0
/* GRR: no write-flags yet, either, but someday... */
if (flag_select & PNG_SELECT_WRITE)
settable_asm_flags |=
PNG_ASM_FLAG_MMX_WRITE_ [whatever] ;
#endif /* 0 */
return settable_asm_flags; /* _theoretically_ settable capabilities only */
}
#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
/* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */
/* this function was added to libpng 1.2.0 */
png_uint_32 PNGAPI
png_get_mmx_flagmask (int flag_select, int *compilerID)
{
png_uint_32 settable_mmx_flags = 0;
if (flag_select & PNG_SELECT_READ)
settable_mmx_flags |=
PNG_ASM_FLAG_MMX_READ_COMBINE_ROW |
PNG_ASM_FLAG_MMX_READ_INTERLACE |
PNG_ASM_FLAG_MMX_READ_FILTER_SUB |
PNG_ASM_FLAG_MMX_READ_FILTER_UP |
PNG_ASM_FLAG_MMX_READ_FILTER_AVG |
PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
#if 0
/* GRR: no MMX write support yet, but someday... */
if (flag_select & PNG_SELECT_WRITE)
settable_mmx_flags |=
PNG_ASM_FLAG_MMX_WRITE_ [whatever] ;
#endif /* 0 */
if (compilerID != NULL) {
#ifdef PNG_USE_PNGVCRD
*compilerID = 1; /* MSVC */
#else
#ifdef PNG_USE_PNGGCCRD
*compilerID = 2; /* gcc/gas */
#else
*compilerID = -1; /* unknown (i.e., no asm/MMX code compiled) */
#endif
#endif
}
return settable_mmx_flags; /* _theoretically_ settable capabilities only */
}
/* this function was added to libpng 1.2.0 */
png_byte PNGAPI
png_get_mmx_bitdepth_threshold (png_structp png_ptr)
{
return (png_byte)(png_ptr? png_ptr->mmx_bitdepth_threshold : 0);
}
/* this function was added to libpng 1.2.0 */
png_uint_32 PNGAPI
png_get_mmx_rowbytes_threshold (png_structp png_ptr)
{
return (png_uint_32)(png_ptr? png_ptr->mmx_rowbytes_threshold : 0L);
}
#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
/* these functions were added to libpng 1.2.6 */
png_uint_32 PNGAPI
png_get_user_width_max (png_structp png_ptr)
{
return (png_ptr? png_ptr->user_width_max : 0);
}
png_uint_32 PNGAPI
png_get_user_height_max (png_structp png_ptr)
{
return (png_ptr? png_ptr->user_height_max : 0);
}
#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
#endif /* ?PNG_1_0_X */

595
libpng/pngmem.c Normal file
View File

@ -0,0 +1,595 @@
/* pngmem.c - stub functions for memory allocation
*
* libpng version 1.2.8 - December 3, 2004
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1998-2004 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This file provides a location for all memory allocation. Users who
* need special memory handling are expected to supply replacement
* functions for png_malloc() and png_free(), and to use
* png_create_read_struct_2() and png_create_write_struct_2() to
* identify the replacement functions.
*/
#define PNG_INTERNAL
#include "png.h"
/* Borland DOS special memory handler */
#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
/* if you change this, be sure to change the one in png.h also */
/* Allocate memory for a png_struct. The malloc and memset can be replaced
by a single call to calloc() if this is thought to improve performance. */
png_voidp /* PRIVATE */
png_create_struct(int type)
{
#ifdef PNG_USER_MEM_SUPPORTED
return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL));
}
/* Alternate version of png_create_struct, for use with user-defined malloc. */
png_voidp /* PRIVATE */
png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
{
#endif /* PNG_USER_MEM_SUPPORTED */
png_size_t size;
png_voidp struct_ptr;
if (type == PNG_STRUCT_INFO)
size = png_sizeof(png_info);
else if (type == PNG_STRUCT_PNG)
size = png_sizeof(png_struct);
else
return (png_get_copyright(NULL));
#ifdef PNG_USER_MEM_SUPPORTED
if(malloc_fn != NULL)
{
png_struct dummy_struct;
png_structp png_ptr = &dummy_struct;
png_ptr->mem_ptr=mem_ptr;
struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size);
}
else
#endif /* PNG_USER_MEM_SUPPORTED */
struct_ptr = (png_voidp)farmalloc(size);
if (struct_ptr != NULL)
png_memset(struct_ptr, 0, size);
return (struct_ptr);
}
/* Free memory allocated by a png_create_struct() call */
void /* PRIVATE */
png_destroy_struct(png_voidp struct_ptr)
{
#ifdef PNG_USER_MEM_SUPPORTED
png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL);
}
/* Free memory allocated by a png_create_struct() call */
void /* PRIVATE */
png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
png_voidp mem_ptr)
{
#endif
if (struct_ptr != NULL)
{
#ifdef PNG_USER_MEM_SUPPORTED
if(free_fn != NULL)
{
png_struct dummy_struct;
png_structp png_ptr = &dummy_struct;
png_ptr->mem_ptr=mem_ptr;
(*(free_fn))(png_ptr, struct_ptr);
return;
}
#endif /* PNG_USER_MEM_SUPPORTED */
farfree (struct_ptr);
}
}
/* Allocate memory. For reasonable files, size should never exceed
* 64K. However, zlib may allocate more then 64K if you don't tell
* it not to. See zconf.h and png.h for more information. zlib does
* need to allocate exactly 64K, so whatever you call here must
* have the ability to do that.
*
* Borland seems to have a problem in DOS mode for exactly 64K.
* It gives you a segment with an offset of 8 (perhaps to store its
* memory stuff). zlib doesn't like this at all, so we have to
* detect and deal with it. This code should not be needed in
* Windows or OS/2 modes, and only in 16 bit mode. This code has
* been updated by Alexander Lehmann for version 0.89 to waste less
* memory.
*
* Note that we can't use png_size_t for the "size" declaration,
* since on some systems a png_size_t is a 16-bit quantity, and as a
* result, we would be truncating potentially larger memory requests
* (which should cause a fatal error) and introducing major problems.
*/
png_voidp PNGAPI
png_malloc(png_structp png_ptr, png_uint_32 size)
{
png_voidp ret;
if (png_ptr == NULL || size == 0)
return (NULL);
#ifdef PNG_USER_MEM_SUPPORTED
if(png_ptr->malloc_fn != NULL)
ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size));
else
ret = (png_malloc_default(png_ptr, size));
if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr, "Out of memory!");
return (ret);
}
png_voidp PNGAPI
png_malloc_default(png_structp png_ptr, png_uint_32 size)
{
png_voidp ret;
#endif /* PNG_USER_MEM_SUPPORTED */
#ifdef PNG_MAX_MALLOC_64K
if (size > (png_uint_32)65536L)
{
png_warning(png_ptr, "Cannot Allocate > 64K");
ret = NULL;
}
else
#endif
if (size != (size_t)size)
ret = NULL;
else if (size == (png_uint_32)65536L)
{
if (png_ptr->offset_table == NULL)
{
/* try to see if we need to do any of this fancy stuff */
ret = farmalloc(size);
if (ret == NULL || ((png_size_t)ret & 0xffff))
{
int num_blocks;
png_uint_32 total_size;
png_bytep table;
int i;
png_byte huge * hptr;
if (ret != NULL)
{
farfree(ret);
ret = NULL;
}
if(png_ptr->zlib_window_bits > 14)
num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14));
else
num_blocks = 1;
if (png_ptr->zlib_mem_level >= 7)
num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7));
else
num_blocks++;
total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16;
table = farmalloc(total_size);
if (table == NULL)
{
#ifndef PNG_USER_MEM_SUPPORTED
if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */
else
png_warning(png_ptr, "Out Of Memory.");
#endif
return (NULL);
}
if ((png_size_t)table & 0xfff0)
{
#ifndef PNG_USER_MEM_SUPPORTED
if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr,
"Farmalloc didn't return normalized pointer");
else
png_warning(png_ptr,
"Farmalloc didn't return normalized pointer");
#endif
return (NULL);
}
png_ptr->offset_table = table;
png_ptr->offset_table_ptr = farmalloc(num_blocks *
png_sizeof (png_bytep));
if (png_ptr->offset_table_ptr == NULL)
{
#ifndef PNG_USER_MEM_SUPPORTED
if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr, "Out Of memory."); /* Note "O" and "M" */
else
png_warning(png_ptr, "Out Of memory.");
#endif
return (NULL);
}
hptr = (png_byte huge *)table;
if ((png_size_t)hptr & 0xf)
{
hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */
}
for (i = 0; i < num_blocks; i++)
{
png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */
}
png_ptr->offset_table_number = num_blocks;
png_ptr->offset_table_count = 0;
png_ptr->offset_table_count_free = 0;
}
}
if (png_ptr->offset_table_count >= png_ptr->offset_table_number)
{
#ifndef PNG_USER_MEM_SUPPORTED
if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */
else
png_warning(png_ptr, "Out of Memory.");
#endif
return (NULL);
}
ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++];
}
else
ret = farmalloc(size);
#ifndef PNG_USER_MEM_SUPPORTED
if (ret == NULL)
{
if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */
else
png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */
}
#endif
return (ret);
}
/* free a pointer allocated by png_malloc(). In the default
configuration, png_ptr is not used, but is passed in case it
is needed. If ptr is NULL, return without taking any action. */
void PNGAPI
png_free(png_structp png_ptr, png_voidp ptr)
{
if (png_ptr == NULL || ptr == NULL)
return;
#ifdef PNG_USER_MEM_SUPPORTED
if (png_ptr->free_fn != NULL)
{
(*(png_ptr->free_fn))(png_ptr, ptr);
return;
}
else png_free_default(png_ptr, ptr);
}
void PNGAPI
png_free_default(png_structp png_ptr, png_voidp ptr)
{
#endif /* PNG_USER_MEM_SUPPORTED */
if (png_ptr->offset_table != NULL)
{
int i;
for (i = 0; i < png_ptr->offset_table_count; i++)
{
if (ptr == png_ptr->offset_table_ptr[i])
{
ptr = NULL;
png_ptr->offset_table_count_free++;
break;
}
}
if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
{
farfree(png_ptr->offset_table);
farfree(png_ptr->offset_table_ptr);
png_ptr->offset_table = NULL;
png_ptr->offset_table_ptr = NULL;
}
}
if (ptr != NULL)
{
farfree(ptr);
}
}
#else /* Not the Borland DOS special memory handler */
/* Allocate memory for a png_struct or a png_info. The malloc and
memset can be replaced by a single call to calloc() if this is thought
to improve performance noticably. */
png_voidp /* PRIVATE */
png_create_struct(int type)
{
#ifdef PNG_USER_MEM_SUPPORTED
return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL));
}
/* Allocate memory for a png_struct or a png_info. The malloc and
memset can be replaced by a single call to calloc() if this is thought
to improve performance noticably. */
png_voidp /* PRIVATE */
png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
{
#endif /* PNG_USER_MEM_SUPPORTED */
png_size_t size;
png_voidp struct_ptr;
if (type == PNG_STRUCT_INFO)
size = png_sizeof(png_info);
else if (type == PNG_STRUCT_PNG)
size = png_sizeof(png_struct);
else
return (NULL);
#ifdef PNG_USER_MEM_SUPPORTED
if(malloc_fn != NULL)
{
png_struct dummy_struct;
png_structp png_ptr = &dummy_struct;
png_ptr->mem_ptr=mem_ptr;
struct_ptr = (*(malloc_fn))(png_ptr, size);
if (struct_ptr != NULL)
png_memset(struct_ptr, 0, size);
return (struct_ptr);
}
#endif /* PNG_USER_MEM_SUPPORTED */
#if defined(__TURBOC__) && !defined(__FLAT__)
struct_ptr = (png_voidp)farmalloc(size);
#else
# if defined(_MSC_VER) && defined(MAXSEG_64K)
struct_ptr = (png_voidp)halloc(size,1);
# else
struct_ptr = (png_voidp)malloc(size);
# endif
#endif
if (struct_ptr != NULL)
png_memset(struct_ptr, 0, size);
return (struct_ptr);
}
/* Free memory allocated by a png_create_struct() call */
void /* PRIVATE */
png_destroy_struct(png_voidp struct_ptr)
{
#ifdef PNG_USER_MEM_SUPPORTED
png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL);
}
/* Free memory allocated by a png_create_struct() call */
void /* PRIVATE */
png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
png_voidp mem_ptr)
{
#endif /* PNG_USER_MEM_SUPPORTED */
if (struct_ptr != NULL)
{
#ifdef PNG_USER_MEM_SUPPORTED
if(free_fn != NULL)
{
png_struct dummy_struct;
png_structp png_ptr = &dummy_struct;
png_ptr->mem_ptr=mem_ptr;
(*(free_fn))(png_ptr, struct_ptr);
return;
}
#endif /* PNG_USER_MEM_SUPPORTED */
#if defined(__TURBOC__) && !defined(__FLAT__)
farfree(struct_ptr);
#else
# if defined(_MSC_VER) && defined(MAXSEG_64K)
hfree(struct_ptr);
# else
free(struct_ptr);
# endif
#endif
}
}
/* Allocate memory. For reasonable files, size should never exceed
64K. However, zlib may allocate more then 64K if you don't tell
it not to. See zconf.h and png.h for more information. zlib does
need to allocate exactly 64K, so whatever you call here must
have the ability to do that. */
png_voidp PNGAPI
png_malloc(png_structp png_ptr, png_uint_32 size)
{
png_voidp ret;
#ifdef PNG_USER_MEM_SUPPORTED
if (png_ptr == NULL || size == 0)
return (NULL);
if(png_ptr->malloc_fn != NULL)
ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size));
else
ret = (png_malloc_default(png_ptr, size));
if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr, "Out of Memory!");
return (ret);
}
png_voidp PNGAPI
png_malloc_default(png_structp png_ptr, png_uint_32 size)
{
png_voidp ret;
#endif /* PNG_USER_MEM_SUPPORTED */
if (png_ptr == NULL || size == 0)
return (NULL);
#ifdef PNG_MAX_MALLOC_64K
if (size > (png_uint_32)65536L)
{
#ifndef PNG_USER_MEM_SUPPORTED
if(png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr, "Cannot Allocate > 64K");
else
#endif
return NULL;
}
#endif
/* Check for overflow */
#if defined(__TURBOC__) && !defined(__FLAT__)
if (size != (unsigned long)size)
ret = NULL;
else
ret = farmalloc(size);
#else
# if defined(_MSC_VER) && defined(MAXSEG_64K)
if (size != (unsigned long)size)
ret = NULL;
else
ret = halloc(size, 1);
# else
if (size != (size_t)size)
ret = NULL;
else
ret = malloc((size_t)size);
# endif
#endif
#ifndef PNG_USER_MEM_SUPPORTED
if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
png_error(png_ptr, "Out of Memory");
#endif
return (ret);
}
/* Free a pointer allocated by png_malloc(). If ptr is NULL, return
without taking any action. */
void PNGAPI
png_free(png_structp png_ptr, png_voidp ptr)
{
if (png_ptr == NULL || ptr == NULL)
return;
#ifdef PNG_USER_MEM_SUPPORTED
if (png_ptr->free_fn != NULL)
{
(*(png_ptr->free_fn))(png_ptr, ptr);
return;
}
else png_free_default(png_ptr, ptr);
}
void PNGAPI
png_free_default(png_structp png_ptr, png_voidp ptr)
{
if (png_ptr == NULL || ptr == NULL)
return;
#endif /* PNG_USER_MEM_SUPPORTED */
#if defined(__TURBOC__) && !defined(__FLAT__)
farfree(ptr);
#else
# if defined(_MSC_VER) && defined(MAXSEG_64K)
hfree(ptr);
# else
free(ptr);
# endif
#endif
}
#endif /* Not Borland DOS special memory handler */
#if defined(PNG_1_0_X)
# define png_malloc_warn png_malloc
#else
/* This function was added at libpng version 1.2.3. The png_malloc_warn()
* function will set up png_malloc() to issue a png_warning and return NULL
* instead of issuing a png_error, if it fails to allocate the requested
* memory.
*/
png_voidp PNGAPI
png_malloc_warn(png_structp png_ptr, png_uint_32 size)
{
png_voidp ptr;
png_uint_32 save_flags=png_ptr->flags;
png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
ptr = (png_voidp)png_malloc((png_structp)png_ptr, size);
png_ptr->flags=save_flags;
return(ptr);
}
#endif
png_voidp PNGAPI
png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2,
png_uint_32 length)
{
png_size_t size;
size = (png_size_t)length;
if ((png_uint_32)size != length)
png_error(png_ptr,"Overflow in png_memcpy_check.");
return(png_memcpy (s1, s2, size));
}
png_voidp PNGAPI
png_memset_check (png_structp png_ptr, png_voidp s1, int value,
png_uint_32 length)
{
png_size_t size;
size = (png_size_t)length;
if ((png_uint_32)size != length)
png_error(png_ptr,"Overflow in png_memset_check.");
return (png_memset (s1, value, size));
}
#ifdef PNG_USER_MEM_SUPPORTED
/* This function is called when the application wants to use another method
* of allocating and freeing memory.
*/
void PNGAPI
png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr
malloc_fn, png_free_ptr free_fn)
{
png_ptr->mem_ptr = mem_ptr;
png_ptr->malloc_fn = malloc_fn;
png_ptr->free_fn = free_fn;
}
/* This function returns a pointer to the mem_ptr associated with the user
* functions. The application should free any memory associated with this
* pointer before png_write_destroy and png_read_destroy are called.
*/
png_voidp PNGAPI
png_get_mem_ptr(png_structp png_ptr)
{
return ((png_voidp)png_ptr->mem_ptr);
}
#endif /* PNG_USER_MEM_SUPPORTED */

1573
libpng/pngpread.c Normal file

File diff suppressed because it is too large Load Diff

1456
libpng/pngread.c Normal file

File diff suppressed because it is too large Load Diff

161
libpng/pngrio.c Normal file
View File

@ -0,0 +1,161 @@
/* pngrio.c - functions for data input
*
* libpng 1.2.8 - December 3, 2004
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1998-2004 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This file provides a location for all input. Users who need
* special handling are expected to write a function that has the same
* arguments as this and performs a similar function, but that possibly
* has a different input method. Note that you shouldn't change this
* function, but rather write a replacement function and then make
* libpng use it at run time with png_set_read_fn(...).
*/
#define PNG_INTERNAL
#include "png.h"
/* Read the data from whatever input you are using. The default routine
reads from a file pointer. Note that this routine sometimes gets called
with very small lengths, so you should implement some kind of simple
buffering if you are using unbuffered reads. This should never be asked
to read more then 64K on a 16 bit machine. */
void /* PRIVATE */
png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_debug1(4,"reading %d bytes\n", (int)length);
if (png_ptr->read_data_fn != NULL)
(*(png_ptr->read_data_fn))(png_ptr, data, length);
else
png_error(png_ptr, "Call to NULL read function");
}
#if !defined(PNG_NO_STDIO)
/* This is the function that does the actual reading of data. If you are
not reading from a standard C stream, you should create a replacement
read_data function and use it at run time with png_set_read_fn(), rather
than changing the library. */
#ifndef USE_FAR_KEYWORD
void PNGAPI
png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_size_t check;
/* fread() returns 0 on error, so it is OK to store this in a png_size_t
* instead of an int, which is what fread() actually returns.
*/
#if defined(_WIN32_WCE)
if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
check = 0;
#else
check = (png_size_t)fread(data, (png_size_t)1, length,
(png_FILE_p)png_ptr->io_ptr);
#endif
if (check != length)
png_error(png_ptr, "Read Error");
}
#else
/* this is the model-independent version. Since the standard I/O library
can't handle far buffers in the medium and small models, we have to copy
the data.
*/
#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)
static void /* PRIVATE */
png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
int check;
png_byte *n_data;
png_FILE_p io_ptr;
/* Check if data really is near. If so, use usual code. */
n_data = (png_byte *)CVT_PTR_NOCHECK(data);
io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
if ((png_bytep)n_data == data)
{
#if defined(_WIN32_WCE)
if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
check = 0;
#else
check = fread(n_data, 1, length, io_ptr);
#endif
}
else
{
png_byte buf[NEAR_BUF_SIZE];
png_size_t read, remaining, err;
check = 0;
remaining = length;
do
{
read = MIN(NEAR_BUF_SIZE, remaining);
#if defined(_WIN32_WCE)
if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) )
err = 0;
#else
err = fread(buf, (png_size_t)1, read, io_ptr);
#endif
png_memcpy(data, buf, read); /* copy far buffer to near buffer */
if(err != read)
break;
else
check += err;
data += read;
remaining -= read;
}
while (remaining != 0);
}
if ((png_uint_32)check != (png_uint_32)length)
png_error(png_ptr, "read Error");
}
#endif
#endif
/* This function allows the application to supply a new input function
for libpng if standard C streams aren't being used.
This function takes as its arguments:
png_ptr - pointer to a png input data structure
io_ptr - pointer to user supplied structure containing info about
the input functions. May be NULL.
read_data_fn - pointer to a new input function that takes as its
arguments a pointer to a png_struct, a pointer to
a location where input data can be stored, and a 32-bit
unsigned int that is the number of bytes to be read.
To exit and output any fatal error messages the new write
function should call png_error(png_ptr, "Error msg"). */
void PNGAPI
png_set_read_fn(png_structp png_ptr, png_voidp io_ptr,
png_rw_ptr read_data_fn)
{
png_ptr->io_ptr = io_ptr;
#if !defined(PNG_NO_STDIO)
if (read_data_fn != NULL)
png_ptr->read_data_fn = read_data_fn;
else
png_ptr->read_data_fn = png_default_read_data;
#else
png_ptr->read_data_fn = read_data_fn;
#endif
/* It is an error to write to a read device */
if (png_ptr->write_data_fn != NULL)
{
png_ptr->write_data_fn = NULL;
png_warning(png_ptr,
"It's an error to set both read_data_fn and write_data_fn in the ");
png_warning(png_ptr,
"same structure. Resetting write_data_fn to NULL.");
}
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
png_ptr->output_flush_fn = NULL;
#endif
}

4177
libpng/pngrtran.c Normal file

File diff suppressed because it is too large Load Diff

3124
libpng/pngrutil.c Normal file

File diff suppressed because it is too large Load Diff

1219
libpng/pngset.c Normal file

File diff suppressed because it is too large Load Diff

650
libpng/pngtrans.c Normal file
View File

@ -0,0 +1,650 @@
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
* libpng 1.2.8 - December 3, 2004
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1998-2004 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*/
#define PNG_INTERNAL
#include "png.h"
#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
/* turn on BGR-to-RGB mapping */
void PNGAPI
png_set_bgr(png_structp png_ptr)
{
png_debug(1, "in png_set_bgr\n");
png_ptr->transformations |= PNG_BGR;
}
#endif
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
/* turn on 16 bit byte swapping */
void PNGAPI
png_set_swap(png_structp png_ptr)
{
png_debug(1, "in png_set_swap\n");
if (png_ptr->bit_depth == 16)
png_ptr->transformations |= PNG_SWAP_BYTES;
}
#endif
#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
/* turn on pixel packing */
void PNGAPI
png_set_packing(png_structp png_ptr)
{
png_debug(1, "in png_set_packing\n");
if (png_ptr->bit_depth < 8)
{
png_ptr->transformations |= PNG_PACK;
png_ptr->usr_bit_depth = 8;
}
}
#endif
#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
/* turn on packed pixel swapping */
void PNGAPI
png_set_packswap(png_structp png_ptr)
{
png_debug(1, "in png_set_packswap\n");
if (png_ptr->bit_depth < 8)
png_ptr->transformations |= PNG_PACKSWAP;
}
#endif
#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
void PNGAPI
png_set_shift(png_structp png_ptr, png_color_8p true_bits)
{
png_debug(1, "in png_set_shift\n");
png_ptr->transformations |= PNG_SHIFT;
png_ptr->shift = *true_bits;
}
#endif
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
defined(PNG_WRITE_INTERLACING_SUPPORTED)
int PNGAPI
png_set_interlace_handling(png_structp png_ptr)
{
png_debug(1, "in png_set_interlace handling\n");
if (png_ptr->interlaced)
{
png_ptr->transformations |= PNG_INTERLACE;
return (7);
}
return (1);
}
#endif
#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
/* Add a filler byte on read, or remove a filler or alpha byte on write.
* The filler type has changed in v0.95 to allow future 2-byte fillers
* for 48-bit input data, as well as to avoid problems with some compilers
* that don't like bytes as parameters.
*/
void PNGAPI
png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc)
{
png_debug(1, "in png_set_filler\n");
png_ptr->transformations |= PNG_FILLER;
png_ptr->filler = (png_byte)filler;
if (filler_loc == PNG_FILLER_AFTER)
png_ptr->flags |= PNG_FLAG_FILLER_AFTER;
else
png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;
/* This should probably go in the "do_read_filler" routine.
* I attempted to do that in libpng-1.0.1a but that caused problems
* so I restored it in libpng-1.0.2a
*/
if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
{
png_ptr->usr_channels = 4;
}
/* Also I added this in libpng-1.0.2a (what happens when we expand
* a less-than-8-bit grayscale to GA? */
if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8)
{
png_ptr->usr_channels = 2;
}
}
#if !defined(PNG_1_0_X)
/* Added to libpng-1.2.7 */
void PNGAPI
png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc)
{
png_debug(1, "in png_set_add_alpha\n");
png_set_filler(png_ptr, filler, filler_loc);
png_ptr->transformations |= PNG_ADD_ALPHA;
}
#endif
#endif
#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
void PNGAPI
png_set_swap_alpha(png_structp png_ptr)
{
png_debug(1, "in png_set_swap_alpha\n");
png_ptr->transformations |= PNG_SWAP_ALPHA;
}
#endif
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
void PNGAPI
png_set_invert_alpha(png_structp png_ptr)
{
png_debug(1, "in png_set_invert_alpha\n");
png_ptr->transformations |= PNG_INVERT_ALPHA;
}
#endif
#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
void PNGAPI
png_set_invert_mono(png_structp png_ptr)
{
png_debug(1, "in png_set_invert_mono\n");
png_ptr->transformations |= PNG_INVERT_MONO;
}
/* invert monochrome grayscale data */
void /* PRIVATE */
png_do_invert(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_invert\n");
/* This test removed from libpng version 1.0.13 and 1.2.0:
* if (row_info->bit_depth == 1 &&
*/
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row == NULL || row_info == NULL)
return;
#endif
if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
{
png_bytep rp = row;
png_uint_32 i;
png_uint_32 istop = row_info->rowbytes;
for (i = 0; i < istop; i++)
{
*rp = (png_byte)(~(*rp));
rp++;
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
row_info->bit_depth == 8)
{
png_bytep rp = row;
png_uint_32 i;
png_uint_32 istop = row_info->rowbytes;
for (i = 0; i < istop; i+=2)
{
*rp = (png_byte)(~(*rp));
rp+=2;
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
row_info->bit_depth == 16)
{
png_bytep rp = row;
png_uint_32 i;
png_uint_32 istop = row_info->rowbytes;
for (i = 0; i < istop; i+=4)
{
*rp = (png_byte)(~(*rp));
*(rp+1) = (png_byte)(~(*(rp+1)));
rp+=4;
}
}
}
#endif
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
/* swaps byte order on 16 bit depth images */
void /* PRIVATE */
png_do_swap(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_swap\n");
if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
row_info->bit_depth == 16)
{
png_bytep rp = row;
png_uint_32 i;
png_uint_32 istop= row_info->width * row_info->channels;
for (i = 0; i < istop; i++, rp += 2)
{
png_byte t = *rp;
*rp = *(rp + 1);
*(rp + 1) = t;
}
}
}
#endif
#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
static png_byte onebppswaptable[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
static png_byte twobppswaptable[256] = {
0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,
0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,
0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,
0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,
0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,
0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,
0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,
0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,
0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,
0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,
0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,
0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,
0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,
0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,
0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,
0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,
0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,
0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,
0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,
0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,
0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,
0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,
0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,
0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,
0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,
0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,
0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,
0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
};
static png_byte fourbppswaptable[256] = {
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,
0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,
0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,
0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,
0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
};
/* swaps pixel packing order within bytes */
void /* PRIVATE */
png_do_packswap(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_packswap\n");
if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
row_info->bit_depth < 8)
{
png_bytep rp, end, table;
end = row + row_info->rowbytes;
if (row_info->bit_depth == 1)
table = onebppswaptable;
else if (row_info->bit_depth == 2)
table = twobppswaptable;
else if (row_info->bit_depth == 4)
table = fourbppswaptable;
else
return;
for (rp = row; rp < end; rp++)
*rp = table[*rp];
}
}
#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
/* remove filler or alpha byte(s) */
void /* PRIVATE */
png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags)
{
png_debug(1, "in png_do_strip_filler\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL)
#endif
{
png_bytep sp=row;
png_bytep dp=row;
png_uint_32 row_width=row_info->width;
png_uint_32 i;
if ((row_info->color_type == PNG_COLOR_TYPE_RGB ||
(row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
(flags & PNG_FLAG_STRIP_ALPHA))) &&
row_info->channels == 4)
{
if (row_info->bit_depth == 8)
{
/* This converts from RGBX or RGBA to RGB */
if (flags & PNG_FLAG_FILLER_AFTER)
{
dp+=3; sp+=4;
for (i = 1; i < row_width; i++)
{
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
sp++;
}
}
/* This converts from XRGB or ARGB to RGB */
else
{
for (i = 0; i < row_width; i++)
{
sp++;
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
}
}
row_info->pixel_depth = 24;
row_info->rowbytes = row_width * 3;
}
else /* if (row_info->bit_depth == 16) */
{
if (flags & PNG_FLAG_FILLER_AFTER)
{
/* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */
sp += 8; dp += 6;
for (i = 1; i < row_width; i++)
{
/* This could be (although png_memcpy is probably slower):
png_memcpy(dp, sp, 6);
sp += 8;
dp += 6;
*/
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
sp += 2;
}
}
else
{
/* This converts from XXRRGGBB or AARRGGBB to RRGGBB */
for (i = 0; i < row_width; i++)
{
/* This could be (although png_memcpy is probably slower):
png_memcpy(dp, sp, 6);
sp += 8;
dp += 6;
*/
sp+=2;
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
*dp++ = *sp++;
}
}
row_info->pixel_depth = 48;
row_info->rowbytes = row_width * 6;
}
row_info->channels = 3;
}
else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY ||
(row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
(flags & PNG_FLAG_STRIP_ALPHA))) &&
row_info->channels == 2)
{
if (row_info->bit_depth == 8)
{
/* This converts from GX or GA to G */
if (flags & PNG_FLAG_FILLER_AFTER)
{
for (i = 0; i < row_width; i++)
{
*dp++ = *sp++;
sp++;
}
}
/* This converts from XG or AG to G */
else
{
for (i = 0; i < row_width; i++)
{
sp++;
*dp++ = *sp++;
}
}
row_info->pixel_depth = 8;
row_info->rowbytes = row_width;
}
else /* if (row_info->bit_depth == 16) */
{
if (flags & PNG_FLAG_FILLER_AFTER)
{
/* This converts from GGXX or GGAA to GG */
sp += 4; dp += 2;
for (i = 1; i < row_width; i++)
{
*dp++ = *sp++;
*dp++ = *sp++;
sp += 2;
}
}
else
{
/* This converts from XXGG or AAGG to GG */
for (i = 0; i < row_width; i++)
{
sp += 2;
*dp++ = *sp++;
*dp++ = *sp++;
}
}
row_info->pixel_depth = 16;
row_info->rowbytes = row_width * 2;
}
row_info->channels = 1;
}
if (flags & PNG_FLAG_STRIP_ALPHA)
row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
}
}
#endif
#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
/* swaps red and blue bytes within a pixel */
void /* PRIVATE */
png_do_bgr(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_bgr\n");
if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
(row_info->color_type & PNG_COLOR_MASK_COLOR))
{
png_uint_32 row_width = row_info->width;
if (row_info->bit_depth == 8)
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
{
png_bytep rp;
png_uint_32 i;
for (i = 0, rp = row; i < row_width; i++, rp += 3)
{
png_byte save = *rp;
*rp = *(rp + 2);
*(rp + 2) = save;
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
png_bytep rp;
png_uint_32 i;
for (i = 0, rp = row; i < row_width; i++, rp += 4)
{
png_byte save = *rp;
*rp = *(rp + 2);
*(rp + 2) = save;
}
}
}
else if (row_info->bit_depth == 16)
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
{
png_bytep rp;
png_uint_32 i;
for (i = 0, rp = row; i < row_width; i++, rp += 6)
{
png_byte save = *rp;
*rp = *(rp + 4);
*(rp + 4) = save;
save = *(rp + 1);
*(rp + 1) = *(rp + 5);
*(rp + 5) = save;
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
png_bytep rp;
png_uint_32 i;
for (i = 0, rp = row; i < row_width; i++, rp += 8)
{
png_byte save = *rp;
*rp = *(rp + 4);
*(rp + 4) = save;
save = *(rp + 1);
*(rp + 1) = *(rp + 5);
*(rp + 5) = save;
}
}
}
}
}
#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
defined(PNG_LEGACY_SUPPORTED)
void PNGAPI
png_set_user_transform_info(png_structp png_ptr, png_voidp
user_transform_ptr, int user_transform_depth, int user_transform_channels)
{
png_debug(1, "in png_set_user_transform_info\n");
#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
png_ptr->user_transform_ptr = user_transform_ptr;
png_ptr->user_transform_depth = (png_byte)user_transform_depth;
png_ptr->user_transform_channels = (png_byte)user_transform_channels;
#else
if(user_transform_ptr || user_transform_depth || user_transform_channels)
png_warning(png_ptr,
"This version of libpng does not support user transform info");
#endif
}
#endif
/* This function returns a pointer to the user_transform_ptr associated with
* the user transform functions. The application should free any memory
* associated with this pointer before png_write_destroy and png_read_destroy
* are called.
*/
png_voidp PNGAPI
png_get_user_transform_ptr(png_structp png_ptr)
{
#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
return ((png_voidp)png_ptr->user_transform_ptr);
#else
if(png_ptr)
return (NULL);
return (NULL);
#endif
}

3903
libpng/pngvcrd.c Normal file

File diff suppressed because it is too large Load Diff

228
libpng/pngwio.c Normal file
View File

@ -0,0 +1,228 @@
/* pngwio.c - functions for data output
*
* libpng 1.2.8 - December 3, 2004
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1998-2004 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This file provides a location for all output. Users who need
* special handling are expected to write functions that have the same
* arguments as these and perform similar functions, but that possibly
* use different output methods. Note that you shouldn't change these
* functions, but rather write replacement functions and then change
* them at run time with png_set_write_fn(...).
*/
#define PNG_INTERNAL
#include "png.h"
#ifdef PNG_WRITE_SUPPORTED
/* Write the data to whatever output you are using. The default routine
writes to a file pointer. Note that this routine sometimes gets called
with very small lengths, so you should implement some kind of simple
buffering if you are using unbuffered writes. This should never be asked
to write more than 64K on a 16 bit machine. */
void /* PRIVATE */
png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
if (png_ptr->write_data_fn != NULL )
(*(png_ptr->write_data_fn))(png_ptr, data, length);
else
png_error(png_ptr, "Call to NULL write function");
}
#if !defined(PNG_NO_STDIO)
/* This is the function that does the actual writing of data. If you are
not writing to a standard C stream, you should create a replacement
write_data function and use it at run time with png_set_write_fn(), rather
than changing the library. */
#ifndef USE_FAR_KEYWORD
void PNGAPI
png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_uint_32 check;
#if defined(_WIN32_WCE)
if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
check = 0;
#else
check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));
#endif
if (check != length)
png_error(png_ptr, "Write Error");
}
#else
/* this is the model-independent version. Since the standard I/O library
can't handle far buffers in the medium and small models, we have to copy
the data.
*/
#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)
void PNGAPI
png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_uint_32 check;
png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
png_FILE_p io_ptr;
/* Check if data really is near. If so, use usual code. */
near_data = (png_byte *)CVT_PTR_NOCHECK(data);
io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
if ((png_bytep)near_data == data)
{
#if defined(_WIN32_WCE)
if ( !WriteFile(io_ptr, near_data, length, &check, NULL) )
check = 0;
#else
check = fwrite(near_data, 1, length, io_ptr);
#endif
}
else
{
png_byte buf[NEAR_BUF_SIZE];
png_size_t written, remaining, err;
check = 0;
remaining = length;
do
{
written = MIN(NEAR_BUF_SIZE, remaining);
png_memcpy(buf, data, written); /* copy far buffer to near buffer */
#if defined(_WIN32_WCE)
if ( !WriteFile(io_ptr, buf, written, &err, NULL) )
err = 0;
#else
err = fwrite(buf, 1, written, io_ptr);
#endif
if (err != written)
break;
else
check += err;
data += written;
remaining -= written;
}
while (remaining != 0);
}
if (check != length)
png_error(png_ptr, "Write Error");
}
#endif
#endif
/* This function is called to output any data pending writing (normally
to disk). After png_flush is called, there should be no data pending
writing in any buffers. */
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
void /* PRIVATE */
png_flush(png_structp png_ptr)
{
if (png_ptr->output_flush_fn != NULL)
(*(png_ptr->output_flush_fn))(png_ptr);
}
#if !defined(PNG_NO_STDIO)
void PNGAPI
png_default_flush(png_structp png_ptr)
{
#if !defined(_WIN32_WCE)
png_FILE_p io_ptr;
io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
if (io_ptr != NULL)
fflush(io_ptr);
#endif
}
#endif
#endif
/* This function allows the application to supply new output functions for
libpng if standard C streams aren't being used.
This function takes as its arguments:
png_ptr - pointer to a png output data structure
io_ptr - pointer to user supplied structure containing info about
the output functions. May be NULL.
write_data_fn - pointer to a new output function that takes as its
arguments a pointer to a png_struct, a pointer to
data to be written, and a 32-bit unsigned int that is
the number of bytes to be written. The new write
function should call png_error(png_ptr, "Error msg")
to exit and output any fatal error messages.
flush_data_fn - pointer to a new flush function that takes as its
arguments a pointer to a png_struct. After a call to
the flush function, there should be no data in any buffers
or pending transmission. If the output method doesn't do
any buffering of ouput, a function prototype must still be
supplied although it doesn't have to do anything. If
PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile
time, output_flush_fn will be ignored, although it must be
supplied for compatibility. */
void PNGAPI
png_set_write_fn(png_structp png_ptr, png_voidp io_ptr,
png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
{
png_ptr->io_ptr = io_ptr;
#if !defined(PNG_NO_STDIO)
if (write_data_fn != NULL)
png_ptr->write_data_fn = write_data_fn;
else
png_ptr->write_data_fn = png_default_write_data;
#else
png_ptr->write_data_fn = write_data_fn;
#endif
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
#if !defined(PNG_NO_STDIO)
if (output_flush_fn != NULL)
png_ptr->output_flush_fn = output_flush_fn;
else
png_ptr->output_flush_fn = png_default_flush;
#else
png_ptr->output_flush_fn = output_flush_fn;
#endif
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
/* It is an error to read while writing a png file */
if (png_ptr->read_data_fn != NULL)
{
png_ptr->read_data_fn = NULL;
png_warning(png_ptr,
"Attempted to set both read_data_fn and write_data_fn in");
png_warning(png_ptr,
"the same structure. Resetting read_data_fn to NULL.");
}
}
#if defined(USE_FAR_KEYWORD)
#if defined(_MSC_VER)
void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
{
void *near_ptr;
void FAR *far_ptr;
FP_OFF(near_ptr) = FP_OFF(ptr);
far_ptr = (void FAR *)near_ptr;
if(check != 0)
if(FP_SEG(ptr) != FP_SEG(far_ptr))
png_error(png_ptr,"segment lost in conversion");
return(near_ptr);
}
# else
void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
{
void *near_ptr;
void FAR *far_ptr;
near_ptr = (void FAR *)ptr;
far_ptr = (void FAR *)near_ptr;
if(check != 0)
if(far_ptr != ptr)
png_error(png_ptr,"segment lost in conversion");
return(near_ptr);
}
# endif
# endif
#endif /* PNG_WRITE_SUPPORTED */

1464
libpng/pngwrite.c Normal file

File diff suppressed because it is too large Load Diff

563
libpng/pngwtran.c Normal file
View File

@ -0,0 +1,563 @@
/* pngwtran.c - transforms the data in a row for PNG writers
*
* libpng version 1.2.8 - December 3, 2004
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1998-2004 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*/
#define PNG_INTERNAL
#include "png.h"
#ifdef PNG_WRITE_SUPPORTED
/* Transform the data according to the user's wishes. The order of
* transformations is significant.
*/
void /* PRIVATE */
png_do_write_transformations(png_structp png_ptr)
{
png_debug(1, "in png_do_write_transformations\n");
if (png_ptr == NULL)
return;
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
if (png_ptr->transformations & PNG_USER_TRANSFORM)
if(png_ptr->write_user_transform_fn != NULL)
(*(png_ptr->write_user_transform_fn)) /* user write transform function */
(png_ptr, /* png_ptr */
&(png_ptr->row_info), /* row_info: */
/* png_uint_32 width; width of row */
/* png_uint_32 rowbytes; number of bytes in row */
/* png_byte color_type; color type of pixels */
/* png_byte bit_depth; bit depth of samples */
/* png_byte channels; number of channels (1-4) */
/* png_byte pixel_depth; bits per pixel (depth*channels) */
png_ptr->row_buf + 1); /* start of pixel data for row */
#endif
#if defined(PNG_WRITE_FILLER_SUPPORTED)
if (png_ptr->transformations & PNG_FILLER)
png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
png_ptr->flags);
#endif
#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
if (png_ptr->transformations & PNG_PACKSWAP)
png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
#if defined(PNG_WRITE_PACK_SUPPORTED)
if (png_ptr->transformations & PNG_PACK)
png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
(png_uint_32)png_ptr->bit_depth);
#endif
#if defined(PNG_WRITE_SWAP_SUPPORTED)
if (png_ptr->transformations & PNG_SWAP_BYTES)
png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
#if defined(PNG_WRITE_SHIFT_SUPPORTED)
if (png_ptr->transformations & PNG_SHIFT)
png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
&(png_ptr->shift));
#endif
#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
if (png_ptr->transformations & PNG_INVERT_ALPHA)
png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
if (png_ptr->transformations & PNG_SWAP_ALPHA)
png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
#if defined(PNG_WRITE_BGR_SUPPORTED)
if (png_ptr->transformations & PNG_BGR)
png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
#if defined(PNG_WRITE_INVERT_SUPPORTED)
if (png_ptr->transformations & PNG_INVERT_MONO)
png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
#endif
}
#if defined(PNG_WRITE_PACK_SUPPORTED)
/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
* row_info bit depth should be 8 (one pixel per byte). The channels
* should be 1 (this only happens on grayscale and paletted images).
*/
void /* PRIVATE */
png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
{
png_debug(1, "in png_do_pack\n");
if (row_info->bit_depth == 8 &&
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
row_info->channels == 1)
{
switch ((int)bit_depth)
{
case 1:
{
png_bytep sp, dp;
int mask, v;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
sp = row;
dp = row;
mask = 0x80;
v = 0;
for (i = 0; i < row_width; i++)
{
if (*sp != 0)
v |= mask;
sp++;
if (mask > 1)
mask >>= 1;
else
{
mask = 0x80;
*dp = (png_byte)v;
dp++;
v = 0;
}
}
if (mask != 0x80)
*dp = (png_byte)v;
break;
}
case 2:
{
png_bytep sp, dp;
int shift, v;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
sp = row;
dp = row;
shift = 6;
v = 0;
for (i = 0; i < row_width; i++)
{
png_byte value;
value = (png_byte)(*sp & 0x03);
v |= (value << shift);
if (shift == 0)
{
shift = 6;
*dp = (png_byte)v;
dp++;
v = 0;
}
else
shift -= 2;
sp++;
}
if (shift != 6)
*dp = (png_byte)v;
break;
}
case 4:
{
png_bytep sp, dp;
int shift, v;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
sp = row;
dp = row;
shift = 4;
v = 0;
for (i = 0; i < row_width; i++)
{
png_byte value;
value = (png_byte)(*sp & 0x0f);
v |= (value << shift);
if (shift == 0)
{
shift = 4;
*dp = (png_byte)v;
dp++;
v = 0;
}
else
shift -= 4;
sp++;
}
if (shift != 4)
*dp = (png_byte)v;
break;
}
}
row_info->bit_depth = (png_byte)bit_depth;
row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
row_info->width);
}
}
#endif
#if defined(PNG_WRITE_SHIFT_SUPPORTED)
/* Shift pixel values to take advantage of whole range. Pass the
* true number of bits in bit_depth. The row should be packed
* according to row_info->bit_depth. Thus, if you had a row of
* bit depth 4, but the pixels only had values from 0 to 7, you
* would pass 3 as bit_depth, and this routine would translate the
* data to 0 to 15.
*/
void /* PRIVATE */
png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
{
png_debug(1, "in png_do_shift\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL &&
#else
if (
#endif
row_info->color_type != PNG_COLOR_TYPE_PALETTE)
{
int shift_start[4], shift_dec[4];
int channels = 0;
if (row_info->color_type & PNG_COLOR_MASK_COLOR)
{
shift_start[channels] = row_info->bit_depth - bit_depth->red;
shift_dec[channels] = bit_depth->red;
channels++;
shift_start[channels] = row_info->bit_depth - bit_depth->green;
shift_dec[channels] = bit_depth->green;
channels++;
shift_start[channels] = row_info->bit_depth - bit_depth->blue;
shift_dec[channels] = bit_depth->blue;
channels++;
}
else
{
shift_start[channels] = row_info->bit_depth - bit_depth->gray;
shift_dec[channels] = bit_depth->gray;
channels++;
}
if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
{
shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
shift_dec[channels] = bit_depth->alpha;
channels++;
}
/* with low row depths, could only be grayscale, so one channel */
if (row_info->bit_depth < 8)
{
png_bytep bp = row;
png_uint_32 i;
png_byte mask;
png_uint_32 row_bytes = row_info->rowbytes;
if (bit_depth->gray == 1 && row_info->bit_depth == 2)
mask = 0x55;
else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
mask = 0x11;
else
mask = 0xff;
for (i = 0; i < row_bytes; i++, bp++)
{
png_uint_16 v;
int j;
v = *bp;
*bp = 0;
for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
{
if (j > 0)
*bp |= (png_byte)((v << j) & 0xff);
else
*bp |= (png_byte)((v >> (-j)) & mask);
}
}
}
else if (row_info->bit_depth == 8)
{
png_bytep bp = row;
png_uint_32 i;
png_uint_32 istop = channels * row_info->width;
for (i = 0; i < istop; i++, bp++)
{
png_uint_16 v;
int j;
int c = (int)(i%channels);
v = *bp;
*bp = 0;
for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
{
if (j > 0)
*bp |= (png_byte)((v << j) & 0xff);
else
*bp |= (png_byte)((v >> (-j)) & 0xff);
}
}
}
else
{
png_bytep bp;
png_uint_32 i;
png_uint_32 istop = channels * row_info->width;
for (bp = row, i = 0; i < istop; i++)
{
int c = (int)(i%channels);
png_uint_16 value, v;
int j;
v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
value = 0;
for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
{
if (j > 0)
value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
else
value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
}
*bp++ = (png_byte)(value >> 8);
*bp++ = (png_byte)(value & 0xff);
}
}
}
}
#endif
#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
void /* PRIVATE */
png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_write_swap_alpha\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL)
#endif
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
/* This converts from ARGB to RGBA */
if (row_info->bit_depth == 8)
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
png_byte save = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = save;
}
}
/* This converts from AARRGGBB to RRGGBBAA */
else
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
png_byte save[2];
save[0] = *(sp++);
save[1] = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = save[0];
*(dp++) = save[1];
}
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
/* This converts from AG to GA */
if (row_info->bit_depth == 8)
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
png_byte save = *(sp++);
*(dp++) = *(sp++);
*(dp++) = save;
}
}
/* This converts from AAGG to GGAA */
else
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
png_byte save[2];
save[0] = *(sp++);
save[1] = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = save[0];
*(dp++) = save[1];
}
}
}
}
}
#endif
#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
void /* PRIVATE */
png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_write_invert_alpha\n");
#if defined(PNG_USELESS_TESTS_SUPPORTED)
if (row != NULL && row_info != NULL)
#endif
{
if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
{
/* This inverts the alpha channel in RGBA */
if (row_info->bit_depth == 8)
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = (png_byte)(255 - *(sp++));
}
}
/* This inverts the alpha channel in RRGGBBAA */
else
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = (png_byte)(255 - *(sp++));
*(dp++) = (png_byte)(255 - *(sp++));
}
}
}
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
/* This inverts the alpha channel in GA */
if (row_info->bit_depth == 8)
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
*(dp++) = *(sp++);
*(dp++) = (png_byte)(255 - *(sp++));
}
}
/* This inverts the alpha channel in GGAA */
else
{
png_bytep sp, dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
for (i = 0, sp = dp = row; i < row_width; i++)
{
*(dp++) = *(sp++);
*(dp++) = *(sp++);
*(dp++) = (png_byte)(255 - *(sp++));
*(dp++) = (png_byte)(255 - *(sp++));
}
}
}
}
}
#endif
#if defined(PNG_MNG_FEATURES_SUPPORTED)
/* undoes intrapixel differencing */
void /* PRIVATE */
png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_write_intrapixel\n");
if (
#if defined(PNG_USELESS_TESTS_SUPPORTED)
row != NULL && row_info != NULL &&
#endif
(row_info->color_type & PNG_COLOR_MASK_COLOR))
{
int bytes_per_pixel;
png_uint_32 row_width = row_info->width;
if (row_info->bit_depth == 8)
{
png_bytep rp;
png_uint_32 i;
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
bytes_per_pixel = 3;
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
bytes_per_pixel = 4;
else
return;
for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
{
*(rp) = (png_byte)((*rp - *(rp+1))&0xff);
*(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
}
}
else if (row_info->bit_depth == 16)
{
png_bytep rp;
png_uint_32 i;
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
bytes_per_pixel = 6;
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
bytes_per_pixel = 8;
else
return;
for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
{
png_uint_32 s0 = (*(rp ) << 8) | *(rp+1);
png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3);
png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5);
png_uint_32 red = (png_uint_32)((s0-s1) & 0xffffL);
png_uint_32 blue = (png_uint_32)((s2-s1) & 0xffffL);
*(rp ) = (png_byte)((red >> 8) & 0xff);
*(rp+1) = (png_byte)(red & 0xff);
*(rp+4) = (png_byte)((blue >> 8) & 0xff);
*(rp+5) = (png_byte)(blue & 0xff);
}
}
}
}
#endif /* PNG_MNG_FEATURES_SUPPORTED */
#endif /* PNG_WRITE_SUPPORTED */

2730
libpng/pngwutil.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,463 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 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.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations
below.
When we speak of free software, we are referring to freedom of use,
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 and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, 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 library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete 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 distribute a copy of this License along with the
Library.
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 Library or any portion
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
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 Library, 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 Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you 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.
If distribution of 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 satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be 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.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library 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.
9. 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 Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
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 with
this License.
11. 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 Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library 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 Library.
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.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library 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.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
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 Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
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
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. 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 LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS

View File

@ -0,0 +1,57 @@
# Run configure to generate Makefile from Makefile.in on
# any system supported by GNU autoconf. For all other
# systems, use this file as a template to create a
# working Makefile.
CC = @CC@
CFLAGS = @CFLAGS@ -Wall
LIBS = @LIBS@ -lm
AR = @AR@
RANLIB = @RANLIB@
srcdir=@srcdir@
OBJS = \
src/resample.c.o \
src/resamplesubs.c.o \
src/filterkit.c.o
TARGETS = @TARGETS@
DIRS=tests
all: $(TARGETS)
libresample.a: $(OBJS) Makefile
$(AR) ruv libresample.a $(OBJS)
ranlib libresample.a
tests/testresample: libresample.a $(srcdir)/tests/testresample.c $(DIRS)
$(CC) -o tests/testresample \
$(CFLAGS) $(srcdir)/tests/testresample.c \
libresample.a $(LIBS)
tests/compareresample: libresample.a $(srcdir)/tests/compareresample.c $(DIRS)
$(CC) -o tests/compareresample \
$(CFLAGS) $(srcdir)/tests/compareresample.c \
libresample.a -lsamplerate $(LIBS)
tests/resample-sndfile: libresample.a $(srcdir)/tests/resample-sndfile.c $(DIRS)
$(CC) -o tests/resample-sndfile \
$(CFLAGS) $(srcdir)/tests/resample-sndfile.c \
libresample.a -lsndfile $(LIBS)
$(DIRS):
mkdir $(DIRS)
clean:
rm -f $(TARGETS) $(OBJS)
dist: clean
rm -f Makefile
rm -f config.status config.cache config.log src/config.h
rm -f *~ src/*~ tests/*~ include/*~
$(OBJS): %.c.o: $(srcdir)/%.c Makefile $(srcdir)/include/libresample.h \
$(srcdir)/src/resample_defs.h $(srcdir)/src/filterkit.h $(srcdir)/src/config.h
$(CC) -c $(CFLAGS) $< -o $@

View File

@ -0,0 +1,84 @@
libresample
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
History:
This library is not the highest-quality resampling library
available, nor is it the most flexible, nor is it the
fastest. But it is pretty good in all of these regards, and
it is quite portable. The best resampling library I am aware
of is libsamplerate by Erik de Castro Lopo. It's small, fast,
and very high quality. However, it uses the GPL for its
license (with commercial options available) and I needed
a more free library. So I wrote this library, using
the LGPL resample-1.7 library by Julius Smith as a basis.
Resample-1.7 is a fixed-point resampler, and as a result
has only limited precision. I rewrote it to use single-precision
floating-point arithmetic instead and increased the number
of filter coefficients between time steps significantly.
On modern processors it can resample in real time even
with this extra overhead.
Resample-1.7 was designed to read and write from files, so
I removed all of that code and replaced it with an API that
lets you pass samples in small chunks. It should be easy
to link to resample-1.7 as a library.
Changes in version 0.1.3:
* Fixed two bugs that were causing subtle problems
on Intel x86 processors due to differences in roundoff errors.
* Prefixed most function names with lrs and changed header file
from resample.h to libresample.h, to avoid namespace
collisions with existing programs and libraries.
* Added resample_dup (thanks to Glenn Maynard)
* Argument to resample_get_filter_width takes a const void *
(thanks to Glenn Maynard)
* resample-sndfile clips output to -1...1 (thanks to Glenn Maynard)
Usage notes:
- If the output buffer you pass is too small, resample_process
may not use any input samples because its internal output
buffer is too full to process any more. So do not assume
that it is an error just because no input samples were
consumed. Just keep passing valid output buffers.
- Given a resampling factor f > 1, and a number of input
samples n, the number of output samples should be between
floor(n - f) and ceil(n + f). In other words, if you
resample 1000 samples at a factor of 8, the number of
output samples might be between 7992 and 8008. Do not
assume that it will be exactly 8000. If you need exactly
8000 outputs, pad the input with extra zeros as necessary.
License and warranty:
All of the files in this package are Copyright 2003 by Dominic
Mazzoni <dominic@minorninth.com>. This library was based heavily
on Resample-1.7, Copyright 1994-2002 by Julius O. Smith III
<jos@ccrma.stanford.edu>, all rights reserved.
Permission to use and copy is granted subject to the terms of the
"GNU Lesser General Public License" (LGPL) as published by the
Free Software Foundation; either version 2.1 of the License,
or any later version. In addition, Julius O. Smith III requests
that a copy of any modified files be sent by email to
jos@ccrma.stanford.edu so that he may incorporate them into the
CCRMA version.
This library 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.

1308
libresample-0.1.3/config.guess vendored Normal file

File diff suppressed because it is too large Load Diff

1413
libresample-0.1.3/config.sub vendored Normal file

File diff suppressed because it is too large Load Diff

2937
libresample-0.1.3/configure vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
dnl
dnl libresample configure.in script
dnl
dnl Dominic Mazzoni
dnl
dnl Require autoconf >= 2.13
AC_PREREQ(2.13)
dnl Init autoconf and make sure configure is being called
dnl from the right directory
AC_INIT([src/resample.c])
dnl Checks for programs.
AC_PROG_CC
AC_PROG_RANLIB
AC_PATH_PROG(AR, ar, no)
if [[ $AR = "no" ]] ; then
AC_MSG_ERROR("Could not find ar - needed to create a library");
fi
AC_SUBST(TARGETS)
TARGETS="libresample.a tests/testresample"
AC_CHECK_LIB(sndfile, sf_open, have_libsndfile=yes, have_libsndfile=no)
if [[ $have_libsndfile = "yes" ]] ; then
TARGETS="$TARGETS tests/resample-sndfile"
fi
AC_CHECK_LIB(samplerate, src_simple, have_libsamplerate=yes, have_libsamplerate=no)
if [[ $have_libsamplerate = "yes" ]] ; then
TARGETS="$TARGETS tests/compareresample"
fi
AC_CHECK_HEADERS(inttypes.h)
AC_CONFIG_HEADER(src/config.h:src/configtemplate.h)
AC_OUTPUT([Makefile])
echo ""
if [[ $have_libsamplerate = "yes" ]] ; then
echo "Configured to build tests/resample-sndfile using libsndfile"
echo ""
else
echo "Could not find libsndfile - needed if you want to"
echo "compile tests/resample-sndfile"
echo ""
fi
if [[ $have_libsamplerate = "yes" ]] ; then
echo "Configured to build tests/compareresample to compare against"
echo "Erik de Castro Lopo's libsamplerate library."
echo ""
else
echo "Could not find libsamplerate - only needed if you want to"
echo "compile tests/compareresample to compare their performance."
echo ""
fi
echo "Type 'configure --help' to see options."
echo ""
echo "Type 'make' to build libresample and tests."

View File

@ -0,0 +1,44 @@
/**********************************************************************
resample.h
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
**********************************************************************/
#ifndef LIBRESAMPLE_INCLUDED
#define LIBRESAMPLE_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void *resample_open(int highQuality,
double minFactor,
double maxFactor);
void *resample_dup(const void *handle);
int resample_get_filter_width(const void *handle);
int resample_process(void *handle,
double factor,
float *inBuffer,
int inBufferLen,
int lastFlag,
int *inBufferUsed,
float *outBuffer,
int outBufferLen);
void resample_close(void *handle);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* LIBRESAMPLE_INCLUDED */

View File

@ -0,0 +1,251 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

View File

@ -0,0 +1,7 @@
/* Run configure to generate config.h automatically on any
system supported by GNU autoconf. For all other systems,
use this file as a template to create config.h
*/
#undef HAVE_INTTYPES_H

View File

@ -0,0 +1,215 @@
/**********************************************************************
resamplesubs.c
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
This file provides Kaiser-windowed low-pass filter support,
including a function to create the filter coefficients, and
two functions to apply the filter at a particular point.
**********************************************************************/
/* Definitions */
#include "resample_defs.h"
#include "filterkit.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
/* LpFilter()
*
* reference: "Digital Filters, 2nd edition"
* R.W. Hamming, pp. 178-179
*
* Izero() computes the 0th order modified bessel function of the first kind.
* (Needed to compute Kaiser window).
*
* LpFilter() computes the coeffs of a Kaiser-windowed low pass filter with
* the following characteristics:
*
* c[] = array in which to store computed coeffs
* frq = roll-off frequency of filter
* N = Half the window length in number of coeffs
* Beta = parameter of Kaiser window
* Num = number of coeffs before 1/frq
*
* Beta trades the rejection of the lowpass filter against the transition
* width from passband to stopband. Larger Beta means a slower
* transition and greater stopband rejection. See Rabiner and Gold
* (Theory and Application of DSP) under Kaiser windows for more about
* Beta. The following table from Rabiner and Gold gives some feel
* for the effect of Beta:
*
* All ripples in dB, width of transition band = D*N where N = window length
*
* BETA D PB RIP SB RIP
* 2.120 1.50 +-0.27 -30
* 3.384 2.23 0.0864 -40
* 4.538 2.93 0.0274 -50
* 5.658 3.62 0.00868 -60
* 6.764 4.32 0.00275 -70
* 7.865 5.0 0.000868 -80
* 8.960 5.7 0.000275 -90
* 10.056 6.4 0.000087 -100
*/
#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */
static double Izero(double x)
{
double sum, u, halfx, temp;
int n;
sum = u = n = 1;
halfx = x/2.0;
do {
temp = halfx/(double)n;
n += 1;
temp *= temp;
u *= temp;
sum += u;
} while (u >= IzeroEPSILON*sum);
return(sum);
}
void lrsLpFilter(double c[], int N, double frq, double Beta, int Num)
{
double IBeta, temp, temp1, inm1;
int i;
/* Calculate ideal lowpass filter impulse response coefficients: */
c[0] = 2.0*frq;
for (i=1; i<N; i++) {
temp = PI*(double)i/(double)Num;
c[i] = sin(2.0*temp*frq)/temp; /* Analog sinc function, cutoff = frq */
}
/*
* Calculate and Apply Kaiser window to ideal lowpass filter.
* Note: last window value is IBeta which is NOT zero.
* You're supposed to really truncate the window here, not ramp
* it to zero. This helps reduce the first sidelobe.
*/
IBeta = 1.0/Izero(Beta);
inm1 = 1.0/((double)(N-1));
for (i=1; i<N; i++) {
temp = (double)i * inm1;
temp1 = 1.0 - temp*temp;
temp1 = (temp1<0? 0: temp1); /* make sure it's not negative since
we're taking the square root - this
happens on Pentium 4's due to tiny
roundoff errors */
c[i] *= Izero(Beta*sqrt(temp1)) * IBeta;
}
}
float lrsFilterUp(float Imp[], /* impulse response */
float ImpD[], /* impulse response deltas */
UWORD Nwing, /* len of one wing of filter */
BOOL Interp, /* Interpolate coefs using deltas? */
float *Xp, /* Current sample */
double Ph, /* Phase */
int Inc) /* increment (1 for right wing or -1 for left) */
{
float *Hp, *Hdp = NULL, *End;
double a = 0;
float v, t;
Ph *= Npc; /* Npc is number of values per 1/delta in impulse response */
v = 0.0; /* The output value */
Hp = &Imp[(int)Ph];
End = &Imp[Nwing];
if (Interp) {
Hdp = &ImpD[(int)Ph];
a = Ph - floor(Ph); /* fractional part of Phase */
}
if (Inc == 1) /* If doing right wing... */
{ /* ...drop extra coeff, so when Ph is */
End--; /* 0.5, we don't do too many mult's */
if (Ph == 0) /* If the phase is zero... */
{ /* ...then we've already skipped the */
Hp += Npc; /* first sample, so we must also */
Hdp += Npc; /* skip ahead in Imp[] and ImpD[] */
}
}
if (Interp)
while (Hp < End) {
t = *Hp; /* Get filter coeff */
t += (*Hdp)*a; /* t is now interp'd filter coeff */
Hdp += Npc; /* Filter coeff differences step */
t *= *Xp; /* Mult coeff by input sample */
v += t; /* The filter output */
Hp += Npc; /* Filter coeff step */
Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
}
else
while (Hp < End) {
t = *Hp; /* Get filter coeff */
t *= *Xp; /* Mult coeff by input sample */
v += t; /* The filter output */
Hp += Npc; /* Filter coeff step */
Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
}
return v;
}
float lrsFilterUD(float Imp[], /* impulse response */
float ImpD[], /* impulse response deltas */
UWORD Nwing, /* len of one wing of filter */
BOOL Interp, /* Interpolate coefs using deltas? */
float *Xp, /* Current sample */
double Ph, /* Phase */
int Inc, /* increment (1 for right wing or -1 for left) */
double dhb) /* filter sampling period */
{
float a;
float *Hp, *Hdp, *End;
float v, t;
double Ho;
v = 0.0; /* The output value */
Ho = Ph*dhb;
End = &Imp[Nwing];
if (Inc == 1) /* If doing right wing... */
{ /* ...drop extra coeff, so when Ph is */
End--; /* 0.5, we don't do too many mult's */
if (Ph == 0) /* If the phase is zero... */
Ho += dhb; /* ...then we've already skipped the */
} /* first sample, so we must also */
/* skip ahead in Imp[] and ImpD[] */
if (Interp)
while ((Hp = &Imp[(int)Ho]) < End) {
t = *Hp; /* Get IR sample */
Hdp = &ImpD[(int)Ho]; /* get interp bits from diff table*/
a = Ho - floor(Ho); /* a is logically between 0 and 1 */
t += (*Hdp)*a; /* t is now interp'd filter coeff */
t *= *Xp; /* Mult coeff by input sample */
v += t; /* The filter output */
Ho += dhb; /* IR step */
Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
}
else
while ((Hp = &Imp[(int)Ho]) < End) {
t = *Hp; /* Get IR sample */
t *= *Xp; /* Mult coeff by input sample */
v += t; /* The filter output */
Ho += dhb; /* IR step */
Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
}
return v;
}

View File

@ -0,0 +1,28 @@
/**********************************************************************
resamplesubs.c
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
**********************************************************************/
/* Definitions */
#include "resample_defs.h"
/*
* FilterUp() - Applies a filter to a given sample when up-converting.
* FilterUD() - Applies a filter to a given sample when up- or down-
*/
float lrsFilterUp(float Imp[], float ImpD[], UWORD Nwing, BOOL Interp,
float *Xp, double Ph, int Inc);
float lrsFilterUD(float Imp[], float ImpD[], UWORD Nwing, BOOL Interp,
float *Xp, double Ph, int Inc, double dhb);
void lrsLpFilter(double c[], int N, double frq, double Beta, int Num);

View File

@ -0,0 +1,347 @@
/**********************************************************************
resample.c
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
This is the main source file, implementing all of the API
functions and handling all of the buffering logic.
**********************************************************************/
/* External interface */
#include "../include/libresample.h"
/* Definitions */
#include "resample_defs.h"
#include "filterkit.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
typedef struct {
float *Imp;
float *ImpD;
float LpScl;
UWORD Nmult;
UWORD Nwing;
double minFactor;
double maxFactor;
UWORD XSize;
float *X;
UWORD Xp; /* Current "now"-sample pointer for input */
UWORD Xread; /* Position to put new samples */
UWORD Xoff;
UWORD YSize;
float *Y;
UWORD Yp;
double Time;
} rsdata;
void *resample_dup(const void * handle)
{
const rsdata *cpy = (const rsdata *)handle;
rsdata *hp = (rsdata *)malloc(sizeof(rsdata));
hp->minFactor = cpy->minFactor;
hp->maxFactor = cpy->maxFactor;
hp->Nmult = cpy->Nmult;
hp->LpScl = cpy->LpScl;
hp->Nwing = cpy->Nwing;
hp->Imp = (float *)malloc(hp->Nwing * sizeof(float));
memcpy(hp->Imp, cpy->Imp, hp->Nwing * sizeof(float));
hp->ImpD = (float *)malloc(hp->Nwing * sizeof(float));
memcpy(hp->ImpD, cpy->ImpD, hp->Nwing * sizeof(float));
hp->Xoff = cpy->Xoff;
hp->XSize = cpy->XSize;
hp->X = (float *)malloc((hp->XSize + hp->Xoff) * sizeof(float));
memcpy(hp->X, cpy->X, (hp->XSize + hp->Xoff) * sizeof(float));
hp->Xp = cpy->Xp;
hp->Xread = cpy->Xread;
hp->YSize = cpy->YSize;
hp->Y = (float *)malloc(hp->YSize * sizeof(float));
memcpy(hp->Y, cpy->Y, hp->YSize * sizeof(float));
hp->Yp = cpy->Yp;
hp->Time = cpy->Time;
return (void *)hp;
}
void *resample_open(int highQuality, double minFactor, double maxFactor)
{
double *Imp64;
double Rolloff, Beta;
rsdata *hp;
UWORD Xoff_min, Xoff_max;
int i;
/* Just exit if we get invalid factors */
if (minFactor <= 0.0 || maxFactor <= 0.0 || maxFactor < minFactor) {
#if DEBUG
fprintf(stderr,
"libresample: "
"minFactor and maxFactor must be positive real numbers,\n"
"and maxFactor should be larger than minFactor.\n");
#endif
return 0;
}
hp = (rsdata *)malloc(sizeof(rsdata));
hp->minFactor = minFactor;
hp->maxFactor = maxFactor;
if (highQuality)
hp->Nmult = 35;
else
hp->Nmult = 11;
hp->LpScl = 1.0;
hp->Nwing = Npc*(hp->Nmult-1)/2; /* # of filter coeffs in right wing */
Rolloff = 0.90;
Beta = 6;
Imp64 = (double *)malloc(hp->Nwing * sizeof(double));
lrsLpFilter(Imp64, hp->Nwing, 0.5*Rolloff, Beta, Npc);
hp->Imp = (float *)malloc(hp->Nwing * sizeof(float));
hp->ImpD = (float *)malloc(hp->Nwing * sizeof(float));
for(i=0; i<hp->Nwing; i++)
hp->Imp[i] = Imp64[i];
/* Storing deltas in ImpD makes linear interpolation
of the filter coefficients faster */
for (i=0; i<hp->Nwing-1; i++)
hp->ImpD[i] = hp->Imp[i+1] - hp->Imp[i];
/* Last coeff. not interpolated */
hp->ImpD[hp->Nwing-1] = - hp->Imp[hp->Nwing-1];
free(Imp64);
/* Calc reach of LP filter wing (plus some creeping room) */
Xoff_min = ((hp->Nmult+1)/2.0) * MAX(1.0, 1.0/minFactor) + 10;
Xoff_max = ((hp->Nmult+1)/2.0) * MAX(1.0, 1.0/maxFactor) + 10;
hp->Xoff = MAX(Xoff_min, Xoff_max);
/* Make the inBuffer size at least 4096, but larger if necessary
in order to store the minimum reach of the LP filter and then some.
Then allocate the buffer an extra Xoff larger so that
we can zero-pad up to Xoff zeros at the end when we reach the
end of the input samples. */
hp->XSize = MAX(2*hp->Xoff+10, 4096);
hp->X = (float *)malloc((hp->XSize + hp->Xoff) * sizeof(float));
hp->Xp = hp->Xoff;
hp->Xread = hp->Xoff;
/* Need Xoff zeros at begining of X buffer */
for(i=0; i<hp->Xoff; i++)
hp->X[i]=0;
/* Make the outBuffer long enough to hold the entire processed
output of one inBuffer */
hp->YSize = (int)(((double)hp->XSize)*maxFactor+2.0);
hp->Y = (float *)malloc(hp->YSize * sizeof(float));
hp->Yp = 0;
hp->Time = (double)hp->Xoff; /* Current-time pointer for converter */
return (void *)hp;
}
int resample_get_filter_width(const void *handle)
{
const rsdata *hp = (const rsdata *)handle;
return hp->Xoff;
}
int resample_process(void *handle,
double factor,
float *inBuffer,
int inBufferLen,
int lastFlag,
int *inBufferUsed, /* output param */
float *outBuffer,
int outBufferLen)
{
rsdata *hp = (rsdata *)handle;
float *Imp = hp->Imp;
float *ImpD = hp->ImpD;
float LpScl = hp->LpScl;
UWORD Nwing = hp->Nwing;
BOOL interpFilt = FALSE; /* TRUE means interpolate filter coeffs */
int outSampleCount;
UWORD Nout, Ncreep, Nreuse;
int Nx;
int i, len;
#if DEBUG
fprintf(stderr, "resample_process: in=%d, out=%d lastFlag=%d\n",
inBufferLen, outBufferLen, lastFlag);
#endif
/* Initialize inBufferUsed and outSampleCount to 0 */
*inBufferUsed = 0;
outSampleCount = 0;
if (factor < hp->minFactor || factor > hp->maxFactor) {
#if DEBUG
fprintf(stderr,
"libresample: factor %f is not between "
"minFactor=%f and maxFactor=%f",
factor, hp->minFactor, hp->maxFactor);
#endif
return -1;
}
/* Start by copying any samples still in the Y buffer to the output
buffer */
if (hp->Yp && (outBufferLen-outSampleCount)>0) {
len = MIN(outBufferLen-outSampleCount, hp->Yp);
for(i=0; i<len; i++)
outBuffer[outSampleCount+i] = hp->Y[i];
outSampleCount += len;
for(i=0; i<hp->Yp-len; i++)
hp->Y[i] = hp->Y[i+len];
hp->Yp -= len;
}
/* If there are still output samples left, return now - we need
the full output buffer available to us... */
if (hp->Yp)
return outSampleCount;
/* Account for increased filter gain when using factors less than 1 */
if (factor < 1)
LpScl = LpScl*factor;
for(;;) {
/* This is the maximum number of samples we can process
per loop iteration */
#ifdef DEBUG
printf("XSize: %d Xoff: %d Xread: %d Xp: %d lastFlag: %d\n",
hp->XSize, hp->Xoff, hp->Xread, hp->Xp, lastFlag);
#endif
/* Copy as many samples as we can from the input buffer into X */
len = hp->XSize - hp->Xread;
if (len >= (inBufferLen - (*inBufferUsed)))
len = (inBufferLen - (*inBufferUsed));
for(i=0; i<len; i++)
hp->X[hp->Xread + i] = inBuffer[(*inBufferUsed) + i];
*inBufferUsed += len;
hp->Xread += len;
if (lastFlag && (*inBufferUsed == inBufferLen)) {
/* If these are the last samples, zero-pad the
end of the input buffer and make sure we process
all the way to the end */
Nx = hp->Xread - hp->Xoff;
for(i=0; i<hp->Xoff; i++)
hp->X[hp->Xread + i] = 0;
}
else
Nx = hp->Xread - 2 * hp->Xoff;
#ifdef DEBUG
fprintf(stderr, "new len=%d Nx=%d\n", len, Nx);
#endif
if (Nx <= 0)
break;
/* Resample stuff in input buffer */
if (factor >= 1) { /* SrcUp() is faster if we can use it */
Nout = lrsSrcUp(hp->X, hp->Y, factor, &hp->Time, Nx,
Nwing, LpScl, Imp, ImpD, interpFilt);
}
else {
Nout = lrsSrcUD(hp->X, hp->Y, factor, &hp->Time, Nx,
Nwing, LpScl, Imp, ImpD, interpFilt);
}
#ifdef DEBUG
printf("Nout: %d\n", Nout);
#endif
hp->Time -= Nx; /* Move converter Nx samples back in time */
hp->Xp += Nx; /* Advance by number of samples processed */
/* Calc time accumulation in Time */
Ncreep = (int)(hp->Time) - hp->Xoff;
if (Ncreep) {
hp->Time -= Ncreep; /* Remove time accumulation */
hp->Xp += Ncreep; /* and add it to read pointer */
}
/* Copy part of input signal that must be re-used */
Nreuse = hp->Xread - (hp->Xp - hp->Xoff);
for (i=0; i<Nreuse; i++)
hp->X[i] = hp->X[i + (hp->Xp - hp->Xoff)];
#ifdef DEBUG
printf("New Xread=%d\n", Nreuse);
#endif
hp->Xread = Nreuse; /* Pos in input buff to read new data into */
hp->Xp = hp->Xoff;
/* Check to see if output buff overflowed (shouldn't happen!) */
if (Nout > hp->YSize) {
#ifdef DEBUG
printf("Nout: %d YSize: %d\n", Nout, hp->YSize);
#endif
fprintf(stderr, "libresample: Output array overflow!\n");
return -1;
}
hp->Yp = Nout;
/* Copy as many samples as possible to the output buffer */
if (hp->Yp && (outBufferLen-outSampleCount)>0) {
len = MIN(outBufferLen-outSampleCount, hp->Yp);
for(i=0; i<len; i++)
outBuffer[outSampleCount+i] = hp->Y[i];
outSampleCount += len;
for(i=0; i<hp->Yp-len; i++)
hp->Y[i] = hp->Y[i+len];
hp->Yp -= len;
}
/* If there are still output samples left, return now,
since we need the full output buffer available */
if (hp->Yp)
break;
}
return outSampleCount;
}
void resample_close(void *handle)
{
rsdata *hp = (rsdata *)handle;
free(hp->X);
free(hp->Y);
free(hp->Imp);
free(hp->ImpD);
free(hp);
}

View File

@ -0,0 +1,86 @@
/**********************************************************************
resample_defs.h
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
**********************************************************************/
#ifndef __RESAMPLE_DEFS__
#define __RESAMPLE_DEFS__
#if !defined(WIN32) && !defined(__CYGWIN__)
#include "config.h"
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef PI
#define PI (3.14159265358979232846)
#endif
#ifndef PI2
#define PI2 (6.28318530717958465692)
#endif
#define D2R (0.01745329348) /* (2*pi)/360 */
#define R2D (57.29577951) /* 360/(2*pi) */
#ifndef MAX
#define MAX(x,y) ((x)>(y) ?(x):(y))
#endif
#ifndef MIN
#define MIN(x,y) ((x)<(y) ?(x):(y))
#endif
#ifndef ABS
#define ABS(x) ((x)<0 ?(-(x)):(x))
#endif
#ifndef SGN
#define SGN(x) ((x)<0 ?(-1):((x)==0?(0):(1)))
#endif
#if HAVE_INTTYPES_H
#include <inttypes.h>
typedef char BOOL;
typedef int32_t WORD;
typedef uint32_t UWORD;
#else
typedef char BOOL;
typedef int WORD;
typedef unsigned int UWORD;
#endif
#ifdef DEBUG
#define INLINE
#else
#define INLINE inline
#endif
/* Accuracy */
#define Npc 4096
/* Function prototypes */
int lrsSrcUp(float X[], float Y[], double factor, double *Time,
UWORD Nx, UWORD Nwing, float LpScl,
float Imp[], float ImpD[], BOOL Interp);
int lrsSrcUD(float X[], float Y[], double factor, double *Time,
UWORD Nx, UWORD Nwing, float LpScl,
float Imp[], float ImpD[], BOOL Interp);
#endif

View File

@ -0,0 +1,123 @@
/**********************************************************************
resamplesubs.c
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
This file provides the routines that do sample-rate conversion
on small arrays, calling routines from filterkit.
**********************************************************************/
/* Definitions */
#include "resample_defs.h"
#include "filterkit.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
/* Sampling rate up-conversion only subroutine;
* Slightly faster than down-conversion;
*/
int lrsSrcUp(float X[],
float Y[],
double factor,
double *TimePtr,
UWORD Nx,
UWORD Nwing,
float LpScl,
float Imp[],
float ImpD[],
BOOL Interp)
{
float *Xp, *Ystart;
float v;
double CurrentTime = *TimePtr;
double dt; /* Step through input signal */
double endTime; /* When Time reaches EndTime, return to user */
dt = 1.0/factor; /* Output sampling period */
Ystart = Y;
endTime = CurrentTime + Nx;
while (CurrentTime < endTime)
{
double LeftPhase = CurrentTime-floor(CurrentTime);
double RightPhase = 1.0 - LeftPhase;
Xp = &X[(int)CurrentTime]; /* Ptr to current input sample */
/* Perform left-wing inner product */
v = lrsFilterUp(Imp, ImpD, Nwing, Interp, Xp,
LeftPhase, -1);
/* Perform right-wing inner product */
v += lrsFilterUp(Imp, ImpD, Nwing, Interp, Xp+1,
RightPhase, 1);
v *= LpScl; /* Normalize for unity filter gain */
*Y++ = v; /* Deposit output */
CurrentTime += dt; /* Move to next sample by time increment */
}
*TimePtr = CurrentTime;
return (Y - Ystart); /* Return the number of output samples */
}
/* Sampling rate conversion subroutine */
int lrsSrcUD(float X[],
float Y[],
double factor,
double *TimePtr,
UWORD Nx,
UWORD Nwing,
float LpScl,
float Imp[],
float ImpD[],
BOOL Interp)
{
float *Xp, *Ystart;
float v;
double CurrentTime = (*TimePtr);
double dh; /* Step through filter impulse response */
double dt; /* Step through input signal */
double endTime; /* When Time reaches EndTime, return to user */
dt = 1.0/factor; /* Output sampling period */
dh = MIN(Npc, factor*Npc); /* Filter sampling period */
Ystart = Y;
endTime = CurrentTime + Nx;
while (CurrentTime < endTime)
{
double LeftPhase = CurrentTime-floor(CurrentTime);
double RightPhase = 1.0 - LeftPhase;
Xp = &X[(int)CurrentTime]; /* Ptr to current input sample */
/* Perform left-wing inner product */
v = lrsFilterUD(Imp, ImpD, Nwing, Interp, Xp,
LeftPhase, -1, dh);
/* Perform right-wing inner product */
v += lrsFilterUD(Imp, ImpD, Nwing, Interp, Xp+1,
RightPhase, 1, dh);
v *= LpScl; /* Normalize for unity filter gain */
*Y++ = v; /* Deposit output */
CurrentTime += dt; /* Move to next sample by time increment */
}
*TimePtr = CurrentTime;
return (Y - Ystart); /* Return the number of output samples */
}

View File

@ -0,0 +1,183 @@
/**********************************************************************
compareresample.c
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
**********************************************************************/
#include "../include/libresample.h"
#include <samplerate.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#define MIN(A, B) (A) < (B)? (A) : (B)
void dostat(char *name, float *d1, float *d2, int len)
{
int i;
double sum, sumsq, err, rmserr;
sum = 0.0;
sumsq = 0.0;
for(i=0; i<len; i++) {
double diff = d1[i] - d2[i];
sum += fabs(diff);
sumsq += diff * diff;
}
err = sum / len;
rmserr = sqrt(sumsq / len);
printf(" %s: Avg err: %f RMS err: %f\n", name, err, rmserr);
}
void runtest(float *src, int srclen,
float *ans, int anslen,
double factor)
{
struct timeval tv0, tv1;
int dstlen = (int)(srclen * factor);
float *dst_rs = (float *)malloc((dstlen+100) * sizeof(float));
float *dst_rabbit = (float *)malloc((dstlen+100) * sizeof(float));
void *handle;
SRC_DATA rabbit;
double deltat;
int srcblocksize = srclen;
int dstblocksize = dstlen;
int i, out, out_rabbit, o, srcused;
int statlen, srcpos;
/* do resample */
for(i=0; i<dstlen+100; i++)
dst_rs[i] = -99.0;
gettimeofday(&tv0, NULL);
handle = resample_open(1, factor, factor);
out = 0;
srcpos = 0;
for(;;) {
int srcBlock = MIN(srclen-srcpos, srcblocksize);
int lastFlag = (srcBlock == srclen-srcpos);
o = resample_process(handle, factor,
&src[srcpos], srcBlock,
lastFlag, &srcused,
&dst_rs[out], MIN(dstlen-out, dstblocksize));
srcpos += srcused;
if (o >= 0)
out += o;
if (o < 0 || (o == 0 && srcpos == srclen))
break;
}
resample_close(handle);
gettimeofday(&tv1, NULL);
deltat =
(tv1.tv_sec + tv1.tv_usec * 0.000001) -
(tv0.tv_sec + tv0.tv_usec * 0.000001);
if (o < 0) {
printf("Error: resample_process returned an error: %d\n", o);
}
if (out <= 0) {
printf("Error: resample_process returned %d samples\n", out);
free(dst_rs);
return;
}
printf(" resample: %.3f seconds, %d outputs\n", deltat, out);
/* do rabbit (Erik's libsamplerate) */
for(i=0; i<dstlen+100; i++)
dst_rabbit[i] = -99.0;
rabbit.data_in = src;
rabbit.data_out = dst_rabbit;
rabbit.input_frames = srclen;
rabbit.output_frames = dstlen;
rabbit.input_frames_used = 0;
rabbit.output_frames_gen = 0;
rabbit.end_of_input = 1;
rabbit.src_ratio = factor;
gettimeofday(&tv0, NULL);
/* src_simple(&rabbit, SRC_SINC_BEST_QUALITY, 1); */
src_simple(&rabbit, SRC_SINC_FASTEST, 1);
/* src_simple(&rabbit, SRC_LINEAR, 1); */
gettimeofday(&tv1, NULL);
deltat =
(tv1.tv_sec + tv1.tv_usec * 0.000001) -
(tv0.tv_sec + tv0.tv_usec * 0.000001);
out_rabbit = rabbit.output_frames_gen;
printf(" rabbit : %.3f seconds, %d outputs\n",
deltat, out_rabbit);
statlen = MIN(out, out_rabbit);
if (anslen > 0)
statlen = MIN(statlen, anslen);
if (ans) {
dostat("resample ", dst_rs, ans, statlen);
dostat("rabbit ", dst_rabbit, ans, statlen);
}
dostat( "RS vs rabbit", dst_rs, dst_rabbit, statlen);
free(dst_rs);
free(dst_rabbit);
}
int main(int argc, char **argv)
{
int i, srclen;
float *src, *ans;
printf("\n*** sin wave, factor = 1.0 *** \n\n");
srclen = 100000;
src = malloc(srclen * sizeof(float));
for(i=0; i<srclen; i++)
src[i] = sin(i/100.0);
runtest(src, srclen, src, srclen, 1.0);
printf("\n*** sin wave, factor = 0.25 *** \n\n");
srclen = 100000;
for(i=0; i<srclen; i++)
src[i] = sin(i/100.0);
ans = malloc((srclen/4) * sizeof(float));
for(i=0; i<srclen/4; i++)
ans[i] = sin(i/25.0);
runtest(src, srclen, ans, srclen/4, 0.25);
free(ans);
printf("\n*** sin wave, factor = 4.0 *** \n\n");
srclen = 20000;
for(i=0; i<srclen; i++)
src[i] = sin(i/100.0);
ans = malloc((srclen*4) * sizeof(float));
for(i=0; i<srclen*4; i++)
ans[i] = sin(i/400.0);
runtest(src, srclen, ans, srclen*4, 4.0);
free(ans);
free(src);
return 0;
}

View File

@ -0,0 +1,213 @@
/**********************************************************************
resample-sndfile.c
Written by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
**********************************************************************/
#include "../include/libresample.h"
#include <sndfile.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/time.h>
#define MIN(A, B) (A) < (B)? (A) : (B)
void usage(char *progname)
{
fprintf(stderr, "Usage: %s -by <ratio> <input> <output>\n", progname);
fprintf(stderr, " %s -to <rate> <input> <output>\n", progname);
fprintf(stderr, "\n");
exit(-1);
}
int main(int argc, char **argv)
{
SNDFILE *srcfile, *dstfile;
SF_INFO srcinfo, dstinfo;
SF_FORMAT_INFO formatinfo;
char *extension;
void **handle;
int channels;
int srclen, dstlen;
float *src, *srci;
float *dst, *dsti;
double ratio = 0.0;
double srcrate;
double dstrate = 0.0;
struct timeval tv0, tv1;
double deltat;
int numformats;
int pos, bufferpos, outcount;
int i, c;
if (argc != 5)
usage(argv[0]);
if (!strcmp(argv[1], "-by")) {
ratio = atof(argv[2]);
if (ratio <= 0.0) {
fprintf(stderr, "Ratio of %f is illegal\n", ratio);
usage(argv[0]);
}
}
else if (!strcmp(argv[1], "-to")) {
dstrate = atof(argv[2]);
if (dstrate < 10.0 || dstrate > 100000.0) {
fprintf(stderr, "Sample rate of %f is illegal\n", dstrate);
usage(argv[0]);
}
}
else
usage(argv[0]);
memset(&srcinfo, 0, sizeof(srcinfo));
memset(&dstinfo, 0, sizeof(dstinfo));
srcfile = sf_open(argv[3], SFM_READ, &srcinfo);
if (!srcfile) {
fprintf(stderr, "%s", sf_strerror(NULL));
exit(-1);
}
srcrate = srcinfo.samplerate;
if (dstrate == 0.0)
dstrate = srcrate * ratio;
else
ratio = dstrate / srcrate;
channels = srcinfo.channels;
/* figure out format of destination file */
extension = strstr(argv[4], ".");
if (extension) {
extension++;
sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT,
&numformats, sizeof(numformats));
for(i=0; i<numformats; i++) {
memset(&formatinfo, 0, sizeof(formatinfo));
formatinfo.format = i;
sf_command(NULL, SFC_GET_FORMAT_MAJOR,
&formatinfo, sizeof(formatinfo));
if (!strcmp(formatinfo.extension, extension)) {
printf("Using %s for output format.\n", formatinfo.name);
dstinfo.format = formatinfo.format |
(srcinfo.format & SF_FORMAT_SUBMASK);
break;
}
}
}
if (!dstinfo.format) {
if (extension)
printf("Warning: output format (%s) not recognized, "
"using same as input format.\n",
extension);
dstinfo.format = srcinfo.format;
}
dstinfo.samplerate = (int)(dstrate + 0.5);
dstinfo.channels = channels;
dstfile = sf_open(argv[4], SFM_WRITE, &dstinfo);
if (!dstfile) {
fprintf(stderr, "%s", sf_strerror(NULL));
exit(-1);
}
printf("Source: %s (%d frames, %.2f Hz)\n",
argv[3], (int)srcinfo.frames, srcrate);
printf("Destination: %s (%.2f Hz, ratio=%.5f)\n", argv[4],
dstrate, ratio);
srclen = 4096;
dstlen = (srclen * ratio + 1000);
srci = (float *)malloc(srclen * channels * sizeof(float));
dsti = (float *)malloc(dstlen * channels * sizeof(float));
src = (float *)malloc(srclen * sizeof(float));
dst = (float *)malloc(dstlen * sizeof(float));
handle = (void **)malloc(channels * sizeof(void *));
for(c=0; c<channels; c++)
handle[c] = resample_open(1, ratio, ratio);
gettimeofday(&tv0, NULL);
pos = 0;
bufferpos = 0;
outcount = 0;
while(pos < srcinfo.frames) {
int block = MIN(srclen-bufferpos, srcinfo.frames-pos);
int lastFlag = (pos+block == srcinfo.frames);
int inUsed, inUsed2=0, out=0, out2=0;
sf_readf_float(srcfile, &srci[bufferpos*channels], block);
block += bufferpos;
for(c=0; c<channels; c++) {
for(i=0; i<block; i++)
src[i] = srci[i*channels+c];
inUsed = 0;
out = resample_process(handle[c], ratio, src, block, lastFlag,
&inUsed, dst, dstlen);
if (c==0) {
inUsed2 = inUsed;
out2 = out;
}
else {
if (inUsed2 != inUsed || out2 != out) {
fprintf(stderr, "Fatal error: channels out of sync!\n");
exit(-1);
}
}
for(i=0; i<out; i++)
{
if(dst[i] <= -1)
dsti[i*channels+c] = -1;
else if(dst[i] >= 1)
dsti[i*channels+c] = 1;
else
dsti[i*channels+c] = dst[i];
}
}
sf_writef_float(dstfile, dsti, out);
bufferpos = block - inUsed;
for(i=0; i<bufferpos*channels; i++)
srci[i] = srci[i+(inUsed*channels)];
pos += inUsed;
outcount += out;
}
sf_close(srcfile);
sf_close(dstfile);
gettimeofday(&tv1, NULL);
deltat =
(tv1.tv_sec + tv1.tv_usec * 0.000001) -
(tv0.tv_sec + tv0.tv_usec * 0.000001);
printf("Elapsed time: %.3f seconds\n", deltat);
printf("%d frames written to output file\n", outcount);
free(src);
free(srci);
free(dst);
free(dsti);
exit(0);
}

View File

@ -0,0 +1,182 @@
/**********************************************************************
testresample.c
Real-time library interface by Dominic Mazzoni
Based on resample-1.7:
http://www-ccrma.stanford.edu/~jos/resample/
License: LGPL - see the file LICENSE.txt for more information
**********************************************************************/
#include "../include/libresample.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MIN(A, B) (A) < (B)? (A) : (B)
void runtest(int srclen, double freq, double factor,
int srcblocksize, int dstblocksize)
{
int expectedlen = (int)(srclen * factor);
int dstlen = expectedlen + 1000;
float *src = (float *)malloc((srclen+100) * sizeof(float));
float *dst = (float *)malloc((dstlen+100) * sizeof(float));
void *handle;
double sum, sumsq, err, rmserr;
int i, out, o, srcused, errcount, rangecount;
int statlen, srcpos, lendiff;
int fwidth;
printf("-- srclen: %d sin freq: %.1f factor: %.3f srcblk: %d dstblk: %d\n",
srclen, freq, factor, srcblocksize, dstblocksize);
for(i=0; i<srclen; i++)
src[i] = sin(i/freq);
for(i=srclen; i<srclen+100; i++)
src[i] = -99.0;
for(i=0; i<dstlen+100; i++)
dst[i] = -99.0;
handle = resample_open(1, factor, factor);
fwidth = resample_get_filter_width(handle);
out = 0;
srcpos = 0;
for(;;) {
int srcBlock = MIN(srclen-srcpos, srcblocksize);
int lastFlag = (srcBlock == srclen-srcpos);
o = resample_process(handle, factor,
&src[srcpos], srcBlock,
lastFlag, &srcused,
&dst[out], MIN(dstlen-out, dstblocksize));
srcpos += srcused;
if (o >= 0)
out += o;
if (o < 0 || (o == 0 && srcpos == srclen))
break;
}
resample_close(handle);
if (o < 0) {
printf("Error: resample_process returned an error: %d\n", o);
}
if (out <= 0) {
printf("Error: resample_process returned %d samples\n", out);
free(src);
free(dst);
return;
}
lendiff = abs(out - expectedlen);
if (lendiff > (int)(2*factor + 1.0)) {
printf(" Expected ~%d, got %d samples out\n",
expectedlen, out);
}
sum = 0.0;
sumsq = 0.0;
errcount = 0.0;
/* Don't compute statistics on all output values; the last few
are guaranteed to be off because it's based on far less
interpolation. */
statlen = out - fwidth;
for(i=0; i<statlen; i++) {
double diff = sin((i/freq)/factor) - dst[i];
if (fabs(diff) > 0.05) {
if (errcount == 0)
printf(" First error at i=%d: expected %.3f, got %.3f\n",
i, sin((i/freq)/factor), dst[i]);
errcount++;
}
sum += fabs(diff);
sumsq += diff * diff;
}
rangecount = 0;
for(i=0; i<statlen; i++) {
if (dst[i] < -1.01 || dst[i] > 1.01) {
if (rangecount == 0)
printf(" Error at i=%d: value is %.3f\n", i, dst[i]);
rangecount++;
}
}
if (rangecount > 1)
printf(" At least %d samples were out of range\n", rangecount);
if (errcount > 0) {
i = out - 1;
printf(" i=%d: expected %.3f, got %.3f\n",
i, sin((i/freq)/factor), dst[i]);
printf(" At least %d samples had significant error.\n", errcount);
}
err = sum / statlen;
rmserr = sqrt(sumsq / statlen);
printf(" Out: %d samples Avg err: %f RMS err: %f\n", out, err, rmserr);
free(src);
free(dst);
}
int main(int argc, char **argv)
{
int i, srclen, dstlen, ifreq;
double factor;
printf("\n*** Vary source block size*** \n\n");
srclen = 10000;
ifreq = 100;
for(i=0; i<20; i++) {
factor = ((rand() % 16) + 1) / 4.0;
dstlen = (int)(srclen * factor + 10);
runtest(srclen, (double)ifreq, factor, 64, dstlen);
runtest(srclen, (double)ifreq, factor, 32, dstlen);
runtest(srclen, (double)ifreq, factor, 8, dstlen);
runtest(srclen, (double)ifreq, factor, 2, dstlen);
runtest(srclen, (double)ifreq, factor, srclen, dstlen);
}
printf("\n*** Vary dest block size ***\n\n");
srclen = 10000;
ifreq = 100;
for(i=0; i<20; i++) {
factor = ((rand() % 16) + 1) / 4.0;
runtest(srclen, (double)ifreq, factor, srclen, 32);
dstlen = (int)(srclen * factor + 10);
runtest(srclen, (double)ifreq, factor, srclen, dstlen);
}
printf("\n*** Resample factor 1.0, testing different srclen ***\n\n");
ifreq = 40;
for(i=0; i<100; i++) {
srclen = (rand() % 30000) + 10;
dstlen = (int)(srclen + 10);
runtest(srclen, (double)ifreq, 1.0, srclen, dstlen);
}
printf("\n*** Resample factor 1.0, testing different sin freq ***\n\n");
srclen = 10000;
for(i=0; i<100; i++) {
ifreq = ((int)rand() % 10000) + 1;
dstlen = (int)(srclen * 10);
runtest(srclen, (double)ifreq, 1.0, srclen, dstlen);
}
printf("\n*** Resample with different factors ***\n\n");
srclen = 10000;
ifreq = 100;
for(i=0; i<100; i++) {
factor = ((rand() % 64) + 1) / 4.0;
dstlen = (int)(srclen * factor + 10);
runtest(srclen, (double)ifreq, factor, srclen, dstlen);
}
return 0;
}

View File

@ -0,0 +1,116 @@
# Microsoft Developer Studio Project File - Name="libresample" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=libresample - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libresample.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libresample.mak" CFG="libresample - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libresample - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "libresample - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "libresample - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"libresample.lib"
!ELSEIF "$(CFG)" == "libresample - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"libresampled.lib"
!ENDIF
# Begin Target
# Name "libresample - Win32 Release"
# Name "libresample - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\src\filterkit.c
# End Source File
# Begin Source File
SOURCE=..\src\resample.c
# End Source File
# Begin Source File
SOURCE=..\src\resamplesubs.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\src\filterkit.h
# End Source File
# Begin Source File
SOURCE=..\include\libresample.h
# End Source File
# Begin Source File
SOURCE=..\src\resample_defs.h
# End Source File
# End Group
# End Target
# End Project

20
res/DevInfo.txt Normal file
View File

@ -0,0 +1,20 @@
Developer Information File:
- Don't use the global optimization switch (/Og) because it causes a black screen in Metroid Prime.
- Project Configurations:
- Debug: Debug ON | Optimizations OFF | UPX OFF
- Release: Debug OFF | Optimizations OFF | UPX OFF
- Optimized: Debug OFF | Optimizations ON | UPX ON
Software Used:
OPTIONAL UPX 1.25 +/-
NEEDED nasm 0.98.39 +/-
INCLUDED zlib 1.2.3 +/-
INCLUDED libpng 1.2.8 +/-
NEEDED Microsoft Platform SDK 2003 SP1 +/-
NEEDED Microsoft DirectX 9.0c SDK (June 2005) +
NEEDED Microsoft Visual Studio .NET Professional 2003 German +
+ newer is ok
+/- newer and older is ok

4
res/Known Bugs.txt Normal file
View File

@ -0,0 +1,4 @@
Known Bugs:
- fsMaxScale = 1 in Direct3D fullscreen results in wrong image size
- Direct3D: Menu toggle takes a little too long

81
res/ReadMe.txt Normal file
View File

@ -0,0 +1,81 @@
VisualBoyAdvance S1.7.6
Nintendo Game Boy / Game Boy Advance Emulator
This program is distributed under the GNU General Public License
http://www.gnu.org/licenses/gpl.html
VBA Official Version 1.7.2 with changes by Spacy
Spacy51@gmx.de (Write in english or in german)
Special Build Aturhors Homepage: www.spacyhacks.de.vu
Original Project Homepage: vba.ngemu.com
My aim:
I want to make this emulator fit my needs and hopefully the needs of others,
which want a light-weight small, fast and multimedial emulator for the GBA
that makes as much use of the power of modern PCs as possible (but with sense).
If you need one of the removed features, just use the original VBA emulator.
Thanks go to:
suanyuan For help in compilation and other fixes
Tauwasser For help in assembler
WingX For fixing a linker error
The following changes have been made:
S1.7.6:
Emu:
- Readded MMX macro
- Updated zlib to 1.2.3
- Changed some first start options
- Other small changes
- Put zlib & libpng in seperate Projects
- Added some changes from the latest CVS source
- Small changes to ROM Header Info (just4fun)
- Fixed the linker error (new&delete defined twice)
Filters:
- Speeded up HQ3X code
- Fixed LQ2X using HQ2X functions
Display:
- Added extended display mode selection
(Display Adapter, Resolution, Bit Depth, Frequency)
- No more unnecessary black borders in full screen
- Direct3D doesn't take the whole screen (only if you want)
- Direct3D shows menu and windows correct
- Direct3D doesn't show a black screen if left fullscreen to Windows
- Changes on max scale are applied immediately
Sound:
- Updated sound to DirectSound8
S1.7.5:
- Removed screen flickering when switching to GDI mode.
- Changed some first start options.
- Rearranged Menu
- Added HQ3X in 32 bit mode
- Changed App Icon
- Added FINAL_VERSION definition again.
- Added 3x/4x filter support to OpenGL mode
- Some minor fixes
S1.7.4:
- optimized build: (many thanks to suanyuan)
- libpng, zlib, MFC linked static
- Target OS: Windows 2000
- Keep in mind that HQ3X/HQ4X is NOT added
at the moment, but everything is ready for it
S1.7.3:
- Optimized build and project file
- Removed Skin support
- Removed SDL support
- Removed Linux support
- Removed Motion Blur Experimental Filter (the none-IFB version)
- Reworked GDI
- 3x / 4x filter support
- Fullscreen modes available

BIN
res/VBA.APS Normal file

Binary file not shown.

BIN
res/VBA.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

22
res/VBA.manifest Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="0.6.0.0"
processorArchitecture="X86"
name="VisualBoyAdvance"
type="win32"
/>
<description>VisualBoyAdvance Emulator.</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

2235
res/VBA.rc Normal file

File diff suppressed because it is too large Load Diff

340
res/gpl.txt Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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.

748
res/resource.h Normal file
View File

@ -0,0 +1,748 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by VBA.rc
//
#define IDS_UNSUPPORTED_VBA_SGM 1
#define IDS_CANNOT_LOAD_SGM 2
#define IDS_SAVE_GAME_NOT_USING_BIOS 3
#define IDS_SAVE_GAME_USING_BIOS 4
#define IDS_UNSUPPORTED_SAVE_TYPE 5
#define IDS_CANNOT_OPEN_FILE 6
#define IDS_BAD_ZIP_FILE 7
#define IDS_NO_IMAGE_ON_ZIP 8
#define IDS_ERROR_OPENING_IMAGE 9
#define IDS_ERROR_READING_IMAGE 10
#define IDS_UNSUPPORTED_BIOS_FUNCTION 11
#define IDS_INVALID_BIOS_FILE_SIZE 12
#define IDS_INVALID_CHEAT_CODE 13
#define IDS_UNKNOWN_ARM_OPCDOE 14
#define IDS_UNKNOWN_THUMB_OPCODE 15
#define IDS_ERROR_CREATING_FILE 16
#define IDS_FAILED_TO_READ_SGM 17
#define IDS_FAILED_TO_READ_RTC 18
#define IDS_UNSUPPORTED_VB_SGM 19
#define IDS_CANNOT_LOAD_SGM_FOR 20
#define IDS_ERROR_OPENING_IMAGE_FROM 21
#define IDS_ERROR_READING_IMAGE_FROM 22
#define IDS_UNSUPPORTED_ROM_SIZE 23
#define IDS_UNSUPPORTED_RAM_SIZE 24
#define IDS_UNKNOWN_CARTRIDGE_TYPE 25
#define IDS_MAXIMUM_NUMBER_OF_CHEATS 26
#define IDS_INVALID_GAMESHARK_CODE 27
#define IDS_INVALID_GAMEGENIE_CODE 28
#define IDS_INVALID_CHEAT_TO_REMOVE 29
#define IDS_INVALID_CHEAT_CODE_ADDRESS 30
#define IDS_UNSUPPORTED_CHEAT_LIST_VERSION 31
#define IDS_UNSUPPORTED_CHEAT_LIST_TYPE 32
#define IDS_INVALID_GSA_CODE 33
#define IDS_CANNOT_IMPORT_SNAPSHOT_FOR 34
#define IDS_UNSUPPORTED_SNAPSHOT_FILE 35
#define IDS_UNSUPPORTED_ARM_MODE 36
#define IDS_UNSUPPORTED_CODE_FILE 37
#define IDS_GSA_CODE_WARNING 38
#define IDS_INVALID_CBA_CODE 39
#define IDS_CBA_CODE_WARNING 40
#define IDS_OUT_OF_MEMORY 41
#define IDI_ICON 101
#define IDR_MENU 104
#define IDD_ABOUT 105
#define IDR_ACCELERATOR 106
#define IDD_CHEATS 107
#define IDD_ADD_CHEAT 108
#define IDD_DIRECTORIES 109
#define IDD_CONFIG 110
#define IDD_CHEAT_LIST 113
#define IDD_ASSOCIATIONS 114
#define IDD_GBA_ROM_INFO 116
#define IDD_GB_ROM_INFO 117
#define IDD_GB_CHEAT_LIST 118
#define IDD_ADD_CHEAT_DLG 119
#define IDD_GB_PRINTER 120
#define IDD_MOTION_CONFIG 121
#define IDD_LANG_SELECT 122
#define IDD_CODE_SELECT 123
#define IDD_OPENDLG 124
#define IDD_MAP_VIEW 126
#define IDD_PALETTE_VIEW 127
#define IDD_MEM_VIEWER 128
#define IDD_OAM_VIEW 130
#define IDD_ACCEL_EDITOR 131
#define IDD_TILE_VIEWER 132
#define IDD_GB_COLORS 133
#define IDD_DISASSEMBLE 134
#define IDD_GDB_PORT 135
#define IDD_GDB_WAITING 136
#define IDD_LOGGING 137
#define IDD_EXPORT_SPS 138
#define IDD_ADDR_SIZE 139
#define IDD_MODES 140
#define IDD_DRIVERS 142
#define IDD_THROTTLE 143
#define IDD_GB_DISASSEMBLE 144
#define IDD_GB_OAM_VIEW 145
#define IDD_GB_TILE_VIEWER 146
#define IDD_GB_MAP_VIEW 147
#define IDD_GB_PALETTE_VIEW 148
#define IDD_MODE_CONFIRM 149
#define IDD_REWIND_INTERVAL 150
#define IDD_IO_VIEWER 151
#define IDD_MAX_SCALE 154
#define IDD_BUG_REPORT 155
#define IDD_UNIVIDMODE 158
#define IDC_R0 1000
#define IDC_EDIT_UP 1000
#define IDC_R1 1001
#define IDC_EDIT_DOWN 1001
#define IDC_R2 1002
#define IDC_EDIT_LEFT 1002
#define IDC_R3 1003
#define IDC_EDIT_RIGHT 1003
#define IDC_R4 1004
#define IDC_EDIT_BUTTON_A 1004
#define IDC_R5 1005
#define IDC_EDIT_BUTTON_B 1005
#define IDC_R6 1006
#define IDC_EDIT_BUTTON_SELECT 1006
#define IDC_R7 1007
#define IDC_EDIT_BUTTON_START 1007
#define IDC_R8 1008
#define ID_OK 1008
#define IDC_R9 1009
#define ID_CANCEL 1009
#define ID_SAVE 1009
#define IDC_R10 1010
#define IDC_EDIT_SPEED 1010
#define IDC_R11 1011
#define IDC_EDIT_CAPTURE 1011
#define IDC_R12 1012
#define IDC_EDIT_BUTTON_L 1012
#define IDC_R13 1013
#define IDC_EDIT_BUTTON_GS 1013
#define IDC_R14 1014
#define IDC_EDIT_BUTTON_R 1014
#define IDC_R15 1015
#define IDC_R16 1016
#define IDC_ROM_DIR 1018
#define IDC_NEXT 1019
#define IDC_BATTERY_DIR 1019
#define IDC_SAVE_DIR 1020
#define IDC_CAPTURE_DIR 1021
#define IDC_CHEAT_LIST 1021
#define IDC_ROM_PATH 1022
#define IDC_START 1022
#define IDC_BATTERY_PATH 1023
#define IDC_SEARCH 1023
#define IDS_DIRECTX_7_REQUIRED 1024
#define IDC_SAVE_PATH 1024
#define IDC_ADD_CHEAT 1024
#define IDC_CAPTURE_PATH 1025
#define IDC_OLD_VALUE 1025
#define IDC_ADD_GS_CHEAT 1025
#define IDS_DISABLING_VIDEO_MEMORY 1025
#define IDC_ADD_GAMESHARK 1025
#define IDC_SPECIFIC_VALUE 1026
#define IDS_SETTING_WILL_BE_EFFECTIVE 1026
#define IDC_GBROM_DIR 1026
#define IDS_DISABLING_EMULATION_ONLY 1027
#define IDC_GBROM_PATH 1027
#define IDC_SIZE_8 1028
#define IDS_FAILED_TO_OPEN_FILE 1028
#define IDC_ROM_DIR_RESET 1028
#define IDC_SIZE_16 1029
#define IDS_FAILED_TO_READ_ZIP_DIR 1029
#define IDC_GBROM_DIR_RESET 1029
#define IDC_SIZE_32 1030
#define IDS_UNSUPPORTED_FILE_TYPE 1030
#define IDC_BATTERY_DIR_RESET 1030
#define IDC_EQ 1031
#define IDS_CANNOT_CREATE_DIRECTSOUND 1031
#define IDC_SAVE_DIR_RESET 1031
#define IDC_NE 1032
#define IDS_CANNOT_SETCOOPERATIVELEVEL 1032
#define IDC_CAPTURE_DIR_RESET 1032
#define IDC_LT 1033
#define IDS_CANNOT_CREATESOUNDBUFFER 1033
#define IDC_LE 1034
#define IDS_CANNOT_SETFORMAT_PRIMARY 1034
#define IDC_GT 1035
#define IDS_CANNOT_CREATESOUNDBUFFER_SEC 1035
#define IDC_GE 1036
#define IDS_CANNOT_PLAY_PRIMARY 1036
#define IDC_SIGNED 1037
#define IDS_SEARCH_PRODUCED_TOO_MANY 1037
#define IDC_UNSIGNED 1038
#define IDS_NUMBER_CANNOT_BE_EMPTY 1038
#define IDS_INVALID_ADDRESS 1039
#define IDC_HEXADECIMAL 1040
#define IDS_MISALIGNED_HALFWORD 1040
#define IDC_VALUE 1041
#define IDS_MISALIGNED_WORD 1041
#define IDC_ADDRESS 1042
#define IDS_VALUE_CANNOT_BE_EMPTY 1042
#define IDS_ERROR_ON_STARTDOC 1043
#define IDC_R 1043
#define IDS_ERROR_ON_STARTPAGE 1044
#define IDC_G 1044
#define IDS_ERROR_PRINTING_ON_STRETCH 1045
#define IDC_B 1045
#define IDC_UPDATE 1046
#define IDS_ERROR_ON_ENDPAGE 1046
#define IDC_TILE_NUM 1046
#define IDS_ERROR_ON_ENDDOC 1047
#define IDC_FLIP 1047
#define IDS_ERROR 1048
#define IDC_PALETTE_NUM 1048
#define IDS_JOY_LEFT 1049
#define IDS_JOY_RIGHT 1050
#define IDS_JOY_UP 1051
#define IDS_JOY_DOWN 1052
#define IDS_JOY_BUTTON 1053
#define IDS_SELECT_ROM_DIR 1054
#define IDS_SELECT_BATTERY_DIR 1055
#define IDS_SELECT_SAVE_DIR 1056
#define IDS_SELECT_CAPTURE_DIR 1057
#define IDS_SELECT_BIOS_FILE 1058
#define IDS_RESET 1059
#define IDS_AUTOFIRE_A_DISABLED 1060
#define IDS_AUTOFIRE_A 1061
#define IDS_AUTOFIRE_B_DISABLED 1062
#define IDS_AUTOFIRE_B 1063
#define IDS_AUTOFIRE_L_DISABLED 1064
#define IDS_AUTOFIRE_L 1065
#define IDS_AUTOFIRE_R_DISABLED 1066
#define IDC_REMOVE 1067
#define IDS_AUTOFIRE_R 1067
#define IDC_REMOVE_ALL 1068
#define IDS_SELECT_ROM 1068
#define IDS_SELECT_SAVE_GAME_NAME 1069
#define IDC_ENABLE 1070
#define IDS_LOADED_STATE 1070
#define IDS_LOADED_STATE_N 1071
#define IDS_WROTE_STATE 1072
#define IDS_WROTE_STATE_N 1073
#define IDC_RESTORE 1074
#define IDS_LOADED_BATTERY 1074
#define IDC_GBA 1075
#define IDS_SELECT_CAPTURE_NAME 1075
#define IDC_AGB 1076
#define IDS_SCREEN_CAPTURE 1076
#define IDC_BIN 1077
#define IDS_ADDRESS 1077
#define IDC_GB 1078
#define IDS_OLD_VALUE 1078
#define IDC_SGB 1079
#define IDC_ROM_TITLE 1079
#define IDS_NEW_VALUE 1079
#define IDC_CGB 1080
#define IDC_ROM_GAME_CODE 1080
#define IDS_ADD_CHEAT_CODE 1080
#define IDC_GBC 1081
#define IDC_ROM_MAKER_CODE 1081
#define IDS_CODE 1081
#define IDC_ROM_UNIT_CODE 1082
#define IDS_DESCRIPTION 1082
#define IDC_ROM_DEVICE_TYPE 1083
#define IDS_STATUS 1083
#define IDC_ROM_VERSION 1084
#define IDS_ADD_GG_CODE 1084
#define IDC_ROM_CRC 1085
#define IDS_ADD_GS_CODE 1085
#define IDC_ROM_COLOR 1086
#define IDC_CODE 1086
#define IDS_POCKET_PRINTER 1086
#define IDC_ROM_MAKER_NAME 1086
#define IDC_ROM_SIZE 1087
#define IDC_DESC 1087
#define IDS_UNKNOWN 1087
#define IDC_ROM_RAM_SIZE 1088
#define IDC_ADD_GG_CHEAT 1088
#define IDS_NONE 1088
#define IDC_ROM_DEST_CODE 1089
#define IDC_GB_PRINTER 1089
#define IDS_FAILED_TO_LOAD_LIBRARY 1089
#define IDC_ROM_LIC_CODE 1090
#define IDC_1X 1090
#define IDS_FAILED_TO_GET_LOCINFO 1090
#define IDC_ROM_CHECKSUM 1091
#define IDC_2X 1091
#define IDS_SELECT_CHEAT_LIST_NAME 1091
#define IDC_3X 1092
#define IDS_FILTER_BIOS 1092
#define IDC_4X 1093
#define IDS_FILTER_ROM 1093
#define IDC_ROM_MAKER_NAME2 1093
#define ID_PRINT 1094
#define IDS_FILTER_SGM 1094
#define IDC_ADD_CODE 1095
#define IDS_FILTER_CHEAT_LIST 1095
#define IDS_FILTER_PNG 1096
#define IDC_LANG_STRING 1097
#define IDS_LOADED_CHEATS 1097
#define IDC_LANG_NAME 1098
#define IDS_ERROR_DISP_COLOR 1098
#define IDS_ADD_GSA_CODE 1099
#define IDC_GAME_LIST 1099
#define IDS_FILTER_SPS 1100
#define IDS_SELECT_SNAPSHOT_FILE 1101
#define IDC_ADD_CODEBREAKER 1101
#define IDS_FILTER_SAV 1102
#define IDS_SELECT_BATTERY_FILE 1103
#define IDS_FILTER_GBS 1104
#define IDS_FILTER_GCF 1105
#define IDS_SELECT_CODE_FILE 1106
#define IDS_SAVE_WILL_BE_LOST 1107
#define IDS_CONFIRM_ACTION 1108
#define IDS_CODES_WILL_BE_LOST 1109
#define IDS_FILTER_SPC 1110
#define IDS_ADD_CBA_CODE 1111
#define IDS_FILTER_WAV 1112
#define IDS_SELECT_WAV_NAME 1113
#define IDC_FRAME_0 1113
#define IDS_FILTER_GBROM 1114
#define IDC_FRAME_1 1114
#define IDC_BG0 1115
#define IDS_FILTER_PAL 1115
#define IDC_BG1 1116
#define IDS_SELECT_PALETTE_NAME 1116
#define IDC_BG2 1117
#define IDS_SEARCH_PRODUCED_NO_RESULTS 1117
#define IDC_BG3 1118
#define IDS_ERROR_BINDING 1118
#define IDS_ERROR_LISTENING 1119
#define IDS_ERROR_CREATING_SOCKET 1120
#define IDS_ACK_NOT_RECEIVED 1121
#define IDS_ERROR_NOT_GBA_IMAGE 1122
#define IDS_EEPROM_NOT_SUPPORTED 1123
#define IDC_MAP_VIEW 1124
#define IDS_FILTER_DUMP 1124
#define IDC_PALETTE_VIEW 1125
#define IDS_SELECT_DUMP_FILE 1125
#define IDC_PALETTE_VIEW_OBJ 1126
#define IDC_REFRESH 1126
#define IDS_FILTER_AVI 1126
#define IDC_SAVE 1127
#define IDC_GOPC 1127
#define IDS_SELECT_AVI_NAME 1127
#define IDC_APPLY 1127
#define IDS_INVALID_THROTTLE_VALUE 1128
#define IDC_REFRESH2 1129
#define IDS_FILTER_INI 1129
#define IDC_CLOSE 1131
#define IDS_FILTER_VMV 1131
#define IDS_SELECT_MOVIE_NAME 1132
#define IDS_BUG_REPORT 1133
#define IDS_UNSUPPORTED_MOVIE_VERSION 1134
#define IDS_END_OF_MOVIE 1135
#define IDC_COLOR 1136
#define IDS_INVALID_INTERVAL_VALUE 1136
#define IDC_SAVE_BG 1137
#define IDS_REGISTRY 1137
#define IDC_SAVE_OBJ 1138
#define IDC_MAP_VIEW_ZOOM 1138
#define IDS_MOVIE_PLAY 1138
#define IDC_VIEWER 1140
#define IDC_ADDRESSES 1141
#define IDC_GO 1143
#define IDC_8_BIT 1144
#define IDC_16_BIT 1145
#define IDC_32_BIT 1146
#define IDC_OAM_VIEW 1147
#define IDC_OAM_VIEW_ZOOM 1148
#define IDC_SPRITE 1150
#define IDC_POS 1151
#define IDC_MODE 1152
#define IDC_COLORS 1153
#define IDC_MAPBASE 1153
#define IDC_PALETTE 1154
#define IDC_CHARBASE 1154
#define IDC_TILE 1155
#define IDC_DIM 1155
#define IDC_PRIO 1156
#define IDC_NUMCOLORS 1156
#define IDC_SCROLLBAR 1157
#define IDC_PRIORITY 1157
#define IDC_MOSAIC 1158
#define IDC_SIZE2 1159
#define IDC_OVERFLOW 1159
#define IDC_ROT 1160
#define IDC_FLAGS 1161
#define IDC_COMMANDS 1162
#define IDC_BANK 1162
#define IDC_CURRENTS 1163
#define IDC_ASSIGN 1164
#define IDC_RESET 1165
#define IDC_EDIT_KEY 1166
#define IDC_ALREADY_AFFECTED 1167
#define IDC_TILE_VIEW 1168
#define IDC_16_COLORS 1169
#define IDC_256_COLORS 1170
#define IDC_CHARBASE_0 1173
#define IDC_CHARBASE_1 1174
#define IDC_CHARBASE_2 1175
#define IDC_CHARBASE_3 1176
#define IDC_PALETTE_SLIDER 1177
#define IDC_CHARBASE_4 1178
#define IDC_COLOR_BG0 1178
#define IDC_COLOR_BG1 1179
#define IDC_URL 1179
#define IDC_COLOR_BG2 1180
#define IDC_STRETCH 1180
#define IDC_URL2 1180
#define IDC_COLOR_BG3 1181
#define IDC_URL3 1181
#define IDC_COLOR_OB0 1182
#define IDC_COLOR_OB1 1183
#define IDC_COLOR_OB2 1184
#define IDC_COLOR_OB3 1185
#define IDC_STATIC1 1187
#define IDC_STATIC2 1188
#define IDC_STATIC3 1189
#define IDC_DEFAULT 1191
#define IDC_USER1 1192
#define IDC_USER2 1193
#define IDC_DISASSEMBLE 1196
#define IDC_AUTOMATIC 1199
#define IDC_ARM 1200
#define IDC_THUMB 1201
#define IDC_AUTO_UPDATE 1204
#define IDC_N 1210
#define IDC_Z 1211
#define IDC_C 1212
#define IDC_V 1213
#define IDC_F 1214
#define IDC_I 1215
#define IDC_T 1216
#define IDC_PORT 1217
#define IDC_VSCROLL 1218
#define IDC_VERSION 1219
#define IDC_VERBOSE_SWI 1223
#define IDC_VERBOSE_UNALIGNED_ACCESS 1224
#define IDC_VERBOSE_ILLEGAL_WRITE 1225
#define IDC_VERBOSE_ILLEGAL_READ 1226
#define IDC_LOG 1227
#define IDC_CLEAR 1228
#define IDC_VERBOSE_DMA0 1229
#define IDC_VERBOSE_DMA1 1230
#define IDC_TILE_NUMBER 1230
#define IDC_VERBOSE_DMA2 1231
#define IDC_XY 1231
#define IDC_VERBOSE_DMA3 1232
#define IDC_VERBOSE_UNDEFINED 1233
#define IDC_TITLE 1234
#define IDC_VERBOSE_AGBPRINT 1234
#define IDC_CURRENT_ADDRESS 1235
#define IDC_NOTES 1236
#define IDC_CURRENT_ADDRESS_LABEL 1236
#define IDC_LOAD 1238
#define IDC_SIZE_CONTROL 1240
#define IDC_MODES 1240
#define IDC_DRIVERS 1241
#define IDC_THROTTLE 1242
#define IDC_H 1243
#define IDC_OAP 1244
#define IDC_BANK_0 1245
#define IDC_BANK_1 1246
#define IDC_TIMER 1247
#define IDC_INTERVAL 1248
#define IDC_BIT_0 1250
#define IDC_BIT_1 1251
#define IDC_PREDEFINED 1251
#define IDC_BIT_2 1252
#define IDC_BUG_REPORT 1252
#define IDC_BIT_3 1253
#define IDC_COPY 1253
#define IDC_BIT_4 1254
#define IDC_APINAME 1254
#define IDC_BIT_5 1255
#define IDC_DISPLAYDEVICE 1255
#define IDC_BIT_6 1256
#define IDC_LISTMODES 1256
#define IDC_BIT_7 1257
#define IDC_BIT_8 1258
#define IDC_BIT_9 1259
#define IDC_BUTTON1 1259
#define IDC_BUTTON_MAXSCALE 1259
#define IDC_BIT_10 1260
#define IDC_CHECK_STRETCHTOFIT 1260
#define IDC_BIT_11 1261
#define IDC_BIT_12 1262
#define IDC_BIT_13 1263
#define IDC_BIT_14 1264
#define IDC_BIT_15 1265
#define ID_HELP_ABOUT 40001
#define ID_FILE_EXIT 40002
#define ID_OPTIONS_VIDEO_FRAMESKIP_0 40003
#define ID_OPTIONS_VIDEO_FRAMESKIP_1 40004
#define ID_OPTIONS_VIDEO_FRAMESKIP_2 40005
#define ID_OPTIONS_VIDEO_FRAMESKIP_3 40006
#define ID_OPTIONS_VIDEO_FRAMESKIP_4 40007
#define ID_OPTIONS_VIDEO_FRAMESKIP_5 40008
#define ID_OPTIONS_VIDEO_VSYNC 40009
#define ID_OPTIONS_VIDEO_X1 40010
#define ID_OPTIONS_VIDEO_X2 40011
#define ID_OPTIONS_VIDEO_X3 40012
#define ID_OPTIONS_VIDEO_X4 40013
#define ID_FILE_PAUSE 40014
#define ID_OPTIONS_EMULATOR_DIRECTORIES 40015
#define ID_OPTIONS_EMULATOR_SYNCHRONIZE 40017
#define ID_FILE_RESET 40018
#define ID_FILE_LOAD 40019
#define ID_OPTIONS_SOUND_DIRECTSOUNDA 40020
#define ID_OPTIONS_SOUND_DIRECTSOUNDB 40021
#define ID_OPTIONS_SOUND_OFF 40022
#define ID_OPTIONS_SOUND_MUTE 40023
#define ID_OPTIONS_SOUND_ON 40024
#define ID_OPTIONS_SOUND_CHANNEL1 40025
#define ID_OPTIONS_SOUND_CHANNEL2 40026
#define ID_OPTIONS_SOUND_CHANNEL3 40027
#define ID_OPTIONS_SOUND_CHANNEL4 40028
#define ID_OPTIONS_EMULATOR_USEBIOSFILE 40029
#define ID_OPTIONS_EMULATOR_SELECTBIOSFILE 40030
#define ID_CHEATS_SEARCHFORCHEATS 40031
#define ID_OPTIONS_VIDEO_DISABLESFX 40033
#define ID_OPTIONS_GAMEBOY_BORDER 40034
#define ID_FILE_SAVEGAME_SLOT1 40035
#define ID_FILE_SAVEGAME_SLOT2 40036
#define ID_FILE_SAVEGAME_SLOT3 40037
#define ID_FILE_SAVEGAME_SLOT4 40038
#define ID_FILE_SAVEGAME_SLOT5 40039
#define ID_FILE_SAVEGAME_SLOT6 40040
#define ID_FILE_SAVEGAME_SLOT7 40041
#define ID_FILE_SAVEGAME_SLOT8 40042
#define ID_FILE_SAVEGAME_SLOT9 40043
#define ID_FILE_SAVEGAME_SLOT10 40044
#define ID_FILE_LOADGAME_SLOT1 40045
#define ID_FILE_LOADGAME_SLOT2 40046
#define ID_FILE_LOADGAME_SLOT3 40047
#define ID_FILE_LOADGAME_SLOT4 40048
#define ID_FILE_LOADGAME_SLOT5 40049
#define ID_FILE_LOADGAME_SLOT6 40050
#define ID_FILE_LOADGAME_SLOT7 40051
#define ID_FILE_LOADGAME_SLOT8 40052
#define ID_FILE_LOADGAME_SLOT9 40053
#define ID_FILE_LOADGAME_SLOT10 40054
#define ID_OPTIONS_GAMEBOY_AUTOMATIC 40057
#define ID_OPTIONS_GAMEBOY_CGB 40058
#define ID_OPTIONS_GAMEBOY_GBA 40059
#define ID_OPTIONS_GAMEBOY_SGB 40060
#define ID_OPTIONS_GAMEBOY_GB 40062
#define ID_OPTIONS_GAMEBOY_REALCOLORS 40063
#define ID_OPTIONS_GAMEBOY_GAMEBOYCOLORS 40064
#define ID_OPTIONS_SOUND_11KHZ 40067
#define ID_OPTIONS_SOUND_22KHZ 40068
#define ID_OPTIONS_SOUND_44KHZ 40069
#define ID_OPTIONS_VIDEO_DDRAWEMULATIONONLY 40070
#define ID_OPTIONS_VIDEO_DDRAWUSEVIDEOMEMORY 40071
#define ID_OPTIONS_PRIORITY_HIGHEST 40072
#define ID_OPTIONS_PRIORITY_ABOVENORMAL 40073
#define ID_OPTIONS_PRIORITY_NORMAL 40074
#define ID_OPTIONS_PRIORITY_BELOWNORMAL 40075
#define ID_OPTIONS_VIDEO_FULLSCREEN320X240 40076
#define ID_OPTIONS_VIDEO_FULLSCREEN640X480 40077
#define ID_OPTIONS_FILTER_NORMAL 40078
#define ID_OPTIONS_FILTER_2XSAI 40079
#define ID_OPTIONS_FILTER_SUPER2XSAI 40081
#define ID_OPTIONS_FILTER_SUPEREAGLE 40082
#define ID_OPTIONS_FILTER_TVMODE 40083
#define ID_CHEATS_CHEATLIST 40084
#define ID_OPTIONS_JOYPAD_AUTOFIRE_A 40085
#define ID_OPTIONS_JOYPAD_AUTOFIRE_B 40086
#define ID_OPTIONS_JOYPAD_AUTOFIRE_L 40087
#define ID_OPTIONS_JOYPAD_AUTOFIRE_R 40088
#define ID_OPTIONS_VIDEO_FULLSCREENSTRETCHTOFIT 40089
#define ID_OPTIONS_EMULATOR_ASSOCIATE 40091
#define ID_OPTIONS_FILTER_DISABLEMMX 40093
#define ID_FILE_ROMINFORMATION 40100
#define ID_OPTIONS_EMULATOR_DISABLESTATUSMESSAGES 40102
#define ID_OPTIONS_JOYPAD_MOTIONCONFIGURE 40103
#define ID_FILE_SCREENCAPTURE 40104
#define ID_OPTIONS_LANGUAGE_SYSTEM 40105
#define ID_OPTIONS_LANGUAGE_ENGLISH 40106
#define ID_OPTIONS_LANGUAGE_OTHER 40107
#define ID_OPTIONS_GAMEBOY_PRINTER 40108
#define ID_FILE_RECENT_RESET 40109
#define ID_CHEATS_SAVECHEATLIST 40110
#define ID_CHEATS_LOADCHEATLIST 40111
#define ID_CHEATS_AUTOMATICSAVELOADCHEATS 40112
#define ID_FILE_IMPORT_GAMESHARKSNAPSHOT 40115
#define ID_FILE_IMPORT_BATTERYFILE 40116
#define ID_FILE_IMPORT_GAMESHARKCODEFILE 40117
#define ID_FILE_EXPORT_BATTERYFILE 40118
#define ID_OPTIONS_FILTER16BIT_PIXELATEEXPERIMENTAL 40121
#define ID_OPTIONS_EMULATOR_PAUSEWHENINACTIVE 40124
#define ID_OPTIONS_SOUND_STARTRECORDING 40125
#define ID_OPTIONS_SOUND_STOPRECORDING 40126
#define ID_OPTIONS_VIDEO_LAYERS_BG0 40127
#define ID_OPTIONS_VIDEO_LAYERS_BG1 40128
#define ID_OPTIONS_VIDEO_LAYERS_BG2 40129
#define ID_OPTIONS_VIDEO_LAYERS_BG3 40130
#define ID_OPTIONS_VIDEO_LAYERS_OBJ 40131
#define ID_OPTIONS_VIDEO_LAYERS_WIN0 40132
#define ID_OPTIONS_VIDEO_LAYERS_WIN1 40133
#define ID_OPTIONS_VIDEO_LAYERS_OBJWIN 40134
#define ID_FILE_OPENGAMEBOY 40135
#define ID_OPTIONS_SOUND_USEOLDSYNCHRONIZATION 40136
#define ID_DEBUG_NEXTFRAME 40137
#define ID_TOOLS_MAPVIEW 40138
#define ID_TOOLS_PALETTEVIEW 40139
#define ID_OPTIONS_EMULATOR_PNGFORMAT 40140
#define ID_OPTIONS_EMULATOR_BMPFORMAT 40141
#define ID_TOOLS_MEMORYVIEWER 40143
#define ID_TOOLS_OAMVIEWER 40144
#define ID_TOOLS_CUSTOMIZE 40145
#define ID_TOOLS_TILEVIEWER 40146
#define ID_OPTIONS_GAMEBOY_COLORS 40147
#define ID_OPTIONS_SOUND_ECHO 40148
#define ID_OPTIONS_SOUND_LOWPASSFILTER 40149
#define ID_OPTIONS_SOUND_REVERSESTEREO 40150
#define ID_TOOLS_DISASSEMBLE 40151
#define ID_TOOLS_DEBUG_GDB 40152
#define ID_TOOLS_DEBUG_LOADANDWAIT 40153
#define ID_TOOLS_DEBUG_DISCONNECT 40154
#define ID_TOOLS_DEBUG_BREAK 40155
#define ID_TOOLS_LOGGING 40156
#define ID_OPTIONS_EMULATOR_SPEEDUPTOGGLE 40158
#define ID_OPTIONS_EMULATOR_REMOVEINTROSGBA 40159
#define ID_OPTIONS_FILTER16BIT_ADVANCEMAMESCALE2X 40160
#define ID_OPTIONS_FILTER16BIT_SIMPLE2X 40161
#define ID_FILE_RECENT_FREEZE 40162
#define ID_FILE_EXPORT_GAMESHARKSNAPSHOT 40163
#define ID_OPTIONS_VIDEO_FULLSCREEN800X600 40164
#define ID_OPTIONS_VIDEO_FRAMESKIP_6 40165
#define ID_OPTIONS_VIDEO_FRAMESKIP_7 40166
#define ID_OPTIONS_VIDEO_FRAMESKIP_8 40167
#define ID_OPTIONS_VIDEO_FRAMESKIP_9 40168
#define ID_OPTIONS_EMULATOR_SAVETYPE_AUTOMATIC 40169
#define ID_OPTIONS_EMULATOR_SAVETYPE_EEPROM 40170
#define ID_OPTIONS_EMULATOR_SAVETYPE_SRAM 40171
#define ID_OPTIONS_EMULATOR_SAVETYPE_FLASH 40172
#define ID_OPTIONS_EMULATOR_SAVETYPE_EEPROMSENSOR 40173
#define ID_OPTIONS_EMULATOR_SAVETYPE_FLASH512K 40174
#define ID_OPTIONS_EMULATOR_SAVETYPE_FLASH1M 40175
#define ID_OPTIONS_EMULATOR_AUTOMATICALLYIPSPATCH 40176
#define ID_TOOLS_RECORD_STARTAVIRECORDING 40178
#define ID_TOOLS_RECORD_STOPAVIRECORDING 40179
#define ID_OPTIONS_SOUND_VOLUME_1X 40182
#define ID_OPTIONS_SOUND_VOLUME_2X 40183
#define ID_OPTIONS_SOUND_VOLUME_3X 40184
#define ID_OPTIONS_SOUND_VOLUME_4X 40185
#define ID_OPTIONS_FILTER_BILINEAR 40186
#define ID_OPTIONS_FILTER_BILINEARPLUS 40187
#define ID_OPTIONS_FILTER_INTERFRAMEBLENDING_NONE 40188
#define ID_OPTIONS_FILTER_INTERFRAMEBLENDING_MOTIONBLUR 40189
#define ID_OPTIONS_FILTER_INTERFRAMEBLENDING_SMART 40190
#define ID_OPTIONS_VIDEO_FULLSCREEN 40191
#define ID_OPTIONS_VIDEO_TRIPLEBUFFERING 40192
#define ID_OPTIONS_FRAMESKIP_AUTOMATIC 40194
#define ID_OPTIONS_EMULATOR_SHOWSPEED_NONE 40195
#define ID_OPTIONS_EMULATOR_SHOWSPEED_PERCENTAGE 40196
#define ID_OPTIONS_EMULATOR_SHOWSPEED_DETAILED 40197
#define ID_OPTIONS_EMULATOR_SHOWSPEED_TRANSPARENT 40198
#define ID_OPTIONS_JOYPAD_CONFIGURE_1 40199
#define ID_OPTIONS_JOYPAD_CONFIGURE_2 40200
#define ID_OPTIONS_JOYPAD_CONFIGURE_3 40201
#define ID_OPTIONS_JOYPAD_CONFIGURE_4 40202
#define ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_1 40208
#define ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_2 40209
#define ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_3 40210
#define ID_OPTIONS_JOYPAD_DEFAULTJOYPAD_4 40211
#define ID_OPTIONS_FRAMESKIP_THROTTLE_NOTHROTTLE 40216
#define ID_OPTIONS_FRAMESKIP_THROTTLE_50 40217
#define ID_OPTIONS_FRAMESKIP_THROTTLE_150 40218
#define ID_OPTIONS_FRAMESKIP_THROTTLE_200 40219
#define ID_OPTIONS_FRAMESKIP_THROTTLE_25 40220
#define ID_OPTIONS_FRAMESKIP_THROTTLE_OTHER 40221
#define ID_OPTIONS_FRAMESKIP_THROTTLE_100 40222
#define ID_OPTIONS_FILTER_SCANLINES 40223
#define ID_OPTIONS_VIDEO_RENDERMETHOD_GDI 40228
#define ID_OPTIONS_VIDEO_RENDERMETHOD_DIRECTDRAW 40229
#define ID_OPTIONS_VIDEO_RENDERMETHOD_DIRECT3D 40230
#define ID_OPTIONS_VIDEO_RENDERMETHOD_OPENGL 40231
#define ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DNOFILTER 40233
#define ID_OPTIONS_VIDEO_RENDEROPTIONS_D3DBILINEAR 40234
#define ID_OPTIONS_VIDEO_RENDEROPTIONS_GLNEAREST 40237
#define ID_OPTIONS_VIDEO_RENDEROPTIONS_GLBILINEAR 40238
#define ID_OPTIONS_VIDEO_RENDEROPTIONS_GLTRIANGLE 40239
#define ID_OPTIONS_VIDEO_RENDEROPTIONS_GLQUADS 40240
#define ID_OPTIONS_EMULATOR_REALTIMECLOCK 40248
#define ID_OPTIONS_GAMEBOY_SGB2 40249
#define ID_TOOLS_RECORD_STARTMOVIERECORDING 40251
#define ID_TOOLS_RECORD_STOPMOVIERECORDING 40252
#define ID_TOOLS_PLAY_STARTMOVIEPLAYING 40253
#define ID_TOOLS_PLAY_STOPMOVIEPLAYING 40254
#define ID_OPTIONS_EMULATOR_AUTOHIDEMENU 40255
#define ID_OPTIONS_GAMEBOY_BORDERAUTOMATIC 40256
#define ID_TOOLS_REWIND 40258
#define ID_OPTIONS_EMULATOR_SKIPBIOS 40259
#define ID_HELP_BUGREPORT 40260
#define ID_HELP_FAQ 40261
#define ID_OPTIONS_EMULATOR_REWINDINTERVAL 40262
#define ID_FILE_TOGGLEMENU 40263
#define ID_OPTIONS_EMULATOR_SAVETYPE_NONE 40264
#define ID_OPTIONS_EMULATOR_SAVETYPE_ENHANCEDDETECTION 40265
#define ID_TOOLS_IOVIEWER 40266
#define ID_FILE_LOADGAME_MOSTRECENT 40267
#define ID_FILE_SAVEGAME_OLDESTSLOT 40268
#define ID_FILE_LOADGAME_AUTOLOADMOSTRECENT 40269
#define ID_OPTIONS_SOUND_VOLUME_5X 40270
#define ID_OPTIONS_SOUND_VOLUME_25X 40271
#define ID_CHEATS_DISABLECHEATS 40272
#define ID_OPTIONS_VIDEO_FULLSCREENMAXSCALE 40273
#define ID_OPTIONS_FILTER_HQ2X 40274
#define ID_OPTIONS_FILTER_LQ2X 40275
#define ID_OPTIONS_EMULATOR_AGBPRINT 40281
#define ID_OPTIONS_VIDEO_FULLSCREEN1024X768 40282
#define ID_OPTIONS_VIDEO_FULLSCREEN1280X1024 40283
#define ID_OPTIONS_FILTER_SIMPLE3X 40287
#define ID_OPTIONS_FILTER_SIMPLE4X 40288
#define ID_OPTIONS_FILTER_HQ3X 40290
#define ID_OPTIONS_FILTER_HQ4X 40291
#define ID_VIDEO_WINDOWED 40292
#define ID_VIDEO_FULL 40293
#define ID_OPTIONS_SOUND_PCMINTERPOLATION_NONE 40294
#define ID_OPTIONS_SOUND_PCMINTERPOLATION_LINEAR 40295
#define ID_OPTIONS_SOUND_PCMINTERPOLATION_CUBIC 40296
#define ID_OPTIONS_SOUND_PCMINTERPOLATION_FIR 40297
#define ID_OPTIONS_SOUND_PCMINTERPOLATION_LIBRESAMPLE 40298
#define ID_OPTIONS_FILTER_LCDCOLORS 40299
#define IDD_LINKTAB1 40300
#define IDD_LINKTAB 40301
#define IDD_LINKTAB2 40302
#define IDD_LINKTAB3 40303
#define IDD_SERVERWAIT 40304
#define IDC_TAB1 40305
#define IDC_LINK_SINGLE 40306
#define IDC_LINK_TIMEOUT 40307
#define IDC_LINK_LAN 40308
#define IDC_LINK2P 40309
#define IDC_LINKTCP 40310
#define IDC_SSPEED 40311
#define IDC_SERVERSTART 40312
#define IDC_SERVERIP 40313
#define IDC_CLINKIP 40314
#define IDC_SPEEDOFF 40315
#define IDC_LINKCONNECT 40316
#define IDC_STATIC4 40317
#define ID_OPTIONS_LINK_OPTIONS 40318
#define ID_OPTIONS_LINK_LOG 40319
#define ID_OPTIONS_LINK_WIRELESSADAPTER 40320
#define IDC_LINKTIMEOUT 40321
#define IDC_CLINKTCP 40322
#define IDC_SERVERWAIT 40323
#define IDC_LINKUDP 40324
#define IDC_LINK3P 40325
#define IDC_LINK4P 40326
#define IDC_CLINKUDP 40327
#define IDC_SPEEDON 40328
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 159
#define _APS_NEXT_COMMAND_VALUE 40300
#define _APS_NEXT_CONTROL_VALUE 1261
#define _APS_NEXT_SYMED_VALUE 103
#endif
#endif

754
snd_interp.cpp Normal file
View File

@ -0,0 +1,754 @@
#include <math.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "../../libresample-0.1.3/include/libresample.h"
//#define LIBSAMPLERATE // buggy
#ifdef LIBSAMPLERATE
#include "../../libsamplerate-0.1.2/src/samplerate.h"
#endif
#include "snd_interp.h"
// this was once borrowed from libmodplug, and was also used to generate the FIR coefficient
// tables that ZSNES uses for its "FIR" interpolation mode
/*
------------------------------------------------------------------------------------------------
fir interpolation doc,
(derived from "an engineer's guide to fir digital filters", n.j. loy)
calculate coefficients for ideal lowpass filter (with cutoff = fc in 0..1 (mapped to 0..nyquist))
c[-N..N] = (i==0) ? fc : sin(fc*pi*i)/(pi*i)
then apply selected window to coefficients
c[-N..N] *= w(0..N)
with n in 2*N and w(n) being a window function (see loy)
then calculate gain and scale filter coefs to have unity gain.
------------------------------------------------------------------------------------------------
*/
// quantizer scale of window coefs
#define WFIR_QUANTBITS 14
#define WFIR_QUANTSCALE (1L<<WFIR_QUANTBITS)
#define WFIR_8SHIFT (WFIR_QUANTBITS-8)
#define WFIR_16BITSHIFT (WFIR_QUANTBITS)
// log2(number)-1 of precalculated taps range is [4..12]
#define WFIR_FRACBITS 12
#define WFIR_LUTLEN ((1L<<(WFIR_FRACBITS+1))+1)
// number of samples in window
#define WFIR_LOG2WIDTH 3
#define WFIR_WIDTH (1L<<WFIR_LOG2WIDTH)
#define WFIR_SMPSPERWING ((WFIR_WIDTH-1)>>1)
// cutoff (1.0 == pi/2)
#define WFIR_CUTOFF 0.95f
// wfir type
#define WFIR_HANN 0
#define WFIR_HAMMING 1
#define WFIR_BLACKMANEXACT 2
#define WFIR_BLACKMAN3T61 3
#define WFIR_BLACKMAN3T67 4
#define WFIR_BLACKMAN4T92 5
#define WFIR_BLACKMAN4T74 6
#define WFIR_KAISER4T 7
#define WFIR_TYPE WFIR_KAISER4T
// wfir help
#ifndef M_zPI
#define M_zPI 3.1415926535897932384626433832795
#endif
#define M_zEPS 1e-8
#define M_zBESSELEPS 1e-21
class CzWINDOWEDFIR
{ public:
CzWINDOWEDFIR( );
~CzWINDOWEDFIR( );
float coef( int _PCnr, float _POfs, float _PCut, int _PWidth, int _PType ) //float _PPos, float _PFc, int _PLen )
{ double _LWidthM1 = _PWidth-1;
double _LWidthM1Half = 0.5*_LWidthM1;
double _LPosU = ((double)_PCnr - _POfs);
double _LPos = _LPosU-_LWidthM1Half;
double _LPIdl = 2.0*M_zPI/_LWidthM1;
double _LWc,_LSi;
if( fabs(_LPos)<M_zEPS )
{ _LWc = 1.0;
_LSi = _PCut;
}
else
{ switch( _PType )
{ case WFIR_HANN:
_LWc = 0.50 - 0.50 * cos(_LPIdl*_LPosU);
break;
case WFIR_HAMMING:
_LWc = 0.54 - 0.46 * cos(_LPIdl*_LPosU);
break;
case WFIR_BLACKMANEXACT:
_LWc = 0.42 - 0.50 * cos(_LPIdl*_LPosU) + 0.08 * cos(2.0*_LPIdl*_LPosU);
break;
case WFIR_BLACKMAN3T61:
_LWc = 0.44959 - 0.49364 * cos(_LPIdl*_LPosU) + 0.05677 * cos(2.0*_LPIdl*_LPosU);
break;
case WFIR_BLACKMAN3T67:
_LWc = 0.42323 - 0.49755 * cos(_LPIdl*_LPosU) + 0.07922 * cos(2.0*_LPIdl*_LPosU);
break;
case WFIR_BLACKMAN4T92:
_LWc = 0.35875 - 0.48829 * cos(_LPIdl*_LPosU) + 0.14128 * cos(2.0*_LPIdl*_LPosU) - 0.01168 * cos(3.0*_LPIdl*_LPosU);
break;
case WFIR_BLACKMAN4T74:
_LWc = 0.40217 - 0.49703 * cos(_LPIdl*_LPosU) + 0.09392 * cos(2.0*_LPIdl*_LPosU) - 0.00183 * cos(3.0*_LPIdl*_LPosU);
break;
case WFIR_KAISER4T:
_LWc = 0.40243 - 0.49804 * cos(_LPIdl*_LPosU) + 0.09831 * cos(2.0*_LPIdl*_LPosU) - 0.00122 * cos(3.0*_LPIdl*_LPosU);
break;
default:
_LWc = 1.0;
break;
}
_LPos *= M_zPI;
_LSi = sin(_PCut*_LPos)/_LPos;
}
return (float)(_LWc*_LSi);
}
static signed short lut[WFIR_LUTLEN*WFIR_WIDTH];
};
signed short CzWINDOWEDFIR::lut[WFIR_LUTLEN*WFIR_WIDTH];
CzWINDOWEDFIR::CzWINDOWEDFIR()
{ int _LPcl;
float _LPcllen = (float)(1L<<WFIR_FRACBITS); // number of precalculated lines for 0..1 (-1..0)
float _LNorm = 1.0f / (float)(2.0f * _LPcllen);
float _LCut = WFIR_CUTOFF;
float _LScale = (float)WFIR_QUANTSCALE;
float _LGain,_LCoefs[WFIR_WIDTH];
for( _LPcl=0;_LPcl<WFIR_LUTLEN;_LPcl++ )
{
float _LOfs = ((float)_LPcl-_LPcllen)*_LNorm;
int _LCc,_LIdx = _LPcl<<WFIR_LOG2WIDTH;
for( _LCc=0,_LGain=0.0f;_LCc<WFIR_WIDTH;_LCc++ )
{ _LGain += (_LCoefs[_LCc] = coef( _LCc, _LOfs, _LCut, WFIR_WIDTH, WFIR_TYPE ));
}
_LGain = 1.0f/_LGain;
for( _LCc=0;_LCc<WFIR_WIDTH;_LCc++ )
{ float _LCoef = (float)floor( 0.5 + _LScale*_LCoefs[_LCc]*_LGain );
lut[_LIdx+_LCc] = (signed short)( (_LCoef<-_LScale)?-_LScale:((_LCoef>_LScale)?_LScale:_LCoef) );
}
}
}
CzWINDOWEDFIR::~CzWINDOWEDFIR()
{ // nothing todo
}
CzWINDOWEDFIR sfir;
template <class T, int buffer_size>
class sample_buffer
{
int ptr, filled;
T * buffer;
public:
sample_buffer() : ptr(0), filled(0), buffer(0) {}
~sample_buffer()
{
if (buffer) delete [] buffer;
}
void clear()
{
if (buffer)
{
delete [] buffer;
buffer = 0;
}
ptr = filled = 0;
}
inline int size() const
{
return filled;
}
void push_back(T sample)
{
if (!buffer) buffer = new T[buffer_size];
buffer[ptr] = sample;
if (++ptr >= buffer_size) ptr = 0;
if (filled < buffer_size) filled++;
}
void erase(int count)
{
if (count > filled) filled = 0;
else filled -= count;
}
T operator[] (int index) const
{
index += ptr - filled;
if (index < 0) index += buffer_size;
else if (index > buffer_size) index -= buffer_size;
return buffer[index];
}
// omghax!
void lock( T * & out1, unsigned & count1, T * & out2, unsigned & count2 )
{
if (!buffer) buffer = new T[buffer_size];
unsigned free = buffer_size - filled;
out1 = & buffer[ ptr ];
if ( ptr )
{
count1 = buffer_size - ptr;
out2 = &buffer[ 0 ];
count2 = ptr;
if ( count1 > free )
{
count1 = free;
out2 = 0;
count2 = 0;
}
else if ( count1 + count2 > free )
{
count2 = free - count1;
if ( ! count2 ) out2 = 0;
}
}
else
{
count1 = free;
out2 = 0;
count2 = 0;
}
}
void push_count( unsigned count )
{
if ( count + filled > buffer_size )
{
count = buffer_size - filled;
}
ptr = ( ptr + count ) % buffer_size;
filled += count;
}
};
class foo_null : public foo_interpolate
{
int sample;
public:
foo_null() : sample(0) {}
~foo_null() {}
void reset() {}
void push( double rate, int psample )
{
sample = psample;
}
int pop(double rate)
{
return sample;
}
};
class foo_linear : public foo_interpolate
{
sample_buffer<int,4> samples;
int position;
inline int smp(int index)
{
return samples[index];
}
public:
foo_linear()
{
position = 0;
}
~foo_linear() {}
void reset()
{
position = 0;
samples.clear();
}
void push(double rate, int sample)
{
samples.push_back(sample);
}
int pop(double rate)
{
int ret, lrate;
if (position > 0x7fff)
{
int howmany = position >> 15;
position &= 0x7fff;
samples.erase(howmany);
}
if (samples.size() < 2) return 0;
ret = smp(0) * (0x8000 - position);
ret += smp(1) * position;
ret >>= 15;
// wahoo, takes care of drifting
if (samples.size() > 2)
{
rate += (.5 / 32768.);
}
lrate = (int)(32768. * rate);
position += lrate;
return ret;
}
};
// and this integer cubic interpolation implementation was kind of borrowed from either TiMidity
// or the P.E.Op.S. SPU project, or is in use in both, or something...
class foo_cubic : public foo_interpolate
{
sample_buffer<int,12> samples;
int position;
inline int smp(int index)
{
return samples[index];
}
public:
foo_cubic()
{
position = 0;
}
~foo_cubic() {}
void reset()
{
position = 0;
samples.clear();
}
void push(double rate, int sample)
{
samples.push_back(sample);
}
int pop(double rate)
{
int ret, lrate;
if (position > 0x7fff)
{
int howmany = position >> 15;
position &= 0x7fff;
samples.erase(howmany);
}
if (samples.size() < 4) return 0;
ret = smp(3) - 3 * smp(2) + 3 * smp(1) - smp(0);
ret *= (position - (2 << 15)) / 6;
ret >>= 15;
ret += smp(2) - 2 * smp(1) + smp(0);
ret *= (position - (1 << 15)) >> 1;
ret >>= 15;
ret += smp(1) - smp(0);
ret *= position;
ret >>= 15;
ret += smp(0);
if (ret > 32767) ret = 32767;
else if (ret < -32768) ret = -32768;
// wahoo, takes care of drifting
if (samples.size() > 8)
{
rate += (.5 / 32768.);
}
lrate = (int)(32768. * rate);
position += lrate;
return ret;
}
};
class foo_fir : public foo_interpolate
{
sample_buffer<int,24> samples;
int position;
inline int smp(int index)
{
return samples[index];
}
public:
foo_fir()
{
position = 0;
}
~foo_fir() {}
void reset()
{
position = 0;
samples.clear();
}
void push(double rate, int sample)
{
samples.push_back(sample);
}
int pop(double rate)
{
int ret, lrate;
if (position > 0x7fff)
{
int howmany = position >> 15;
position &= 0x7fff;
samples.erase(howmany);
}
if (samples.size() < 8) return 0;
ret = smp(0) * CzWINDOWEDFIR::lut[(position & ~7) ];
ret += smp(1) * CzWINDOWEDFIR::lut[(position & ~7) + 1];
ret += smp(2) * CzWINDOWEDFIR::lut[(position & ~7) + 2];
ret += smp(3) * CzWINDOWEDFIR::lut[(position & ~7) + 3];
ret += smp(4) * CzWINDOWEDFIR::lut[(position & ~7) + 4];
ret += smp(5) * CzWINDOWEDFIR::lut[(position & ~7) + 5];
ret += smp(6) * CzWINDOWEDFIR::lut[(position & ~7) + 6];
ret += smp(7) * CzWINDOWEDFIR::lut[(position & ~7) + 7];
ret >>= WFIR_QUANTBITS;
if (ret > 32767) ret = 32767;
else if (ret < -32768) ret = -32768;
// wahoo, takes care of drifting
if (samples.size() > 16)
{
rate += (.5 / 32768.);
}
lrate = (int)(32768. * rate);
position += lrate;
return ret;
}
};
class foo_libresample : public foo_interpolate
{
sample_buffer<float,32> samples;
void * resampler;
public:
foo_libresample()
{
resampler = 0;
}
~foo_libresample()
{
reset();
}
void reset()
{
samples.clear();
if (resampler)
{
resample_close( resampler );
resampler = 0;
}
}
void push( double rate, int sample )
{
if ( ! resampler )
{
resampler = resample_open( 0, .25, 44100. / 4000. );
}
{
float in = float( sample );
float * samples1, * samples2;
unsigned count1, count2;
samples.lock( samples1, count1, samples2, count2 );
int used;
int processed = resample_process( resampler, 1. / rate, & in, 1, 0, & used, samples1, count1 );
samples.push_count( processed );
if ( ! used && count2 )
{
processed = resample_process( resampler, 1. / rate, & in, 1, 0, & used, samples2, count2 );
samples.push_count( processed );
}
}
}
int pop( double rate )
{
int ret;
if ( samples.size() )
{
ret = int( samples[ 0 ] );
samples.erase( 1 );
}
else ret = 0;
if ( ret > 32767 ) ret = 32767;
else if ( ret < -32768 ) ret = -32768;
return ret;
}
};
#ifdef LIBSAMPLERATE
class foo_src : public foo_interpolate
{
sample_buffer<float,32> samples;
SRC_STATE * resampler;
SRC_DATA resampler_data;
public:
foo_src()
{
resampler = 0;
}
~foo_src()
{
reset();
}
void reset()
{
samples.clear();
if (resampler)
{
resampler = src_delete( resampler );
}
}
void push( double rate, int sample )
{
if ( ! resampler )
{
int err;
resampler = src_new( SRC_LINEAR, 1, & err );
if ( err )
{
if ( resampler ) resampler = src_delete( resampler );
return;
}
}
{
float in = float( sample );
float * samples1, * samples2;
unsigned count1, count2;
samples.lock( samples1, count1, samples2, count2 );
resampler_data.data_in = & in;
resampler_data.input_frames = 1;
resampler_data.data_out = samples1;
resampler_data.output_frames = count1;
resampler_data.src_ratio = 1. / rate;
if ( src_process( resampler, & resampler_data ) )
return;
samples.push_count( resampler_data.output_frames_gen );
if ( ! resampler_data.input_frames_used && count2 )
{
resampler_data.data_out = samples2;
resampler_data.output_frames = count2;
if ( src_process( resampler, & resampler_data ) )
return;
samples.push_count( resampler_data.output_frames_gen );
}
}
}
int pop(double rate)
{
int ret;
if ( samples.size() )
{
ret = int( samples[ 0 ] );
samples.erase( 1 );
}
else ret = 0;
if ( ret > 32767 ) ret = 32767;
else if ( ret < -32768 ) ret = -32768;
return ret;
}
};
#endif
foo_interpolate * get_filter(int which)
{
switch (which)
{
default:
return new foo_null;
case 1:
return new foo_linear;
case 2:
return new foo_cubic;
case 3:
return new foo_fir;
case 4:
return new foo_libresample;
}
}
// and here is the implementation specific code, in a messier state than the stuff above
extern bool timer0On;
extern int timer0Reload;
extern int timer0ClockReload;
extern bool timer1On;
extern int timer1Reload;
extern int timer1ClockReload;
extern int SOUND_CLOCK_TICKS;
extern int soundInterpolation;
double calc_rate(int timer)
{
if (timer ? timer1On : timer0On)
{
return double(SOUND_CLOCK_TICKS) /
double((0x10000 - (timer ? timer1Reload : timer0Reload)) <<
(timer ? timer1ClockReload : timer0ClockReload));
}
else
{
return 1.;
}
}
static foo_interpolate * interp[2];
class foo_interpolate_setup
{
public:
foo_interpolate_setup()
{
for (int i = 0; i < 2; i++)
{
interp[i] = get_filter(0);
}
}
~foo_interpolate_setup()
{
for (int i = 0; i < 2; i++)
{
delete interp[i];
}
}
};
static foo_interpolate_setup blah;
class critical_section
{
CRITICAL_SECTION cs;
public:
critical_section() { InitializeCriticalSection(&cs); }
~critical_section() { DeleteCriticalSection(&cs); }
void enter() { EnterCriticalSection(&cs); }
void leave() { LeaveCriticalSection(&cs); }
};
static critical_section interp_sync;
static int interpolation = 0;
class scopelock
{
critical_section * cs;
public:
scopelock(critical_section & pcs) { cs = &pcs; cs->enter(); }
~scopelock() { cs->leave(); }
};
void interp_switch(int which)
{
scopelock sl(interp_sync);
for (int i = 0; i < 2; i++)
{
delete interp[i];
interp[i] = get_filter(which);
}
interpolation = which;
}
void interp_reset(int ch)
{
scopelock sl(interp_sync);
if (soundInterpolation != interpolation) interp_switch(soundInterpolation);
interp[ch]->reset();
}
void interp_push(int ch, double rate, int sample)
{
scopelock sl(interp_sync);
if (soundInterpolation != interpolation) interp_switch(soundInterpolation);
interp[ch]->push(rate, sample);
}
int interp_pop(int ch, double rate)
{
scopelock sl(interp_sync);
if (soundInterpolation != interpolation) interp_switch(soundInterpolation);
return interp[ch]->pop(rate);
}

30
snd_interp.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef __SND_INTERP_H__
#define __SND_INTERP_H__
// simple interface that could easily be recycled
class foo_interpolate
{
public:
foo_interpolate() {}
virtual ~foo_interpolate() {};
virtual void reset() = 0;
virtual void push( double rate, int sample ) = 0;
virtual int pop( double rate ) = 0;
};
foo_interpolate * get_filter(int which);
// complicated, synced interface, specific to this implementation
double calc_rate(int timer);
void interp_switch(int which);
void interp_reset(int ch);
void interp_push(int ch, double rate, int sample);
int interp_pop(int ch, double rate);
#endif

1274
src/2xSaI.cpp Normal file

File diff suppressed because it is too large Load Diff

2109
src/2xSaImmx.asm Normal file

File diff suppressed because it is too large Load Diff

329
src/CheatSearch.cpp Normal file
View File

@ -0,0 +1,329 @@
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <stdlib.h>
#include <memory.h>
#include "CheatSearch.h"
CheatSearchBlock cheatSearchBlocks[4];
CheatSearchData cheatSearchData = {
0,
cheatSearchBlocks
};
static bool cheatSearchEQ(u32 a, u32 b)
{
return a == b;
}
static bool cheatSearchNE(u32 a, u32 b)
{
return a != b;
}
static bool cheatSearchLT(u32 a, u32 b)
{
return a < b;
}
static bool cheatSearchLE(u32 a, u32 b)
{
return a <= b;
}
static bool cheatSearchGT(u32 a, u32 b)
{
return a > b;
}
static bool cheatSearchGE(u32 a, u32 b)
{
return a >= b;
}
static bool cheatSearchSignedEQ(s32 a, s32 b)
{
return a == b;
}
static bool cheatSearchSignedNE(s32 a, s32 b)
{
return a != b;
}
static bool cheatSearchSignedLT(s32 a, s32 b)
{
return a < b;
}
static bool cheatSearchSignedLE(s32 a, s32 b)
{
return a <= b;
}
static bool cheatSearchSignedGT(s32 a, s32 b)
{
return a > b;
}
static bool cheatSearchSignedGE(s32 a, s32 b)
{
return a >= b;
}
static bool (*cheatSearchFunc[])(u32,u32) = {
cheatSearchEQ,
cheatSearchNE,
cheatSearchLT,
cheatSearchLE,
cheatSearchGT,
cheatSearchGE
};
static bool (*cheatSearchSignedFunc[])(s32,s32) = {
cheatSearchSignedEQ,
cheatSearchSignedNE,
cheatSearchSignedLT,
cheatSearchSignedLE,
cheatSearchSignedGT,
cheatSearchSignedGE
};
void cheatSearchCleanup(CheatSearchData *cs)
{
int count = cs->count;
for(int i = 0; i < count; i++) {
free(cs->blocks[i].saved);
free(cs->blocks[i].bits);
}
cs->count = 0;
}
void cheatSearchStart(const CheatSearchData *cs)
{
int count = cs->count;
for(int i = 0; i < count; i++) {
CheatSearchBlock *block = &cs->blocks[i];
memset(block->bits, 0xff, block->size >> 3);
memcpy(block->saved, block->data, block->size);
}
}
s32 cheatSearchSignedRead(u8 *data, int off, int size)
{
u32 res = data[off++];
switch(size) {
case BITS_8:
res <<= 24;
return ((s32)res) >> 24;
case BITS_16:
res |= ((u32)data[off++])<<8;
res <<= 16;
return ((s32)res) >> 16;
case BITS_32:
res |= ((u32)data[off++])<<8;
res |= ((u32)data[off++])<<16;
res |= ((u32)data[off++])<<24;
return (s32)res;
}
return (s32)res;
}
u32 cheatSearchRead(u8 *data, int off, int size)
{
u32 res = data[off++];
if(size == BITS_16)
res |= ((u32)data[off++])<<8;
else if(size == BITS_32) {
res |= ((u32)data[off++])<<8;
res |= ((u32)data[off++])<<16;
res |= ((u32)data[off++])<<24;
}
return res;
}
void cheatSearch(const CheatSearchData *cs, int compare, int size,
bool isSigned)
{
if(compare < 0 || compare > SEARCH_GE)
return;
int inc = 1;
if(size == BITS_16)
inc = 2;
else if(size == BITS_32)
inc = 4;
if(isSigned) {
bool (*func)(s32,s32) = cheatSearchSignedFunc[compare];
for(int i = 0; i < cs->count; i++) {
CheatSearchBlock *block = &cs->blocks[i];
int size2 = block->size;
u8 *bits = block->bits;
u8 *data = block->data;
u8 *saved = block->saved;
for(int j = 0; j < size2; j += inc) {
if(IS_BIT_SET(bits, j)) {
s32 a = cheatSearchSignedRead(data, j, size);
s32 b = cheatSearchSignedRead(saved,j, size);
if(!func(a, b)) {
CLEAR_BIT(bits, j);
if(size == BITS_16)
CLEAR_BIT(bits, j+1);
if(size == BITS_32) {
CLEAR_BIT(bits, j+2);
CLEAR_BIT(bits, j+3);
}
}
}
}
}
} else {
bool (*func)(u32,u32) = cheatSearchFunc[compare];
for(int i = 0; i < cs->count; i++) {
CheatSearchBlock *block = &cs->blocks[i];
int size2 = block->size;
u8 *bits = block->bits;
u8 *data = block->data;
u8 *saved = block->saved;
for(int j = 0; j < size2; j += inc) {
if(IS_BIT_SET(bits, j)) {
u32 a = cheatSearchRead(data, j, size);
u32 b = cheatSearchRead(saved,j, size);
if(!func(a, b)) {
CLEAR_BIT(bits, j);
if(size == BITS_16)
CLEAR_BIT(bits, j+1);
if(size == BITS_32) {
CLEAR_BIT(bits, j+2);
CLEAR_BIT(bits, j+3);
}
}
}
}
}
}
}
void cheatSearchValue(const CheatSearchData *cs, int compare, int size,
bool isSigned, u32 value)
{
if(compare < 0 || compare > SEARCH_GE)
return;
int inc = 1;
if(size == BITS_16)
inc = 2;
else if(size == BITS_32)
inc = 4;
if(isSigned) {
bool (*func)(s32,s32) = cheatSearchSignedFunc[compare];
for(int i = 0; i < cs->count; i++) {
CheatSearchBlock *block = &cs->blocks[i];
int size2 = block->size;
u8 *bits = block->bits;
u8 *data = block->data;
for(int j = 0; j < size2; j += inc) {
if(IS_BIT_SET(bits, j)) {
s32 a = cheatSearchSignedRead(data, j, size);
s32 b = (s32)value;
if(!func(a, b)) {
CLEAR_BIT(bits, j);
if(size == BITS_16)
CLEAR_BIT(bits, j+1);
if(size == BITS_32) {
CLEAR_BIT(bits, j+2);
CLEAR_BIT(bits, j+3);
}
}
}
}
}
} else {
bool (*func)(u32,u32) = cheatSearchFunc[compare];
for(int i = 0; i < cs->count; i++) {
CheatSearchBlock *block = &cs->blocks[i];
int size2 = block->size;
u8 *bits = block->bits;
u8 *data = block->data;
for(int j = 0; j < size2; j += inc) {
if(IS_BIT_SET(bits, j)) {
u32 a = cheatSearchRead(data, j, size);
if(!func(a, value)) {
CLEAR_BIT(bits, j);
if(size == BITS_16)
CLEAR_BIT(bits, j+1);
if(size == BITS_32) {
CLEAR_BIT(bits, j+2);
CLEAR_BIT(bits, j+3);
}
}
}
}
}
}
}
int cheatSearchGetCount(const CheatSearchData *cs, int size)
{
int res = 0;
int inc = 1;
if(size == BITS_16)
inc = 2;
else if(size == BITS_32)
inc = 4;
for(int i = 0; i < cs->count; i++) {
CheatSearchBlock *block = &cs->blocks[i];
int size2 = block->size;
u8 *bits = block->bits;
for(int j = 0; j < size2; j += inc) {
if(IS_BIT_SET(bits, j))
res++;
}
}
return res;
}
void cheatSearchUpdateValues(const CheatSearchData *cs)
{
for(int i = 0; i < cs->count; i++) {
CheatSearchBlock *block = &cs->blocks[i];
memcpy(block->saved, block->data, block->size);
}
}

73
src/CheatSearch.h Normal file
View File

@ -0,0 +1,73 @@
// -*- C++ -*-
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef VBA_CHEATSEARCH_H
#define VBA_CHEATSEARCH_H
#include "System.h"
struct CheatSearchBlock {
int size;
u32 offset;
u8 *bits;
u8 *data;
u8 *saved;
};
struct CheatSearchData {
int count;
CheatSearchBlock *blocks;
};
enum {
SEARCH_EQ,
SEARCH_NE,
SEARCH_LT,
SEARCH_LE,
SEARCH_GT,
SEARCH_GE
};
enum {
BITS_8,
BITS_16,
BITS_32
};
#define SET_BIT(bits,off) \
(bits)[(off) >> 3] |= (1 << ((off) & 7))
#define CLEAR_BIT(bits, off) \
(bits)[(off) >> 3] &= ~(1 << ((off) & 7))
#define IS_BIT_SET(bits, off) \
(bits)[(off) >> 3] & (1 << ((off) & 7))
extern CheatSearchData cheatSearchData;
extern void cheatSearchCleanup(CheatSearchData *cs);
extern void cheatSearchStart(const CheatSearchData *cs);
extern void cheatSearch(const CheatSearchData *cs, int compare, int size,
bool isSigned);
extern void cheatSearchValue(const CheatSearchData *cs, int compare, int size,
bool isSigned, u32 value);
extern int cheatSearchGetCount(const CheatSearchData *cs, int size);
extern void cheatSearchUpdateValues(const CheatSearchData *cs);
extern s32 cheatSearchSignedRead(u8 *data, int off, int size);
extern u32 cheatSearchRead(u8 *data, int off, int size);
#endif

2770
src/Cheats.cpp Normal file

File diff suppressed because it is too large Load Diff

55
src/Cheats.h Normal file
View File

@ -0,0 +1,55 @@
// -*- C++ -*-
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef GBA_CHEATS_H
#define GBA_CHEATS_H
struct CheatsData {
int code;
int size;
int status;
bool enabled;
u32 rawaddress;
u32 address;
u32 value;
u32 oldValue;
char codestring[20];
char desc[32];
};
extern void cheatsAdd(const char *,const char *,u32, u32,u32,int,int);
extern void cheatsAddCheatCode(const char *code, const char *desc);
extern void cheatsAddGSACode(const char *code, const char *desc, bool v3);
extern void cheatsAddCBACode(const char *code, const char *desc);
extern bool cheatsImportGSACodeFile(const char *name, int game, bool v3);
extern void cheatsDelete(int number, bool restore);
extern void cheatsDeleteAll(bool restore);
extern void cheatsEnable(int number);
extern void cheatsDisable(int number);
extern void cheatsSaveGame(gzFile file);
extern void cheatsReadGame(gzFile file);
extern void cheatsSaveCheatList(const char *file);
extern bool cheatsLoadCheatList(const char *file);
extern void cheatsWriteMemory(u32, u32);
extern void cheatsWriteHalfWord(u32, u16);
extern void cheatsWriteByte(u32, u8);
extern int cheatsCheckKeys(u32,u32);
extern int cheatsNumber;
extern CheatsData cheatsList[100];
#endif // GBA_CHEATS_H

191
src/EEprom.cpp Normal file
View File

@ -0,0 +1,191 @@
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "GBA.h"
#include "EEprom.h"
#include "Util.h"
extern int cpuDmaCount;
int eepromMode = EEPROM_IDLE;
int eepromByte = 0;
int eepromBits = 0;
int eepromAddress = 0;
u8 eepromData[0x2000];
u8 eepromBuffer[16];
bool eepromInUse = false;
int eepromSize = 512;
variable_desc eepromSaveData[] = {
{ &eepromMode, sizeof(int) },
{ &eepromByte, sizeof(int) },
{ &eepromBits , sizeof(int) },
{ &eepromAddress , sizeof(int) },
{ &eepromInUse, sizeof(bool) },
{ &eepromData[0], 512 },
{ &eepromBuffer[0], 16 },
{ NULL, 0 }
};
void eepromReset()
{
eepromMode = EEPROM_IDLE;
eepromByte = 0;
eepromBits = 0;
eepromAddress = 0;
eepromInUse = false;
eepromSize = 512;
}
void eepromSaveGame(gzFile gzFile)
{
utilWriteData(gzFile, eepromSaveData);
utilWriteInt(gzFile, eepromSize);
utilGzWrite(gzFile, eepromData, 0x2000);
}
void eepromReadGame(gzFile gzFile, int version)
{
utilReadData(gzFile, eepromSaveData);
if(version >= SAVE_GAME_VERSION_3) {
eepromSize = utilReadInt(gzFile);
utilGzRead(gzFile, eepromData, 0x2000);
} else {
// prior to 0.7.1, only 4K EEPROM was supported
eepromSize = 512;
}
}
int eepromRead(u32 /* address */)
{
switch(eepromMode) {
case EEPROM_IDLE:
case EEPROM_READADDRESS:
case EEPROM_WRITEDATA:
return 1;
case EEPROM_READDATA:
{
eepromBits++;
if(eepromBits == 4) {
eepromMode = EEPROM_READDATA2;
eepromBits = 0;
eepromByte = 0;
}
return 0;
}
case EEPROM_READDATA2:
{
int data = 0;
int address = eepromAddress << 3;
int mask = 1 << (7 - (eepromBits & 7));
data = (eepromData[address+eepromByte] & mask) ? 1 : 0;
eepromBits++;
if((eepromBits & 7) == 0)
eepromByte++;
if(eepromBits == 0x40)
eepromMode = EEPROM_IDLE;
return data;
}
default:
return 0;
}
return 1;
}
void eepromWrite(u32 /* address */, u8 value)
{
if(cpuDmaCount == 0)
return;
int bit = value & 1;
switch(eepromMode) {
case EEPROM_IDLE:
eepromByte = 0;
eepromBits = 1;
eepromBuffer[eepromByte] = bit;
eepromMode = EEPROM_READADDRESS;
break;
case EEPROM_READADDRESS:
eepromBuffer[eepromByte] <<= 1;
eepromBuffer[eepromByte] |= bit;
eepromBits++;
if((eepromBits & 7) == 0) {
eepromByte++;
}
if(cpuDmaCount == 0x11 || cpuDmaCount == 0x51) {
if(eepromBits == 0x11) {
eepromInUse = true;
eepromSize = 0x2000;
eepromAddress = ((eepromBuffer[0] & 0x3F) << 8) |
((eepromBuffer[1] & 0xFF));
if(!(eepromBuffer[0] & 0x40)) {
eepromBuffer[0] = bit;
eepromBits = 1;
eepromByte = 0;
eepromMode = EEPROM_WRITEDATA;
} else {
eepromMode = EEPROM_READDATA;
eepromByte = 0;
eepromBits = 0;
}
}
} else {
if(eepromBits == 9) {
eepromInUse = true;
eepromAddress = (eepromBuffer[0] & 0x3F);
if(!(eepromBuffer[0] & 0x40)) {
eepromBuffer[0] = bit;
eepromBits = 1;
eepromByte = 0;
eepromMode = EEPROM_WRITEDATA;
} else {
eepromMode = EEPROM_READDATA;
eepromByte = 0;
eepromBits = 0;
}
}
}
break;
case EEPROM_READDATA:
case EEPROM_READDATA2:
// should we reset here?
eepromMode = EEPROM_IDLE;
break;
case EEPROM_WRITEDATA:
eepromBuffer[eepromByte] <<= 1;
eepromBuffer[eepromByte] |= bit;
eepromBits++;
if((eepromBits & 7) == 0) {
eepromByte++;
}
if(eepromBits == 0x40) {
eepromInUse = true;
// write data;
for(int i = 0; i < 8; i++) {
eepromData[(eepromAddress << 3) + i] = eepromBuffer[i];
}
systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
} else if(eepromBits == 0x41) {
eepromMode = EEPROM_IDLE;
eepromByte = 0;
eepromBits = 0;
}
break;
}
}

38
src/EEprom.h Normal file
View File

@ -0,0 +1,38 @@
// -*- C++ -*-
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef VBA_EEPROM_H
#define VBA_EEPROM_H
extern void eepromSaveGame(gzFile gzFile);
extern void eepromReadGame(gzFile gzFile, int version);
extern int eepromRead(u32 address);
extern void eepromWrite(u32 address, u8 value);
extern void eepromReset();
extern u8 eepromData[0x2000];
extern bool eepromInUse;
extern int eepromSize;
#define EEPROM_IDLE 0
#define EEPROM_READADDRESS 1
#define EEPROM_READDATA 2
#define EEPROM_READDATA2 3
#define EEPROM_WRITEDATA 4
#endif // VBA_EEPROM_H

259
src/Flash.cpp Normal file
View File

@ -0,0 +1,259 @@
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <stdio.h>
#include <memory.h>
#include "GBA.h"
#include "Globals.h"
#include "Flash.h"
#include "Sram.h"
#include "Util.h"
#define FLASH_READ_ARRAY 0
#define FLASH_CMD_1 1
#define FLASH_CMD_2 2
#define FLASH_AUTOSELECT 3
#define FLASH_CMD_3 4
#define FLASH_CMD_4 5
#define FLASH_CMD_5 6
#define FLASH_ERASE_COMPLETE 7
#define FLASH_PROGRAM 8
#define FLASH_SETBANK 9
u8 flashSaveMemory[0x20000];
int flashState = FLASH_READ_ARRAY;
int flashReadState = FLASH_READ_ARRAY;
int flashSize = 0x10000;
int flashDeviceID = 0x1b;
int flashManufacturerID = 0x32;
int flashBank = 0;
static variable_desc flashSaveData[] = {
{ &flashState, sizeof(int) },
{ &flashReadState, sizeof(int) },
{ &flashSaveMemory[0], 0x10000 },
{ NULL, 0 }
};
static variable_desc flashSaveData2[] = {
{ &flashState, sizeof(int) },
{ &flashReadState, sizeof(int) },
{ &flashSize, sizeof(int) },
{ &flashSaveMemory[0], 0x20000 },
{ NULL, 0 }
};
static variable_desc flashSaveData3[] = {
{ &flashState, sizeof(int) },
{ &flashReadState, sizeof(int) },
{ &flashSize, sizeof(int) },
{ &flashBank, sizeof(int) },
{ &flashSaveMemory[0], 0x20000 },
{ NULL, 0 }
};
void flashInit()
{
memset(flashSaveMemory, 0xff, sizeof(flashSaveMemory));
}
void flashReset()
{
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
flashBank = 0;
}
void flashSaveGame(gzFile gzFile)
{
utilWriteData(gzFile, flashSaveData3);
}
void flashReadGame(gzFile gzFile, int version)
{
if(version < SAVE_GAME_VERSION_5)
utilReadData(gzFile, flashSaveData);
else if(version < SAVE_GAME_VERSION_7) {
utilReadData(gzFile, flashSaveData2);
flashBank = 0;
flashSetSize(flashSize);
} else {
utilReadData(gzFile, flashSaveData3);
}
}
void flashSetSize(int size)
{
// log("Setting flash size to %d\n", size);
flashSize = size;
if(size == 0x10000) {
flashDeviceID = 0x1b;
flashManufacturerID = 0x32;
} else {
flashDeviceID = 0x13; //0x09;
flashManufacturerID = 0x62; //0xc2;
}
}
u8 flashRead(u32 address)
{
// log("Reading %08x from %08x\n", address, reg[15].I);
// log("Current read state is %d\n", flashReadState);
address &= 0xFFFF;
switch(flashReadState) {
case FLASH_READ_ARRAY:
return flashSaveMemory[(flashBank << 16) + address];
case FLASH_AUTOSELECT:
switch(address & 0xFF) {
case 0:
// manufacturer ID
return flashManufacturerID;
case 1:
// device ID
return flashDeviceID;
}
break;
case FLASH_ERASE_COMPLETE:
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
return 0xFF;
};
return 0;
}
void flashSaveDecide(u32 address, u8 byte)
{
// log("Deciding save type %08x\n", address);
if(address == 0x0e005555) {
saveType = 2;
cpuSaveGameFunc = flashWrite;
} else {
saveType = 1;
cpuSaveGameFunc = sramWrite;
}
(*cpuSaveGameFunc)(address, byte);
}
void flashDelayedWrite(u32 address, u8 byte)
{
saveType = 2;
cpuSaveGameFunc = flashWrite;
flashWrite(address, byte);
}
void flashWrite(u32 address, u8 byte)
{
// log("Writing %02x at %08x\n", byte, address);
// log("Current state is %d\n", flashState);
address &= 0xFFFF;
switch(flashState) {
case FLASH_READ_ARRAY:
if(address == 0x5555 && byte == 0xAA)
flashState = FLASH_CMD_1;
break;
case FLASH_CMD_1:
if(address == 0x2AAA && byte == 0x55)
flashState = FLASH_CMD_2;
else
flashState = FLASH_READ_ARRAY;
break;
case FLASH_CMD_2:
if(address == 0x5555) {
if(byte == 0x90) {
flashState = FLASH_AUTOSELECT;
flashReadState = FLASH_AUTOSELECT;
} else if(byte == 0x80) {
flashState = FLASH_CMD_3;
} else if(byte == 0xF0) {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
} else if(byte == 0xA0) {
flashState = FLASH_PROGRAM;
} else if(byte == 0xB0 && flashSize == 0x20000) {
flashState = FLASH_SETBANK;
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_CMD_3:
if(address == 0x5555 && byte == 0xAA) {
flashState = FLASH_CMD_4;
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_CMD_4:
if(address == 0x2AAA && byte == 0x55) {
flashState = FLASH_CMD_5;
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_CMD_5:
if(byte == 0x30) {
// SECTOR ERASE
memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)],
0,
0x1000);
systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
flashReadState = FLASH_ERASE_COMPLETE;
} else if(byte == 0x10) {
// CHIP ERASE
memset(flashSaveMemory, 0, flashSize);
systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
flashReadState = FLASH_ERASE_COMPLETE;
} else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_AUTOSELECT:
if(byte == 0xF0) {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
} else if(address == 0x5555 && byte == 0xAA)
flashState = FLASH_CMD_1;
else {
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
}
break;
case FLASH_PROGRAM:
flashSaveMemory[(flashBank<<16)+address] = byte;
systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED;
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
break;
case FLASH_SETBANK:
if(address == 0) {
flashBank = (byte & 1);
}
flashState = FLASH_READ_ARRAY;
flashReadState = FLASH_READ_ARRAY;
break;
}
}

35
src/Flash.h Normal file
View File

@ -0,0 +1,35 @@
// -*- C++ -*-
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef VBA_FLASH_H
#define VBA_FLASH_H
extern void flashSaveGame(gzFile gzFile);
extern void flashReadGame(gzFile gzFile, int version);
extern u8 flashRead(u32 address);
extern void flashWrite(u32 address, u8 byte);
extern void flashDelayedWrite(u32 address, u8 byte);
extern u8 flashSaveMemory[0x20000];
extern void flashSaveDecide(u32 address, u8 byte);
extern void flashReset();
extern void flashSetSize(int size);
extern void flashInit();
extern int flashSize;
#endif // VBA_FLASH_H

4027
src/GBA.cpp Normal file

File diff suppressed because it is too large Load Diff

147
src/GBA.h Normal file
View File

@ -0,0 +1,147 @@
// -*- C++ -*-
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef VBA_GBA_H
#define VBA_GBA_H
#include "System.h"
#define SAVE_GAME_VERSION_1 1
#define SAVE_GAME_VERSION_2 2
#define SAVE_GAME_VERSION_3 3
#define SAVE_GAME_VERSION_4 4
#define SAVE_GAME_VERSION_5 5
#define SAVE_GAME_VERSION_6 6
#define SAVE_GAME_VERSION_7 7
#define SAVE_GAME_VERSION_8 8
#define SAVE_GAME_VERSION SAVE_GAME_VERSION_8
typedef struct {
u8 *address;
u32 mask;
} memoryMap;
typedef union {
struct {
#ifdef WORDS_BIGENDIAN
u8 B3;
u8 B2;
u8 B1;
u8 B0;
#else
u8 B0;
u8 B1;
u8 B2;
u8 B3;
#endif
} B;
struct {
#ifdef WORDS_BIGENDIAN
u16 W1;
u16 W0;
#else
u16 W0;
u16 W1;
#endif
} W;
#ifdef WORDS_BIGENDIAN
volatile u32 I;
#else
u32 I;
#endif
} reg_pair;
#ifndef NO_GBA_MAP
extern memoryMap map[256];
#endif
extern reg_pair reg[45];
extern u8 biosProtected[4];
extern bool N_FLAG;
extern bool Z_FLAG;
extern bool C_FLAG;
extern bool V_FLAG;
extern bool armIrqEnable;
extern bool armState;
extern int armMode;
extern void (*cpuSaveGameFunc)(u32,u8);
extern u8 freezeWorkRAM[0x40000];
extern u8 freezeInternalRAM[0x8000];
extern bool CPUReadGSASnapshot(const char *);
extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *);
extern bool CPUWriteBatteryFile(const char *);
extern bool CPUReadBatteryFile(const char *);
extern bool CPUExportEepromFile(const char *);
extern bool CPUImportEepromFile(const char *);
extern bool CPUWritePNGFile(const char *);
extern bool CPUWriteBMPFile(const char *);
extern void CPUCleanUp();
extern void CPUUpdateRender();
extern bool CPUReadMemState(char *, int);
extern bool CPUReadState(const char *);
extern bool CPUWriteMemState(char *, int);
extern bool CPUWriteState(const char *);
extern int CPULoadRom(const char *);
extern void CPUUpdateRegister(u32, u16);
extern void CPUWriteHalfWord(u32, u16);
extern void CPUWriteByte(u32, u8);
extern void CPUInit(const char *,bool);
extern void CPUReset();
extern void CPULoop(int);
extern bool CPUCheckDMA(int,int);
extern bool CPUIsGBAImage(const char *);
extern bool CPUIsZipFile(const char *);
#ifdef PROFILING
extern void cpuProfil(char *buffer, int, u32, int);
extern void cpuEnableProfiling(int hz);
#endif
extern struct EmulatedSystem GBASystem;
#define R13_IRQ 18
#define R14_IRQ 19
#define SPSR_IRQ 20
#define R13_USR 26
#define R14_USR 27
#define R13_SVC 28
#define R14_SVC 29
#define SPSR_SVC 30
#define R13_ABT 31
#define R14_ABT 32
#define SPSR_ABT 33
#define R13_UND 34
#define R14_UND 35
#define SPSR_UND 36
#define R8_FIQ 37
#define R9_FIQ 38
#define R10_FIQ 39
#define R11_FIQ 40
#define R12_FIQ 41
#define R13_FIQ 42
#define R14_FIQ 43
#define SPSR_FIQ 44
#include "Cheats.h"
#include "Globals.h"
#include "EEprom.h"
#include "Flash.h"
#endif //VBA_GBA_H

427
src/GBAinline.h Normal file
View File

@ -0,0 +1,427 @@
// -*- C++ -*-
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team
// 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, or(at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef VBA_GBAinline_H
#define VBA_GBAinline_H
#include "System.h"
#include "Port.h"
#include "RTC.h"
#include "Sound.h"
extern bool cpuSramEnabled;
extern bool cpuFlashEnabled;
extern bool cpuEEPROMEnabled;
extern bool cpuEEPROMSensorEnabled;
extern bool cpuDmaHack;
extern bool cpuDmaHack2;
extern u32 cpuDmaLast;
extern int lspeed;
extern void LinkSStop(void);
#define CPUReadByteQuick(addr) \
map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
#define CPUReadHalfWordQuick(addr) \
READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
#define CPUReadMemoryQuick(addr) \
READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
inline u32 CPUReadMemory(u32 address)
{
#ifdef DEV_VERSION
if(address & 3) {
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned word read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
}
#endif
u32 value;
switch(address >> 24) {
case 0:
if(reg[15].I >> 24) {
if(address < 0x4000) {
#ifdef DEV_VERSION
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal word read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
value = READ32LE(((u32 *)&biosProtected));
}
else goto unreadable;
} else
value = READ32LE(((u32 *)&bios[address & 0x3FFC]));
break;
case 2:
value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC]));
break;
case 3:
value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC]));
break;
case 4:
if((address>=0x4000120||address<=0x4000126)&&lspeed)
LinkSStop();
if((address < 0x4000400) && ioReadable[address & 0x3fc]) {
if(ioReadable[(address & 0x3fc) + 2])
value = soundRead32(address & 0x3fC);
else
value = soundRead16(address & 0x3fc);
} else goto unreadable;
break;
case 5:
value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC]));
break;
case 6:
value = READ32LE(((u32 *)&vram[address & 0x1fffc]));
break;
case 7:
value = READ32LE(((u32 *)&oam[address & 0x3FC]));
break;
case 8:
case 9:
case 10:
case 11:
case 12:
value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
break;
case 13:
if(cpuEEPROMEnabled)
// no need to swap this
return eepromRead(address);
goto unreadable;
case 14:
if(cpuFlashEnabled | cpuSramEnabled)
// no need to swap this
return flashRead(address);
// default
default:
unreadable:
#ifdef DEV_VERSION
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal word read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
if(cpuDmaHack || cpuDmaHack2) {
value = cpuDmaLast;
} else {
if(armState) {
value = CPUReadMemoryQuick(reg[15].I);
} else {
value = CPUReadHalfWordQuick(reg[15].I) |
CPUReadHalfWordQuick(reg[15].I) << 16;
}
}
}
if(address & 3) {
#ifdef C_CORE
int shift = (address & 3) << 3;
value = (value >> shift) | (value << (32 - shift));
#else
#ifdef __GNUC__
asm("and $3, %%ecx;"
"shl $3 ,%%ecx;"
"ror %%cl, %0"
: "=r" (value)
: "r" (value), "c" (address));
#else
__asm {
mov ecx, address;
and ecx, 3;
shl ecx, 3;
ror [dword ptr value], cl;
}
#endif
#endif
}
return value;
}
extern u32 myROM[];
inline u32 CPUReadHalfWord(u32 address)
{
#ifdef DEV_VERSION
if(address & 1) {
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned halfword read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
}
#endif
u32 value;
switch(address >> 24) {
case 0:
if (reg[15].I >> 24) {
if(address < 0x4000) {
#ifdef DEV_VERSION
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal halfword read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
value = READ16LE(((u16 *)&biosProtected[address&2]));
} else goto unreadable;
} else
value = READ16LE(((u16 *)&bios[address & 0x3FFE]));
break;
case 2:
value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE]));
break;
case 3:
value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe]));
break;
case 4:
if((address>=0x4000120||address<=0x4000126)&&lspeed)
LinkSStop();
if((address < 0x4000400) && ioReadable[address & 0x3fe])
value = READ16LE(((u16 *)&ioMem[address & 0x3fe]));
else goto unreadable;
break;
case 5:
value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe]));
break;
case 6:
value = READ16LE(((u16 *)&vram[address & 0x1fffe]));
break;
case 7:
value = READ16LE(((u16 *)&oam[address & 0x3fe]));
break;
case 8:
case 9:
case 10:
case 11:
case 12:
if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
value = rtcRead(address);
else
value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
break;
case 13:
if(cpuEEPROMEnabled)
// no need to swap this
return eepromRead(address);
goto unreadable;
case 14:
if(cpuFlashEnabled | cpuSramEnabled)
// no need to swap this
return flashRead(address);
// default
default:
unreadable:
#ifdef DEV_VERSION
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal halfword read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
if(cpuDmaHack2 || cpuDmaHack) {
value = cpuDmaLast & 0xFFFF;
} else {
if(armState) {
value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
} else {
value = CPUReadHalfWordQuick(reg[15].I);
}
}
break;
}
if(address & 1) {
value = (value >> 8) | (value << 24);
}
return value;
}
inline u16 CPUReadHalfWordSigned(u32 address)
{
u16 value = CPUReadHalfWord(address);
if((address & 1))
value = (s8)value;
return value;
}
inline u8 CPUReadByte(u32 address)
{
switch(address >> 24) {
case 0:
if (reg[15].I >> 24) {
if(address < 0x4000) {
#ifdef DEV_VERSION
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal byte read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
return biosProtected[address & 3];
} else goto unreadable;
}
return bios[address & 0x3FFF];
case 2:
return workRAM[address & 0x3FFFF];
case 3:
return internalRAM[address & 0x7fff];
case 4:
if((address>=0x4000120||address<=0x4000126)&&lspeed)
LinkSStop();
if((address < 0x4000400) && ioReadable[address & 0x3ff])
return soundRead(address & 0x3ff);
else goto unreadable;
case 5:
return paletteRAM[address & 0x3ff];
case 6:
return vram[address & 0x1ffff];
case 7:
return oam[address & 0x3ff];
case 8:
case 9:
case 10:
case 11:
case 12:
return rom[address & 0x1FFFFFF];
case 13:
if(cpuEEPROMEnabled)
return eepromRead(address);
goto unreadable;
case 14:
if(cpuSramEnabled | cpuFlashEnabled)
return flashRead(address);
if(cpuEEPROMSensorEnabled) {
switch(address & 0x00008f00) {
case 0x8200:
return systemGetSensorX() & 255;
case 0x8300:
return (systemGetSensorX() >> 8)|0x80;
case 0x8400:
return systemGetSensorY() & 255;
case 0x8500:
return systemGetSensorY() >> 8;
}
}
// default
default:
unreadable:
#ifdef DEV_VERSION
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal byte read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
if(cpuDmaHack || cpuDmaHack2) {
return cpuDmaLast & 0xFF;
} else {
if(armState) {
return CPUReadByteQuick(reg[15].I+(address & 3));
} else {
return CPUReadByteQuick(reg[15].I+(address & 1));
}
}
break;
}
}
inline void CPUWriteMemory(u32 address, u32 value)
{
#ifdef DEV_VERSION
if(address & 3) {
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaliagned word write: %08x to %08x from %08x\n",
value,
address,
armMode ? armNextPC - 4 : armNextPC - 2);
}
}
#endif
switch(address >> 24) {
case 0x02:
#ifdef SDL
if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC]))
cheatsWriteMemory(address & 0x203FFFC,
value);
else
#endif
WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value);
break;
case 0x03:
#ifdef SDL
if(*((u32 *)&freezeInternalRAM[address & 0x7ffc]))
cheatsWriteMemory(address & 0x3007FFC,
value);
else
#endif
WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value);
break;
case 0x04:
if(address < 0x4000400) {
CPUUpdateRegister((address & 0x3FC), value & 0xFFFF);
CPUUpdateRegister((address & 0x3FC) + 2, (value >> 16));
} else goto unwritable;
break;
case 0x05:
WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
break;
case 0x06:
if(address & 0x10000)
WRITE32LE(((u32 *)&vram[address & 0x17ffc]), value);
else
WRITE32LE(((u32 *)&vram[address & 0x1fffc]), value);
break;
case 0x07:
WRITE32LE(((u32 *)&oam[address & 0x3fc]), value);
break;
case 0x0D:
if(cpuEEPROMEnabled) {
eepromWrite(address, value);
break;
}
goto unwritable;
case 0x0E:
if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) {
(*cpuSaveGameFunc)(address, (u8)value);
break;
}
// default
default:
unwritable:
#ifdef DEV_VERSION
if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
log("Illegal word write: %08x to %08x from %08x\n",
value,
address,
armMode ? armNextPC - 4 : armNextPC - 2);
}
#endif
break;
}
}
#endif //VBA_GBAinline_H

406
src/Gb_Apu/Blip_Buffer.cpp Normal file
View File

@ -0,0 +1,406 @@
// Blip_Buffer 0.4.0. http://www.slack.net/~ant/
#include "Blip_Buffer.h"
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
/* Copyright (C) 2003-2006 Shay Green. This module 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
module 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 module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
int const buffer_extra = blip_widest_impulse_ + 2;
Blip_Buffer::Blip_Buffer()
{
factor_ = LONG_MAX;
offset_ = 0;
buffer_ = 0;
buffer_size_ = 0;
sample_rate_ = 0;
reader_accum = 0;
bass_shift = 0;
clock_rate_ = 0;
bass_freq_ = 16;
length_ = 0;
// assumptions code makes about implementation-defined features
#ifndef NDEBUG
// right shift of negative value preserves sign
buf_t_ i = -0x7FFFFFFE;
assert( (i >> 1) == -0x3FFFFFFF );
// casting to short truncates to 16 bits and sign-extends
i = 0x18000;
assert( (short) i == -0x8000 );
#endif
}
Blip_Buffer::~Blip_Buffer()
{
free( buffer_ );
}
void Blip_Buffer::clear( int entire_buffer )
{
offset_ = 0;
reader_accum = 0;
if ( buffer_ )
{
long count = (entire_buffer ? buffer_size_ : samples_avail());
memset( buffer_, 0, (count + buffer_extra) * sizeof (buf_t_) );
}
}
Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
{
// start with maximum length that resampled time can represent
long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - buffer_extra - 64;
if ( msec != blip_max_length )
{
long s = (new_rate * (msec + 1) + 999) / 1000;
if ( s < new_size )
new_size = s;
else
assert( 0 ); // fails if requested buffer length exceeds limit
}
if ( buffer_size_ != new_size )
{
void* p = realloc( buffer_, (new_size + buffer_extra) * sizeof *buffer_ );
if ( !p )
return "Out of memory";
buffer_ = (buf_t_*) p;
}
buffer_size_ = new_size;
// update things based on the sample rate
sample_rate_ = new_rate;
length_ = new_size * 1000 / new_rate - 1;
if ( msec )
assert( length_ == msec ); // ensure length is same as that passed in
if ( clock_rate_ )
clock_rate( clock_rate_ );
bass_freq( bass_freq_ );
clear();
return 0; // success
}
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long clock_rate ) const
{
double ratio = (double) sample_rate_ / clock_rate;
long factor = (long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
return (blip_resampled_time_t) factor;
}
void Blip_Buffer::bass_freq( int freq )
{
bass_freq_ = freq;
int shift = 31;
if ( freq > 0 )
{
shift = 13;
long f = (freq << 16) / sample_rate_;
while ( (f >>= 1) && --shift ) { }
}
bass_shift = shift;
}
void Blip_Buffer::end_frame( blip_time_t t )
{
offset_ += t * factor_;
assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length
}
void Blip_Buffer::remove_silence( long count )
{
assert( count <= samples_avail() ); // tried to remove more samples than available
offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
}
long Blip_Buffer::count_samples( blip_time_t t ) const
{
unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
return (long) (last_sample - first_sample);
}
blip_time_t Blip_Buffer::count_clocks( long count ) const
{
if ( count > buffer_size_ )
count = buffer_size_;
blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
}
void Blip_Buffer::remove_samples( long count )
{
if ( count )
{
remove_silence( count );
// copy remaining samples to beginning and clear old samples
long remain = samples_avail() + buffer_extra;
memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
memset( buffer_ + remain, 0, count * sizeof *buffer_ );
}
}
// Blip_Synth_
Blip_Synth_::Blip_Synth_( short* p, int w ) :
impulses( p ),
width( w )
{
volume_unit_ = 0.0;
kernel_unit = 0;
buf = 0;
last_amp = 0;
delta_factor = 0;
}
static double const pi = 3.1415926535897932384626433832795029;
static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
{
if ( cutoff >= 0.999 )
cutoff = 0.999;
if ( treble < -300.0 )
treble = -300.0;
if ( treble > 5.0 )
treble = 5.0;
double const maxh = 4096.0;
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
double const to_angle = pi / 2 / maxh / oversample;
for ( int i = 0; i < count; i++ )
{
double angle = ((i - count) * 2 + 1) * to_angle;
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
double cos_nc_angle = cos( maxh * cutoff * angle );
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
double cos_angle = cos( angle );
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
double b = 2.0 - cos_angle - cos_angle;
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
}
}
void blip_eq_t::generate( float* out, int count ) const
{
// lower cutoff freq for narrow kernels with their wider transition band
// (8 points->1.49, 16 points->1.15)
double oversample = blip_res * 2.25 / count + 0.85;
double half_rate = sample_rate * 0.5;
if ( cutoff_freq )
oversample = half_rate / cutoff_freq;
double cutoff = rolloff_freq * oversample / half_rate;
gen_sinc( out, count, blip_res * oversample, treble, cutoff );
// apply (half of) hamming window
double to_fraction = pi / (count - 1);
for ( int i = count; i--; )
out [i] *= 0.54 - 0.46 * cos( i * to_fraction );
}
void Blip_Synth_::adjust_impulse()
{
// sum pairs for each phase and add error correction to end of first half
int const size = impulses_size();
for ( int p = blip_res; p-- >= blip_res / 2; )
{
int p2 = blip_res - 2 - p;
long error = kernel_unit;
for ( int i = 1; i < size; i += blip_res )
{
error -= impulses [i + p ];
error -= impulses [i + p2];
}
if ( p == p2 )
error /= 2; // phase = 0.5 impulse uses same half for both sides
impulses [size - blip_res + p] += error;
//printf( "error: %ld\n", error );
}
//for ( int i = blip_res; i--; printf( "\n" ) )
// for ( int j = 0; j < width / 2; j++ )
// printf( "%5ld,", impulses [j * blip_res + i + 1] );
}
void Blip_Synth_::treble_eq( blip_eq_t const& eq )
{
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
int const half_size = blip_res / 2 * (width - 1);
eq.generate( &fimpulse [blip_res], half_size );
int i;
// need mirror slightly past center for calculation
for ( i = blip_res; i--; )
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
// starts at 0
for ( i = 0; i < blip_res; i++ )
fimpulse [i] = 0.0f;
// find rescale factor
double total = 0.0;
for ( i = 0; i < half_size; i++ )
total += fimpulse [blip_res + i];
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
//double const base_unit = 37888.0; // allows treble to +5 dB
double const base_unit = 32768.0; // necessary for blip_unscaled to work
double rescale = base_unit / 2 / total;
kernel_unit = (long) base_unit;
// integrate, first difference, rescale, convert to int
double sum = 0.0;
double next = 0.0;
int const impulses_size = this->impulses_size();
for ( i = 0; i < impulses_size; i++ )
{
impulses [i] = (short) floor( (next - sum) * rescale + 0.5 );
sum += fimpulse [i];
next += fimpulse [i + blip_res];
}
adjust_impulse();
// volume might require rescaling
double vol = volume_unit_;
if ( vol )
{
volume_unit_ = 0.0;
volume_unit( vol );
}
}
void Blip_Synth_::volume_unit( double new_unit )
{
if ( new_unit != volume_unit_ )
{
// use default eq if it hasn't been set yet
if ( !kernel_unit )
treble_eq( -8.0 );
volume_unit_ = new_unit;
double factor = new_unit * (1L << blip_sample_bits) / kernel_unit;
if ( factor > 0.0 )
{
int shift = 0;
// if unit is really small, might need to attenuate kernel
while ( factor < 2.0 )
{
shift++;
factor *= 2.0;
}
if ( shift )
{
kernel_unit >>= shift;
assert( kernel_unit > 0 ); // fails if volume unit is too low
// keep values positive to avoid round-towards-zero of sign-preserving
// right shift for negative values
long offset = 0x8000 + (1 << (shift - 1));
long offset2 = 0x8000 >> shift;
for ( int i = impulses_size(); i--; )
impulses [i] = (short) (((impulses [i] + offset) >> shift) - offset2);
adjust_impulse();
}
}
delta_factor = (int) floor( factor + 0.5 );
//printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit );
}
}
long Blip_Buffer::read_samples( blip_sample_t* out, long max_samples, int stereo )
{
long count = samples_avail();
if ( count > max_samples )
count = max_samples;
if ( count )
{
int const sample_shift = blip_sample_bits - 16;
int const bass_shift = this->bass_shift;
long accum = reader_accum;
buf_t_* in = buffer_;
if ( !stereo )
{
for ( long n = count; n--; )
{
long s = accum >> sample_shift;
accum -= accum >> bass_shift;
accum += *in++;
*out++ = (blip_sample_t) s;
// clamp sample
if ( (blip_sample_t) s != s )
out [-1] = (blip_sample_t) (0x7FFF - (s >> 24));
}
}
else
{
for ( long n = count; n--; )
{
long s = accum >> sample_shift;
accum -= accum >> bass_shift;
accum += *in++;
*out = (blip_sample_t) s;
out += 2;
// clamp sample
if ( (blip_sample_t) s != s )
out [-2] = (blip_sample_t) (0x7FFF - (s >> 24));
}
}
reader_accum = accum;
remove_samples( count );
}
return count;
}
void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
{
buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
int const sample_shift = blip_sample_bits - 16;
int prev = 0;
while ( count-- )
{
long s = (long) *in++ << sample_shift;
*out += s - prev;
prev = s;
++out;
}
*out -= prev;
}

354
src/Gb_Apu/Blip_Buffer.h Normal file
View File

@ -0,0 +1,354 @@
// Band-limited sound synthesis and buffering
// Blip_Buffer 0.4.0
#ifndef BLIP_BUFFER_H
#define BLIP_BUFFER_H
// Time unit at source clock rate
typedef long blip_time_t;
// Output samples are 16-bit signed, with a range of -32768 to 32767
typedef short blip_sample_t;
enum { blip_sample_max = 32767 };
class Blip_Buffer {
public:
typedef const char* blargg_err_t;
// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
// isn't enough memory, returns error without affecting current buffer setup.
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
// Set number of source time units per second
void clock_rate( long );
// End current time frame of specified duration and make its samples available
// (along with any still-unread samples) for reading with read_samples(). Begins
// a new time frame at the end of the current frame.
void end_frame( blip_time_t time );
// Read at most 'max_samples' out of buffer into 'dest', removing them from from
// the buffer. Returns number of samples actually read and removed. If stereo is
// true, increments 'dest' one extra time after writing each sample, to allow
// easy interleving of two channels into a stereo output buffer.
long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
// Additional optional features
// Current output sample rate
long sample_rate() const;
// Length of buffer, in milliseconds
int length() const;
// Number of source time units per second
long clock_rate() const;
// Set frequency high-pass filter frequency, where higher values reduce bass more
void bass_freq( int frequency );
// Number of samples delay from synthesis to samples read out
int output_latency() const;
// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
// false, just clears out any samples waiting rather than the entire buffer.
void clear( int entire_buffer = 1 );
// Number of samples available for reading with read_samples()
long samples_avail() const;
// Remove 'count' samples from those waiting to be read
void remove_samples( long count );
// Experimental features
// Number of raw samples that can be mixed within frame of specified duration.
long count_samples( blip_time_t duration ) const;
// Mix 'count' samples from 'buf' into buffer.
void mix_samples( blip_sample_t const* buf, long count );
// Count number of clocks needed until 'count' samples will be available.
// If buffer can't even hold 'count' samples, returns number of clocks until
// buffer becomes full.
blip_time_t count_clocks( long count ) const;
// not documented yet
typedef unsigned long blip_resampled_time_t;
void remove_silence( long count );
blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
public:
Blip_Buffer();
~Blip_Buffer();
// Deprecated
typedef blip_resampled_time_t resampled_time_t;
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
private:
// noncopyable
Blip_Buffer( const Blip_Buffer& );
Blip_Buffer& operator = ( const Blip_Buffer& );
public:
typedef long buf_t_;
unsigned long factor_;
blip_resampled_time_t offset_;
buf_t_* buffer_;
long buffer_size_;
private:
long reader_accum;
int bass_shift;
long sample_rate_;
long clock_rate_;
int bass_freq_;
int length_;
friend class Blip_Reader;
};
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
// but reduce maximum buffer size.
#ifndef BLIP_BUFFER_ACCURACY
#define BLIP_BUFFER_ACCURACY 16
#endif
// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
// noticeable broadband noise when synthesizing high frequency square waves.
// Affects size of Blip_Synth objects since they store the waveform directly.
#ifndef BLIP_PHASE_BITS
#define BLIP_PHASE_BITS 6
#endif
// Internal
typedef unsigned long blip_resampled_time_t;
int const blip_widest_impulse_ = 16;
int const blip_res = 1 << BLIP_PHASE_BITS;
class blip_eq_t;
class Blip_Synth_ {
double volume_unit_;
short* const impulses;
int const width;
long kernel_unit;
int impulses_size() const { return blip_res / 2 * width + 1; }
void adjust_impulse();
public:
Blip_Buffer* buf;
int last_amp;
int delta_factor;
Blip_Synth_( short* impulses, int width );
void treble_eq( blip_eq_t const& );
void volume_unit( double );
};
// Quality level. Start with blip_good_quality.
const int blip_med_quality = 8;
const int blip_good_quality = 12;
const int blip_high_quality = 16;
// Range specifies the greatest expected change in amplitude. Calculate it
// by finding the difference between the maximum and minimum expected
// amplitudes (max - min).
template<int quality,int range>
class Blip_Synth {
public:
// Set overall volume of waveform
void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
// Configure low-pass filter (see notes.txt)
void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
// Get/set Blip_Buffer used for output
Blip_Buffer* output() const { return impl.buf; }
void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
// Update amplitude of waveform at given time. Using this requires a separate
// Blip_Synth for each waveform.
void update( blip_time_t time, int amplitude );
// Low-level interface
// Add an amplitude transition of specified delta, optionally into specified buffer
// rather than the one set with output(). Delta can be positive or negative.
// The actual change in amplitude is delta * (volume / range)
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
// Works directly in terms of fractional output samples. Contact author for more.
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
// Same as offset(), except code is inlined for higher performance
void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}
void offset_inline( blip_time_t t, int delta ) const {
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}
public:
Blip_Synth() : impl( impulses, quality ) { }
private:
typedef short imp_t;
imp_t impulses [blip_res * (quality / 2) + 1];
Blip_Synth_ impl;
};
// Low-pass equalization parameters
class blip_eq_t {
public:
// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
// treble, small positive values (0 to 5.0) increase treble.
blip_eq_t( double treble_db = 0 );
// See notes.txt
blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
private:
double treble;
long rolloff_freq;
long sample_rate;
long cutoff_freq;
void generate( float* out, int count ) const;
friend class Blip_Synth_;
};
int const blip_sample_bits = 30;
// Optimized inline sample reader for custom sample formats and mixing of Blip_Buffer samples
class Blip_Reader {
public:
// Begin reading samples from buffer. Returns value to pass to next() (can
// be ignored if default bass_freq is acceptable).
int begin( Blip_Buffer& );
// Current sample
long read() const { return accum >> (blip_sample_bits - 16); }
// Current raw sample in full internal resolution
long read_raw() const { return accum; }
// Advance to next sample
void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
// End reading samples from buffer. The number of samples read must now be removed
// using Blip_Buffer::remove_samples().
void end( Blip_Buffer& b ) { b.reader_accum = accum; }
private:
const Blip_Buffer::buf_t_* buf;
long accum;
};
// End of public interface
#include <assert.h>
// Compatibility with older version
const long blip_unscaled = 65535;
const int blip_low_quality = blip_med_quality;
const int blip_best_quality = blip_high_quality;
#define BLIP_FWD( i ) { \
long t0 = i0 * delta + buf [fwd + i]; \
long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i]; \
i0 = imp [blip_res * (i + 2)]; \
buf [fwd + i] = t0; \
buf [fwd + 1 + i] = t1; }
#define BLIP_REV( r ) { \
long t0 = i0 * delta + buf [rev - r]; \
long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r]; \
i0 = imp [blip_res * (r - 1)]; \
buf [rev - r] = t0; \
buf [rev + 1 - r] = t1; }
template<int quality,int range>
inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
int delta, Blip_Buffer* blip_buf ) const
{
// Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
// need for a longer buffer as set by set_sample_rate().
assert( (long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
delta *= impl.delta_factor;
int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
imp_t const* imp = impulses + blip_res - phase;
long* buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
long i0 = *imp;
int const fwd = (blip_widest_impulse_ - quality) / 2;
int const rev = fwd + quality - 2;
BLIP_FWD( 0 )
if ( quality > 8 ) BLIP_FWD( 2 )
if ( quality > 12 ) BLIP_FWD( 4 )
{
int const mid = quality / 2 - 1;
long t0 = i0 * delta + buf [fwd + mid - 1];
long t1 = imp [blip_res * mid] * delta + buf [fwd + mid];
imp = impulses + phase;
i0 = imp [blip_res * mid];
buf [fwd + mid - 1] = t0;
buf [fwd + mid] = t1;
}
if ( quality > 12 ) BLIP_REV( 6 )
if ( quality > 8 ) BLIP_REV( 4 )
BLIP_REV( 2 )
long t0 = i0 * delta + buf [rev];
long t1 = *imp * delta + buf [rev + 1];
buf [rev] = t0;
buf [rev + 1] = t1;
}
#undef BLIP_FWD
#undef BLIP_REV
template<int quality,int range>
void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
{
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}
template<int quality,int range>
void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
{
int delta = amp - impl.last_amp;
impl.last_amp = amp;
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}
inline blip_eq_t::blip_eq_t( double t ) :
treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
inline int Blip_Buffer::length() const { return length_; }
inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
inline long Blip_Buffer::sample_rate() const { return sample_rate_; }
inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
inline long Blip_Buffer::clock_rate() const { return clock_rate_; }
inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
{
buf = blip_buf.buffer_;
accum = blip_buf.reader_accum;
return blip_buf.bass_shift;
}
int const blip_max_length = 0;
int const blip_default_length = 250;
#endif

204
src/Gb_Apu/Blip_Synth.h Normal file
View File

@ -0,0 +1,204 @@
// Blip_Synth and Blip_Wave are waveform transition synthesizers for adding
// waveforms to a Blip_Buffer.
// Blip_Buffer 0.3.3. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
#ifndef BLIP_SYNTH_H
#define BLIP_SYNTH_H
#ifndef BLIP_BUFFER_H
#include "Blip_Buffer.h"
#endif
// Quality level. Higher levels are slower, and worse in a few cases.
// Use blip_good_quality as a starting point.
const int blip_low_quality = 1;
const int blip_med_quality = 2;
const int blip_good_quality = 3;
const int blip_high_quality = 4;
// Blip_Synth is a transition waveform synthesizer which adds band-limited
// offsets (transitions) into a Blip_Buffer. For a simpler interface, use
// Blip_Wave (below).
//
// Range specifies the greatest expected offset that will occur. For a
// waveform that goes between +amp and -amp, range should be amp * 2 (half
// that if it only goes between +amp and 0). When range is large, a higher
// accuracy scheme is used; to force this even when range is small, pass
// the negative of range (i.e. -range).
template<int quality,int range>
class Blip_Synth {
BOOST_STATIC_ASSERT( 1 <= quality && quality <= 5 );
BOOST_STATIC_ASSERT( -32768 <= range && range <= 32767 );
enum {
abs_range = (range < 0) ? -range : range,
fine_mode = (range > 512 || range < 0),
width = (quality < 5 ? quality * 4 : Blip_Buffer::widest_impulse_),
res = 1 << blip_res_bits_,
impulse_size = width / 2 * (fine_mode + 1),
base_impulses_size = width / 2 * (res / 2 + 1),
fine_bits = (fine_mode ? (abs_range <= 64 ? 2 : abs_range <= 128 ? 3 :
abs_range <= 256 ? 4 : abs_range <= 512 ? 5 : abs_range <= 1024 ? 6 :
abs_range <= 2048 ? 7 : 8) : 0)
};
blip_pair_t_ impulses [impulse_size * res * 2 + base_impulses_size];
Blip_Impulse_ impulse;
public:
Blip_Synth() { impulse.init( impulses, width, res, fine_bits ); }
// Configure low-pass filter (see notes.txt). Not optimized for real-time control
void treble_eq( const blip_eq_t& eq ) { impulse.treble_eq( eq ); }
// Set volume of a transition at amplitude 'range' by setting volume_unit
// to v / range
void volume( double v ) { impulse.volume_unit( v * (1.0 / abs_range) ); }
// Set base volume unit of transitions, where 1.0 is a full swing between the
// positive and negative extremes. Not optimized for real-time control.
void volume_unit( double unit ) { impulse.volume_unit( unit ); }
// Default Blip_Buffer used for output when none is specified for a given call
Blip_Buffer* output() const { return impulse.buf; }
void output( Blip_Buffer* b ) { impulse.buf = b; }
// Add an amplitude offset (transition) with an amplitude of delta * volume_unit
// into the specified buffer (default buffer if none specified) at the
// specified source time. Amplitude can be positive or negative. To increase
// performance by inlining code at the call site, use offset_inline().
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
void offset_resampled( blip_resampled_time_t t, int o ) const {
offset_resampled( t, o, impulse.buf );
}
void offset( blip_time_t t, int delta ) const {
offset( t, delta, impulse.buf );
}
void offset_inline( blip_time_t time, int delta, Blip_Buffer* buf ) const {
offset_resampled( time * buf->factor_ + buf->offset_, delta, buf );
}
void offset_inline( blip_time_t time, int delta ) const {
offset_inline( time, delta, impulse.buf );
}
};
// Blip_Wave is a synthesizer for adding a *single* waveform to a Blip_Buffer.
// A wave is built from a series of delays and new amplitudes. This provides a
// simpler interface than Blip_Synth.
template<int quality,int range>
class Blip_Wave {
Blip_Synth<quality,range> synth;
blip_time_t time_;
int last_amp;
public:
// Start wave at time 0 and amplitude 0
Blip_Wave() : time_( 0 ), last_amp( 0 ) { }
// See Blip_Synth for description
void volume( double v ) { synth.volume( v ); }
void volume_unit( double v ) { synth.volume_unit( v ); }
void treble_eq( const blip_eq_t& eq){ synth.treble_eq( eq ); }
Blip_Buffer* output() const { return synth.output(); }
void output( Blip_Buffer* b ) { synth.output( b ); if ( !b ) time_ = last_amp = 0; }
// Current time in frame
blip_time_t time() const { return time_; }
void time( blip_time_t t ) { time_ = t; }
// Current amplitude of wave
int amplitude() const { return last_amp; }
void amplitude( int );
// Move forward by 't' time units
void delay( blip_time_t t ) { time_ += t; }
// End time frame of specified duration. Localize time to new frame.
void end_frame( blip_time_t duration ) {
assert(( "Blip_Wave::end_frame(): Wave hadn't yet been run for entire frame",
duration <= time_ ));
time_ -= duration;
}
};
// End of public interface
template<int quality,int range>
void Blip_Wave<quality,range>::amplitude( int amp ) {
int delta = amp - last_amp;
last_amp = amp;
synth.offset_inline( time_, delta );
}
template<int quality,int range>
inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
int delta, Blip_Buffer* blip_buf ) const
{
typedef blip_pair_t_ pair_t;
unsigned sample_index = (time >> BLIP_BUFFER_ACCURACY) & ~1;
assert(( "Blip_Synth/Blip_wave: Went past end of buffer",
sample_index < blip_buf->buffer_size_ ));
enum { const_offset = Blip_Buffer::widest_impulse_ / 2 - width / 2 };
pair_t* buf = (pair_t*) &blip_buf->buffer_ [const_offset + sample_index];
enum { shift = BLIP_BUFFER_ACCURACY - blip_res_bits_ };
enum { mask = res * 2 - 1 };
const pair_t* imp = &impulses [((time >> shift) & mask) * impulse_size];
pair_t offset = impulse.offset * delta;
if ( !fine_bits )
{
// normal mode
for ( int n = width / 4; n; --n )
{
pair_t t0 = buf [0] - offset;
pair_t t1 = buf [1] - offset;
t0 += imp [0] * delta;
t1 += imp [1] * delta;
imp += 2;
buf [0] = t0;
buf [1] = t1;
buf += 2;
}
}
else
{
// fine mode
enum { sub_range = 1 << fine_bits };
delta += sub_range / 2;
int delta2 = (delta & (sub_range - 1)) - sub_range / 2;
delta >>= fine_bits;
for ( int n = width / 4; n; --n )
{
pair_t t0 = buf [0] - offset;
pair_t t1 = buf [1] - offset;
t0 += imp [0] * delta2;
t0 += imp [1] * delta;
t1 += imp [2] * delta2;
t1 += imp [3] * delta;
imp += 4;
buf [0] = t0;
buf [1] = t1;
buf += 2;
}
}
}
template<int quality,int range>
void Blip_Synth<quality,range>::offset( blip_time_t time, int delta, Blip_Buffer* buf ) const {
offset_resampled( time * buf->factor_ + buf->offset_, delta, buf );
}
#endif

504
src/Gb_Apu/COPYING Normal file
View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
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 and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, 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 library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete 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 distribute a copy of this License along with the
Library.
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 Library or any portion
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
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 Library, 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 Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you 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.
If distribution of 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 satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be 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.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library 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.
9. 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 Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
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 with
this License.
11. 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 Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library 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 Library.
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.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library 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.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
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 Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
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
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. 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 LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. 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 library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library 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 library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

318
src/Gb_Apu/Gb_Apu.cpp Normal file
View File

@ -0,0 +1,318 @@
// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
#include "Gb_Apu.h"
#include <string.h>
/* Copyright (C) 2003-2006 Shay Green. This module 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
module 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 module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include BLARGG_SOURCE_BEGIN
int const vol_reg = 0xFF24;
int const status_reg = 0xFF26;
Gb_Apu::Gb_Apu()
{
square1.synth = &square_synth;
square2.synth = &square_synth;
wave.synth = &other_synth;
noise.synth = &other_synth;
oscs [0] = &square1;
oscs [1] = &square2;
oscs [2] = &wave;
oscs [3] = &noise;
for ( int i = 0; i < osc_count; i++ )
{
Gb_Osc& osc = *oscs [i];
osc.regs = &regs [i * 5];
osc.output = NULL;
osc.outputs [0] = NULL;
osc.outputs [1] = NULL;
osc.outputs [2] = NULL;
osc.outputs [3] = NULL;
}
volume( 1.0 );
reset();
}
Gb_Apu::~Gb_Apu()
{
}
void Gb_Apu::treble_eq( const blip_eq_t& eq )
{
square_synth.treble_eq( eq );
other_synth.treble_eq( eq );
}
void Gb_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
{
require( (unsigned) index < osc_count );
require( (center && left && right) || (!center && !left && !right) );
Gb_Osc& osc = *oscs [index];
osc.outputs [1] = right;
osc.outputs [2] = left;
osc.outputs [3] = center;
osc.output = osc.outputs [osc.output_select];
}
void Gb_Apu::output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
{
for ( int i = 0; i < osc_count; i++ )
osc_output( i, center, left, right );
}
void Gb_Apu::update_volume()
{
// to do: doesn't handle differing left/right global volume
int data = regs [vol_reg - start_addr];
double vol = (max( data & 7, data >> 4 & 7 ) + 1) * volume_unit;
square_synth.volume( vol );
other_synth.volume( vol );
}
static unsigned char const powerup_regs [0x30] = {
0x80,0x3F,0x00,0xFF,0xBF, // square 1
0xFF,0x3F,0x00,0xFF,0xBF, // square 2
0x7F,0xFF,0x9F,0xFF,0xBF, // wave
0xFF,0xFF,0x00,0x00,0xBF, // noise
0x00, // left/right enables
0x77, // master volume
0x80, // power
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table
0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA
};
void Gb_Apu::reset(bool igba)
{
next_frame_time = 0;
last_time = 0;
frame_count = 0;
stereo_found = false;
square1.reset();
square2.reset();
wave.reset(gba = igba);
noise.reset();
noise.bits = 1;
wave.wave_pos = 0;
// avoid click at beginning
regs [vol_reg - start_addr] = 0x77;
update_volume();
regs [status_reg - start_addr] = 0x01; // force power
write_register( 0, status_reg, 0x00 );
}
// to do: remove
//static unsigned long abs_time;
void Gb_Apu::run_until( gb_time_t end_time )
{
require( end_time >= last_time ); // end_time must not be before previous time
if ( end_time == last_time )
return;
while ( true )
{
gb_time_t time = next_frame_time;
if ( time > end_time )
time = end_time;
// run oscillators
for ( int i = 0; i < osc_count; ++i )
{
Gb_Osc& osc = *oscs [i];
if ( osc.output )
{
int playing = false;
if ( osc.enabled && osc.volume &&
(!(osc.regs [4] & osc.len_enabled_mask) || osc.length) )
playing = -1;
if ( osc.output != osc.outputs [3] )
stereo_found = true;
switch ( i )
{
case 0: square1.run( last_time, time, playing ); break;
case 1: square2.run( last_time, time, playing ); break;
case 2: wave .run( last_time, time, playing ); break;
case 3: noise .run( last_time, time, playing ); break;
}
}
}
last_time = time;
if ( time == end_time )
break;
next_frame_time += 4194304 / 256; // 256 Hz
// 256 Hz actions
square1.clock_length();
square2.clock_length();
wave.clock_length();
noise.clock_length();
frame_count = (frame_count + 1) & 3;
if ( frame_count == 0 )
{
// 64 Hz actions
square1.clock_envelope();
square2.clock_envelope();
noise.clock_envelope();
}
if ( frame_count & 1 )
square1.clock_sweep(); // 128 Hz action
}
}
bool Gb_Apu::end_frame( gb_time_t end_time )
{
if ( end_time > last_time )
run_until( end_time );
//abs_time += end_time;
assert( next_frame_time >= end_time );
next_frame_time -= end_time;
assert( last_time >= end_time );
last_time -= end_time;
bool result = stereo_found;
stereo_found = false;
return result;
}
void Gb_Apu::write_register( gb_time_t time, gb_addr_t addr, int data )
{
require( (unsigned) data < 0x100 );
int reg = addr - start_addr;
if ( (unsigned) reg >= register_count )
return;
run_until( time );
int old_reg = regs [reg];
regs [reg] = data;
if ( addr < vol_reg )
{
write_osc( reg / 5, reg, data );
}
else if ( addr == vol_reg && data != old_reg ) // global volume
{
// return all oscs to 0
for ( int i = 0; i < osc_count; i++ )
{
Gb_Osc& osc = *oscs [i];
int amp = osc.last_amp;
osc.last_amp = 0;
if ( amp && osc.enabled && osc.output )
other_synth.offset( time, -amp, osc.output );
}
if ( wave.outputs [3] )
other_synth.offset( time, 30, wave.outputs [3] );
update_volume();
if ( wave.outputs [3] )
other_synth.offset( time, -30, wave.outputs [3] );
// oscs will update with new amplitude when next run
}
else if ( addr == 0xFF25 || addr == status_reg )
{
int mask = (regs [status_reg - start_addr] & 0x80) ? ~0 : 0;
int flags = regs [0xFF25 - start_addr] & mask;
// left/right assignments
for ( int i = 0; i < osc_count; i++ )
{
Gb_Osc& osc = *oscs [i];
osc.enabled &= mask;
int bits = flags >> i;
Blip_Buffer* old_output = osc.output;
osc.output_select = (bits >> 3 & 2) | (bits & 1);
osc.output = osc.outputs [osc.output_select];
if ( osc.output != old_output )
{
int amp = osc.last_amp;
osc.last_amp = 0;
if ( amp && old_output )
other_synth.offset( time, -amp, old_output );
}
}
if ( addr == status_reg && data != old_reg )
{
if ( !(data & 0x80) )
{
for ( int i = 0; i < (int) sizeof powerup_regs; i++ )
{
if ( i != status_reg - start_addr )
write_register( time, i + start_addr, powerup_regs [i] );
}
}
else
{
//dprintf( "APU powered on\n" );
}
}
}
else if ( addr >= 0xFF30 )
{
int bank;
if (gba) bank = (wave.wave_bank ^ 0x20);
else bank = 0;
int index = (addr & 0x0F) * 2 + bank;
wave.wave [index] = data >> 4;
wave.wave [index + 1] = data & 0x0F;
}
}
int Gb_Apu::read_register( gb_time_t time, gb_addr_t addr )
{
run_until( time );
int index = addr - start_addr;
require( (unsigned) index < register_count );
int data = regs [index];
if ( addr == status_reg )
{
data = (data & 0x80) | 0x70;
for ( int i = 0; i < osc_count; i++ )
{
const Gb_Osc& osc = *oscs [i];
if ( osc.enabled && (osc.length || !(osc.regs [4] & osc.len_enabled_mask)) )
data |= 1 << i;
}
} else if ( gba && addr >= 0xff30 ) {
int bank = (wave.wave_bank ^ 0x20);
int index = (addr & 0x0f) * 2;
data = wave.wave [bank + index] << 4;
data |= wave.wave [bank + index + 1];
}
return data;
}

99
src/Gb_Apu/Gb_Apu.h Normal file
View File

@ -0,0 +1,99 @@
// Nintendo Game Boy PAPU sound chip emulator
// Gb_Snd_Emu 0.1.4
#ifndef GB_APU_H
#define GB_APU_H
typedef long gb_time_t; // clock cycle count
typedef unsigned gb_addr_t; // 16-bit address
#include "Gb_Oscs.h"
class Gb_Apu {
public:
// Set overall volume of all oscillators, where 1.0 is full volume
void volume( double );
// Set treble equalization
void treble_eq( const blip_eq_t& );
// Outputs can be assigned to a single buffer for mono output, or to three
// buffers for stereo output (using Stereo_Buffer to do the mixing).
// Assign all oscillator outputs to specified buffer(s). If buffer
// is NULL, silences all oscillators.
void output( Blip_Buffer* mono );
void output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right );
// Assign single oscillator output to buffer(s). Valid indicies are 0 to 3,
// which refer to Square 1, Square 2, Wave, and Noise. If buffer is NULL,
// silences oscillator.
enum { osc_count = 4 };
void osc_output( int index, Blip_Buffer* mono );
void osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right );
// Reset oscillators and internal state
void reset(bool gba = false);
// Reads and writes at addr must satisfy start_addr <= addr <= end_addr
enum { start_addr = 0xFF10 };
enum { end_addr = 0xFF3f };
enum { register_count = end_addr - start_addr + 1 };
// Write 'data' to address at specified time
void write_register( gb_time_t, gb_addr_t, int data );
// Read from address at specified time
int read_register( gb_time_t, gb_addr_t );
// Run all oscillators up to specified time, end current time frame, then
// start a new frame at time 0. Returns true if any oscillators added
// sound to one of the left/right buffers, false if they only added
// to the center buffer.
bool end_frame( gb_time_t );
public:
Gb_Apu();
~Gb_Apu();
private:
// noncopyable
Gb_Apu( const Gb_Apu& );
Gb_Apu& operator = ( const Gb_Apu& );
Gb_Osc* oscs [osc_count];
gb_time_t next_frame_time;
gb_time_t last_time;
double volume_unit;
int frame_count;
bool stereo_found;
Gb_Square square1;
Gb_Square square2;
Gb_Wave wave;
Gb_Noise noise;
BOOST::uint8_t regs [register_count];
Gb_Square::Synth square_synth; // used by squares
Gb_Wave::Synth other_synth; // used by wave and noise
bool gba; // enable GBA extensions to wave channel
void update_volume();
void run_until( gb_time_t );
void write_osc( int index, int reg, int data );
};
inline void Gb_Apu::output( Blip_Buffer* b ) { output( b, b, b ); }
inline void Gb_Apu::osc_output( int i, Blip_Buffer* b ) { osc_output( i, b, b, b ); }
inline void Gb_Apu::volume( double vol )
{
volume_unit = 0.60 / osc_count / 15 /*steps*/ / 2 /*?*/ / 8 /*master vol range*/ * vol;
update_volume();
}
#endif

360
src/Gb_Apu/Gb_Oscs.cpp Normal file
View File

@ -0,0 +1,360 @@
// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
#include "Gb_Apu.h"
#include <string.h>
/* Copyright (C) 2003-2006 Shay Green. This module 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
module 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 module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include BLARGG_SOURCE_BEGIN
// Gb_Osc
void Gb_Osc::reset()
{
delay = 0;
last_amp = 0;
length = 0;
output_select = 3;
output = outputs [output_select];
}
void Gb_Osc::clock_length()
{
if ( (regs [4] & len_enabled_mask) && length )
length--;
}
// Gb_Env
void Gb_Env::clock_envelope()
{
if ( env_delay && !--env_delay )
{
env_delay = regs [2] & 7;
int v = volume - 1 + (regs [2] >> 2 & 2);
if ( (unsigned) v < 15 )
volume = v;
}
}
bool Gb_Env::write_register( int reg, int data )
{
switch ( reg )
{
case 1:
length = 64 - (regs [1] & 0x3f);
break;
case 2:
if ( !(data >> 4) )
enabled = false;
break;
case 4:
if ( data & trigger )
{
env_delay = regs [2] & 7;
volume = regs [2] >> 4;
enabled = true;
if ( length == 0 )
length = 64;
return true;
}
}
return false;
}
// Gb_Square
void Gb_Square::reset()
{
phase = 0;
sweep_freq = 0;
sweep_delay = 0;
Gb_Env::reset();
}
void Gb_Square::clock_sweep()
{
int sweep_period = (regs [0] & period_mask) >> 4;
if ( sweep_period && sweep_delay && !--sweep_delay )
{
sweep_delay = sweep_period;
regs [3] = sweep_freq & 0xFF;
regs [4] = (regs [4] & ~0x07) | (sweep_freq >> 8 & 0x07);
int offset = sweep_freq >> (regs [0] & shift_mask);
if ( regs [0] & 0x08 )
offset = -offset;
sweep_freq += offset;
if ( sweep_freq < 0 )
{
sweep_freq = 0;
}
else if ( sweep_freq >= 2048 )
{
sweep_delay = 0; // don't modify channel frequency any further
sweep_freq = 2048; // silence sound immediately
}
}
}
void Gb_Square::run( gb_time_t time, gb_time_t end_time, int playing )
{
if ( sweep_freq == 2048 )
playing = false;
static unsigned char const table [4] = { 1, 2, 4, 6 };
int const duty = table [regs [1] >> 6];
int amp = volume & playing;
if ( phase >= duty )
amp = -amp;
int frequency = this->frequency();
if ( unsigned (frequency - 1) > 2040 ) // frequency < 1 || frequency > 2041
{
// really high frequency results in DC at half volume
amp = volume >> 1;
playing = false;
}
int delta = amp - last_amp;
if ( delta )
{
last_amp = amp;
synth->offset( time, delta, output );
}
time += delay;
if ( !playing )
time = end_time;
if ( time < end_time )
{
int const period = (2048 - frequency) * 4;
Blip_Buffer* const output = this->output;
int phase = this->phase;
int delta = amp * 2;
do
{
phase = (phase + 1) & 7;
if ( phase == 0 || phase == duty )
{
delta = -delta;
synth->offset_inline( time, delta, output );
}
time += period;
}
while ( time < end_time );
this->phase = phase;
last_amp = delta >> 1;
}
delay = time - end_time;
}
// Gb_Noise
#include BLARGG_ENABLE_OPTIMIZER
void Gb_Noise::run( gb_time_t time, gb_time_t end_time, int playing )
{
int amp = volume & playing;
int tap = 13 - (regs [3] & 8);
if ( bits >> tap & 2 )
amp = -amp;
int delta = amp - last_amp;
if ( delta )
{
last_amp = amp;
synth->offset( time, delta, output );
}
time += delay;
if ( !playing )
time = end_time;
if ( time < end_time )
{
static unsigned char const table [8] = { 8, 16, 32, 48, 64, 80, 96, 112 };
int period = table [regs [3] & 7] << (regs [3] >> 4);
// keep parallel resampled time to eliminate time conversion in the loop
Blip_Buffer* const output = this->output;
const blip_resampled_time_t resampled_period =
output->resampled_duration( period );
blip_resampled_time_t resampled_time = output->resampled_time( time );
unsigned bits = this->bits;
int delta = amp * 2;
do
{
unsigned changed = (bits >> tap) + 1;
time += period;
bits <<= 1;
if ( changed & 2 )
{
delta = -delta;
bits |= 1;
synth->offset_resampled( resampled_time, delta, output );
}
resampled_time += resampled_period;
}
while ( time < end_time );
this->bits = bits;
last_amp = delta >> 1;
}
delay = time - end_time;
}
// Gb_Wave
void Gb_Wave::reset(bool gba)
{
volume_forced = 0;
wave_pos = 0;
wave_mode = gba;
wave_size = 32;
wave_bank = 0;
memset( wave, 0, sizeof wave );
Gb_Osc::reset();
}
inline void Gb_Wave::write_register( int reg, int data )
{
switch ( reg )
{
case 0:
if ( !(data & 0x80) )
enabled = false;
if (wave_mode)
{
wave_bank = (data & 0x40) >> 1;
wave_size = (data & 0x20) + 32;
}
if (wave_pos > wave_size) wave_pos %= wave_size;
break;
case 1:
length = 256 - regs [1];
break;
case 2:
volume = data >> 5 & 3;
if (wave_mode) volume_forced = data & 0x80;
if (volume_forced) volume = -1;
break;
case 4:
if ( data & trigger & regs [0] )
{
wave_pos = 0;
enabled = true;
if ( length == 0 )
length = 256;
}
}
}
void Gb_Wave::run( gb_time_t time, gb_time_t end_time, int playing )
{
int volume_shift = (volume - 1) & 7; // volume = 0 causes shift = 7
int amp = (wave_size == 32) ? wave [wave_bank + wave_pos] : wave [wave_pos];
if (volume_forced) amp = ((amp >> 1) + amp) >> 1;
else amp >>= volume_shift;
amp = (amp & playing) * 2;
int frequency = this->frequency();
if ( unsigned (frequency - 1) > 2044 ) // frequency < 1 || frequency > 2045
{
if (volume_forced) amp = ((30 >> 1) + 30) >> 1;
else amp = 30 >> volume_shift;
amp &= playing;
playing = false;
}
int delta = amp - last_amp;
if ( delta )
{
last_amp = amp;
synth->offset( time, delta, output );
}
time += delay;
if ( !playing )
time = end_time;
if ( time < end_time )
{
Blip_Buffer* const output = this->output;
int const period = (2048 - frequency) * 2;
int wave_pos = (this->wave_pos + 1) & (wave_size - 1);
do
{
int amp = (wave_size == 32) ? wave [wave_bank + wave_pos] : wave [wave_pos];
if (volume_forced) amp = ((amp >> 1) + amp) >> 1;
else amp >>= volume_shift;
amp *= 2;
wave_pos = (wave_pos + 1) & (wave_size - 1);
int delta = amp - last_amp;
if ( delta )
{
last_amp = amp;
synth->offset_inline( time, delta, output );
}
time += period;
}
while ( time < end_time );
this->wave_pos = (wave_pos - 1) & (wave_size - 1);
}
delay = time - end_time;
}
// Gb_Apu::write_osc
void Gb_Apu::write_osc( int index, int reg, int data )
{
reg -= index * 5;
Gb_Square* sq = &square2;
switch ( index )
{
case 0:
sq = &square1;
case 1:
if ( sq->write_register( reg, data ) && index == 0 )
{
square1.sweep_freq = square1.frequency();
if ( (regs [0] & sq->period_mask) && (regs [0] & sq->shift_mask) )
{
square1.sweep_delay = 1; // cause sweep to recalculate now
square1.clock_sweep();
}
}
break;
case 2:
wave.write_register( reg, data );
break;
case 3:
if ( noise.write_register( reg, data ) )
noise.bits = 0x7FFF;
}
}

90
src/Gb_Apu/Gb_Oscs.h Normal file
View File

@ -0,0 +1,90 @@
// Private oscillators used by Gb_Apu
// Gb_Snd_Emu 0.1.4
#ifndef GB_OSCS_H
#define GB_OSCS_H
#include "blargg_common.h"
#include "Blip_Buffer.h"
struct Gb_Osc
{
enum { trigger = 0x80 };
enum { len_enabled_mask = 0x40 };
Blip_Buffer* outputs [4]; // NULL, right, left, center
Blip_Buffer* output;
int output_select;
BOOST::uint8_t* regs; // osc's 5 registers
int delay;
int last_amp;
int volume;
int length;
bool enabled;
void reset();
void clock_length();
int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; }
};
struct Gb_Env : Gb_Osc
{
int env_delay;
void reset();
void clock_envelope();
bool write_register( int, int );
};
struct Gb_Square : Gb_Env
{
enum { period_mask = 0x70 };
enum { shift_mask = 0x07 };
typedef Blip_Synth<blip_good_quality,1> Synth;
Synth const* synth;
int sweep_delay;
int sweep_freq;
int phase;
void reset();
void clock_sweep();
void run( gb_time_t, gb_time_t, int playing );
};
struct Gb_Noise : Gb_Env
{
typedef Blip_Synth<blip_med_quality,1> Synth;
Synth const* synth;
unsigned bits;
void run( gb_time_t, gb_time_t, int playing );
};
struct Gb_Wave : Gb_Osc
{
typedef Blip_Synth<blip_med_quality,1> Synth;
Synth const* synth;
int volume_forced;
int wave_pos;
unsigned wave_mode;
unsigned wave_size;
unsigned wave_bank;
BOOST::uint8_t wave [32 * 2];
void reset(bool gba = false);
void write_register( int, int );
void run( gb_time_t, gb_time_t, int playing );
};
inline void Gb_Env::reset()
{
env_delay = 0;
Gb_Osc::reset();
}
#endif

215
src/Gb_Apu/Multi_Buffer.cpp Normal file
View File

@ -0,0 +1,215 @@
// Blip_Buffer 0.4.0. http://www.slack.net/~ant/
#include "Multi_Buffer.h"
/* Copyright (C) 2003-2006 Shay Green. This module 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
module 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 module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include BLARGG_SOURCE_BEGIN
Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf )
{
length_ = 0;
sample_rate_ = 0;
channels_changed_count_ = 1;
}
blargg_err_t Multi_Buffer::set_channel_count( int )
{
return blargg_success;
}
Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 )
{
}
Mono_Buffer::~Mono_Buffer()
{
}
blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec )
{
BLARGG_RETURN_ERR( buf.set_sample_rate( rate, msec ) );
return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() );
}
// Silent_Buffer
Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse
{
chan.left = NULL;
chan.center = NULL;
chan.right = NULL;
}
// Mono_Buffer
Mono_Buffer::channel_t Mono_Buffer::channel( int )
{
channel_t ch;
ch.center = &buf;
ch.left = &buf;
ch.right = &buf;
return ch;
}
void Mono_Buffer::end_frame( blip_time_t t, bool )
{
buf.end_frame( t );
}
// Stereo_Buffer
Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 )
{
chan.center = &bufs [0];
chan.left = &bufs [1];
chan.right = &bufs [2];
}
Stereo_Buffer::~Stereo_Buffer()
{
}
blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec )
{
for ( int i = 0; i < buf_count; i++ )
BLARGG_RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );
return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() );
}
void Stereo_Buffer::clock_rate( long rate )
{
for ( int i = 0; i < buf_count; i++ )
bufs [i].clock_rate( rate );
}
void Stereo_Buffer::bass_freq( int bass )
{
for ( unsigned i = 0; i < buf_count; i++ )
bufs [i].bass_freq( bass );
}
void Stereo_Buffer::clear()
{
stereo_added = false;
was_stereo = false;
for ( int i = 0; i < buf_count; i++ )
bufs [i].clear();
}
void Stereo_Buffer::end_frame( blip_time_t clock_count, bool stereo )
{
for ( unsigned i = 0; i < buf_count; i++ )
bufs [i].end_frame( clock_count );
stereo_added |= stereo;
}
long Stereo_Buffer::read_samples( blip_sample_t* out, long count )
{
require( !(count & 1) ); // count must be even
count = (unsigned) count / 2;
long avail = bufs [0].samples_avail();
if ( count > avail )
count = avail;
if ( count )
{
if ( stereo_added || was_stereo )
{
mix_stereo( out, count );
bufs [0].remove_samples( count );
bufs [1].remove_samples( count );
bufs [2].remove_samples( count );
}
else
{
mix_mono( out, count );
bufs [0].remove_samples( count );
bufs [1].remove_silence( count );
bufs [2].remove_silence( count );
}
// to do: this might miss opportunities for optimization
if ( !bufs [0].samples_avail() ) {
was_stereo = stereo_added;
stereo_added = false;
}
}
return count * 2;
}
#include BLARGG_ENABLE_OPTIMIZER
void Stereo_Buffer::mix_stereo( blip_sample_t* out, long count )
{
Blip_Reader left;
Blip_Reader right;
Blip_Reader center;
left.begin( bufs [1] );
right.begin( bufs [2] );
int bass = center.begin( bufs [0] );
while ( count-- )
{
int c = center.read();
long l = c + left.read();
long r = c + right.read();
center.next( bass );
out [0] = l;
out [1] = r;
out += 2;
if ( (BOOST::int16_t) l != l )
out [-2] = 0x7FFF - (l >> 24);
left.next( bass );
right.next( bass );
if ( (BOOST::int16_t) r != r )
out [-1] = 0x7FFF - (r >> 24);
}
center.end( bufs [0] );
right.end( bufs [2] );
left.end( bufs [1] );
}
void Stereo_Buffer::mix_mono( blip_sample_t* out, long count )
{
Blip_Reader in;
int bass = in.begin( bufs [0] );
while ( count-- )
{
long s = in.read();
in.next( bass );
out [0] = s;
out [1] = s;
out += 2;
if ( (BOOST::int16_t) s != s ) {
s = 0x7FFF - (s >> 24);
out [-2] = s;
out [-1] = s;
}
}
in.end( bufs [0] );
}

175
src/Gb_Apu/Multi_Buffer.h Normal file
View File

@ -0,0 +1,175 @@
// Multi-channel sound buffer interface, and basic mono and stereo buffers
// Blip_Buffer 0.4.0
#ifndef MULTI_BUFFER_H
#define MULTI_BUFFER_H
#include "blargg_common.h"
#include "Blip_Buffer.h"
// Interface to one or more Blip_Buffers mapped to one or more channels
// consisting of left, center, and right buffers.
class Multi_Buffer {
public:
Multi_Buffer( int samples_per_frame );
virtual ~Multi_Buffer() { }
// Set the number of channels available
virtual blargg_err_t set_channel_count( int );
// Get indexed channel, from 0 to channel count - 1
struct channel_t {
Blip_Buffer* center;
Blip_Buffer* left;
Blip_Buffer* right;
};
virtual channel_t channel( int index ) = 0;
// See Blip_Buffer.h
virtual blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ) = 0;
virtual void clock_rate( long ) = 0;
virtual void bass_freq( int ) = 0;
virtual void clear() = 0;
long sample_rate() const;
// Length of buffer, in milliseconds
int length() const;
// See Blip_Buffer.h. For optimal operation, pass false for 'added_stereo'
// if nothing was added to the left and right buffers of any channel for
// this time frame.
virtual void end_frame( blip_time_t, bool added_stereo = true ) = 0;
// Number of samples per output frame (1 = mono, 2 = stereo)
int samples_per_frame() const;
// Count of changes to channel configuration. Incremented whenever
// a change is made to any of the Blip_Buffers for any channel.
unsigned channels_changed_count() { return channels_changed_count_; }
// See Blip_Buffer.h
virtual long read_samples( blip_sample_t*, long ) = 0;
virtual long samples_avail() const = 0;
protected:
void channels_changed() { channels_changed_count_++; }
private:
// noncopyable
Multi_Buffer( const Multi_Buffer& );
Multi_Buffer& operator = ( const Multi_Buffer& );
unsigned channels_changed_count_;
long sample_rate_;
int length_;
int const samples_per_frame_;
};
// Uses a single buffer and outputs mono samples.
class Mono_Buffer : public Multi_Buffer {
Blip_Buffer buf;
public:
Mono_Buffer();
~Mono_Buffer();
// Buffer used for all channels
Blip_Buffer* center() { return &buf; }
// See Multi_Buffer
blargg_err_t set_sample_rate( long rate, int msec = blip_default_length );
void clock_rate( long );
void bass_freq( int );
void clear();
channel_t channel( int );
void end_frame( blip_time_t, bool unused = true );
long samples_avail() const;
long read_samples( blip_sample_t*, long );
};
// Uses three buffers (one for center) and outputs stereo sample pairs.
class Stereo_Buffer : public Multi_Buffer {
public:
Stereo_Buffer();
~Stereo_Buffer();
// Buffers used for all channels
Blip_Buffer* center() { return &bufs [0]; }
Blip_Buffer* left() { return &bufs [1]; }
Blip_Buffer* right() { return &bufs [2]; }
// See Multi_Buffer
blargg_err_t set_sample_rate( long, int msec = blip_default_length );
void clock_rate( long );
void bass_freq( int );
void clear();
channel_t channel( int index );
void end_frame( blip_time_t, bool added_stereo = true );
long samples_avail() const;
long read_samples( blip_sample_t*, long );
private:
enum { buf_count = 3 };
Blip_Buffer bufs [buf_count];
channel_t chan;
bool stereo_added;
bool was_stereo;
void mix_stereo( blip_sample_t*, long );
void mix_mono( blip_sample_t*, long );
};
// Silent_Buffer generates no samples, useful where no sound is wanted
class Silent_Buffer : public Multi_Buffer {
channel_t chan;
public:
Silent_Buffer();
blargg_err_t set_sample_rate( long rate, int msec = blip_default_length );
void clock_rate( long ) { }
void bass_freq( int ) { }
void clear() { }
channel_t channel( int ) { return chan; }
void end_frame( blip_time_t, bool unused = true ) { }
long samples_avail() const { return 0; }
long read_samples( blip_sample_t*, long ) { return 0; }
};
// End of public interface
inline blargg_err_t Multi_Buffer::set_sample_rate( long rate, int msec )
{
sample_rate_ = rate;
length_ = msec;
return blargg_success;
}
inline blargg_err_t Silent_Buffer::set_sample_rate( long rate, int msec )
{
return Multi_Buffer::set_sample_rate( rate, msec );
}
inline int Multi_Buffer::samples_per_frame() const { return samples_per_frame_; }
inline long Stereo_Buffer::samples_avail() const { return bufs [0].samples_avail() * 2; }
inline Stereo_Buffer::channel_t Stereo_Buffer::channel( int ) { return chan; }
inline long Multi_Buffer::sample_rate() const { return sample_rate_; }
inline int Multi_Buffer::length() const { return length_; }
inline void Mono_Buffer::clock_rate( long rate ) { buf.clock_rate( rate ); }
inline void Mono_Buffer::clear() { buf.clear(); }
inline void Mono_Buffer::bass_freq( int freq ) { buf.bass_freq( freq ); }
inline long Mono_Buffer::read_samples( blip_sample_t* p, long s ) { return buf.read_samples( p, s ); }
inline long Mono_Buffer::samples_avail() const { return buf.samples_avail(); }
#endif

242
src/Gb_Apu/blargg_common.h Normal file
View File

@ -0,0 +1,242 @@
// Sets up common environment for Shay Green's libraries.
//
// To change configuration options, modify blargg_config.h, not this file.
#ifndef BLARGG_COMMON_H
#define BLARGG_COMMON_H
// HAVE_CONFIG_H: If defined, include user's "config.h" first (which *can*
// re-include blargg_common.h if it needs to)
#ifdef HAVE_CONFIG_H
#undef BLARGG_COMMON_H
#include "config.h"
#define BLARGG_COMMON_H
#endif
// BLARGG_NONPORTABLE: If defined to 1, platform-specific (and possibly non-portable)
// optimizations are used. Defaults to off. Report any problems that occur only when
// this is enabled.
#ifndef BLARGG_NONPORTABLE
#define BLARGG_NONPORTABLE 0
#endif
// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
// one must be #defined to 1. Only needed if something actually depends on byte order.
#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
#if defined (MSB_FIRST) || defined (__powerc) || defined (macintosh) || \
defined (WORDS_BIGENDIAN) || defined (__BIG_ENDIAN__)
#define BLARGG_BIG_ENDIAN 1
#else
#define BLARGG_LITTLE_ENDIAN 1
#endif
#endif
// Determine compiler's language support
// Metrowerks CodeWarrior
#if defined (__MWERKS__)
#define BLARGG_COMPILER_HAS_NAMESPACE 1
#if !__option(bool)
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
#define STATIC_CAST(T,expr) static_cast< T > (expr)
// Microsoft Visual C++
#elif defined (_MSC_VER)
#if _MSC_VER < 1100
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
// GNU C++
#elif defined (__GNUC__)
#if __GNUC__ > 2
#define BLARGG_COMPILER_HAS_NAMESPACE 1
#endif
// Mingw
#elif defined (__MINGW32__)
// empty
// Pre-ISO C++ compiler
#elif __cplusplus < 199711
#ifndef BLARGG_COMPILER_HAS_BOOL
#define BLARGG_COMPILER_HAS_BOOL 0
#endif
#endif
/* BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compilers.
If errors occur here, add the following line to your config.h file:
#define BLARGG_COMPILER_HAS_BOOL 0
*/
#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
typedef int bool;
const bool true = 1;
const bool false = 0;
#endif
// BLARGG_USE_NAMESPACE: If 1, use <cxxx> headers rather than <xxxx.h>
#if BLARGG_USE_NAMESPACE || (!defined (BLARGG_USE_NAMESPACE) && BLARGG_COMPILER_HAS_NAMESPACE)
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <climits>
#define STD std
#else
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#define STD
#endif
// BLARGG_NEW is used in place of 'new' to create objects. By default, plain new is used.
// To prevent an exception if out of memory, #define BLARGG_NEW new (std::nothrow)
#ifndef BLARGG_NEW
#define BLARGG_NEW new
#endif
// BOOST::int8_t etc.
// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
#if defined (HAVE_STDINT_H)
#include <stdint.h>
#define BOOST
// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
#elif defined (HAVE_INTTYPES_H)
#include <inttypes.h>
#define BOOST
#else
struct BOOST
{
#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
typedef signed char int8_t;
typedef unsigned char uint8_t;
#else
// No suitable 8-bit type available
typedef struct see_blargg_common_h int8_t;
typedef struct see_blargg_common_h uint8_t;
#endif
#if USHRT_MAX == 0xFFFF
typedef short int16_t;
typedef unsigned short uint16_t;
#else
// No suitable 16-bit type available
typedef struct see_blargg_common_h int16_t;
typedef struct see_blargg_common_h uint16_t;
#endif
#if ULONG_MAX == 0xFFFFFFFF
typedef long int32_t;
typedef unsigned long uint32_t;
#elif UINT_MAX == 0xFFFFFFFF
typedef int int32_t;
typedef unsigned int uint32_t;
#else
// No suitable 32-bit type available
typedef struct see_blargg_common_h int32_t;
typedef struct see_blargg_common_h uint32_t;
#endif
};
#endif
// BLARGG_SOURCE_BEGIN: Library sources #include this after other #includes.
#ifndef BLARGG_SOURCE_BEGIN
#define BLARGG_SOURCE_BEGIN "blargg_source.h"
#endif
// BLARGG_ENABLE_OPTIMIZER: Library sources #include this for speed-critical code
#ifndef BLARGG_ENABLE_OPTIMIZER
#define BLARGG_ENABLE_OPTIMIZER "blargg_common.h"
#endif
// BLARGG_CPU_*: Used to select between some optimizations
#if !defined (BLARGG_CPU_POWERPC) && !defined (BLARGG_CPU_X86)
#if defined (__powerc)
#define BLARGG_CPU_POWERPC 1
#elif defined (_MSC_VER) && defined (_M_IX86)
#define BLARGG_CPU_X86 1
#endif
#endif
// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
#ifndef BOOST_STATIC_ASSERT
#ifdef _MSC_VER
// MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
#define BOOST_STATIC_ASSERT( expr ) \
void blargg_failed_( int (*arg) [2 / ((expr) ? 1 : 0) - 1] )
#else
// Some other compilers fail when declaring same function multiple times in class,
// so differentiate them by line
#define BOOST_STATIC_ASSERT( expr ) \
void blargg_failed_( int (*arg) [2 / ((expr) ? 1 : 0) - 1] [__LINE__] )
#endif
#endif
// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
#ifndef STATIC_CAST
#define STATIC_CAST(T,expr) ((T) (expr))
#endif
// blargg_err_t (NULL on success, otherwise error string)
#ifndef blargg_err_t
typedef const char* blargg_err_t;
#endif
const char* const blargg_success = 0;
// blargg_vector: Simple array that does *not* work for types with a constructor (non-POD).
template<class T>
class blargg_vector {
T* begin_;
STD::size_t size_;
public:
blargg_vector() : begin_( 0 ), size_( 0 ) { }
~blargg_vector() { STD::free( begin_ ); }
typedef STD::size_t size_type;
blargg_err_t resize( size_type n )
{
void* p = STD::realloc( begin_, n * sizeof (T) );
if ( !p && n )
return "Out of memory";
begin_ = (T*) p;
size_ = n;
return 0;
}
void clear()
{
void* p = begin_;
begin_ = 0;
size_ = 0;
STD::free( p );
}
size_type size() const { return size_; }
T* begin() { return begin_; }
T* end() { return begin_ + size_; }
const T* begin() const { return begin_; }
const T* end() const { return begin_ + size_; }
T& operator [] ( size_type n )
{
assert( n <= size_ ); // allow for past-the-end value
return begin_ [n];
}
const T& operator [] ( size_type n ) const
{
assert( n <= size_ ); // allow for past-the-end value
return begin_ [n];
}
};
#endif

156
src/Gb_Apu/blargg_endian.h Normal file
View File

@ -0,0 +1,156 @@
// CPU Byte Order Utilities
// Game_Music_Emu 0.3.0
#ifndef BLARGG_ENDIAN
#define BLARGG_ENDIAN
#include "blargg_common.h"
#if 0
// Read 16/32-bit little-endian integer from memory
unsigned GET_LE16( void const* );
unsigned long GET_LE32( void const* );
// Read 16/32-bit big-endian integer from memory
unsigned GET_BE16( void const* );
unsigned long GET_BE32( void const* );
// Write 16/32-bit integer to memory in little-endian format
void SET_LE16( void*, unsigned );
void SET_LE32( void*, unsigned );
// Write 16/32-bit integer to memory in big-endian format
void SET_BE16( void*, unsigned long );
void SET_BE32( void*, unsigned long );
#endif
inline unsigned get_le16( void const* p )
{
return ((unsigned char*) p) [1] * 0x100 +
((unsigned char*) p) [0];
}
inline unsigned get_be16( void const* p )
{
return ((unsigned char*) p) [0] * 0x100 +
((unsigned char*) p) [1];
}
inline unsigned long get_le32( void const* p )
{
return ((unsigned char*) p) [3] * 0x01000000 +
((unsigned char*) p) [2] * 0x00010000 +
((unsigned char*) p) [1] * 0x00000100 +
((unsigned char*) p) [0];
}
inline unsigned long get_be32( void const* p )
{
return ((unsigned char*) p) [0] * 0x01000000 +
((unsigned char*) p) [1] * 0x00010000 +
((unsigned char*) p) [2] * 0x00000100 +
((unsigned char*) p) [3];
}
inline void set_le16( void* p, unsigned n )
{
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
((unsigned char*) p) [0] = (unsigned char) n;
}
inline void set_be16( void* p, unsigned n )
{
((unsigned char*) p) [0] = (unsigned char) (n >> 8);
((unsigned char*) p) [1] = (unsigned char) n;
}
inline void set_le32( void* p, unsigned long n )
{
((unsigned char*) p) [3] = (unsigned char) (n >> 24);
((unsigned char*) p) [2] = (unsigned char) (n >> 16);
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
((unsigned char*) p) [0] = (unsigned char) n;
}
inline void set_be32( void* p, unsigned long n )
{
((unsigned char*) p) [0] = (unsigned char) (n >> 24);
((unsigned char*) p) [1] = (unsigned char) (n >> 16);
((unsigned char*) p) [2] = (unsigned char) (n >> 8);
((unsigned char*) p) [3] = (unsigned char) n;
}
#ifndef GET_LE16
// Optimized implementation if byte order is known
#if BLARGG_NONPORTABLE && BLARGG_LITTLE_ENDIAN
#define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
#define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
#define SET_LE16( addr, data ) (void (*(BOOST::uint16_t*) (addr) = (data)))
#define SET_LE32( addr, data ) (void (*(BOOST::uint32_t*) (addr) = (data)))
#elif BLARGG_NONPORTABLE && BLARGG_CPU_POWERPC
// PowerPC has special byte-reversed instructions
// to do: assumes that PowerPC is running in big-endian mode
#define GET_LE16( addr ) (__lhbrx( (addr), 0 ))
#define GET_LE32( addr ) (__lwbrx( (addr), 0 ))
#define SET_LE16( addr, data ) (__sthbrx( (data), (addr), 0 ))
#define SET_LE32( addr, data ) (__stwbrx( (data), (addr), 0 ))
#define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
#define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
#define SET_BE16( addr, data ) (void (*(BOOST::uint16_t*) (addr) = (data)))
#define SET_BE32( addr, data ) (void (*(BOOST::uint32_t*) (addr) = (data)))
#endif
#endif
#ifndef GET_LE16
#define GET_LE16( addr ) get_le16( addr )
#endif
#ifndef GET_LE32
#define GET_LE32( addr ) get_le32( addr )
#endif
#ifndef SET_LE16
#define SET_LE16( addr, data ) set_le16( addr, data )
#endif
#ifndef SET_LE32
#define SET_LE32( addr, data ) set_le32( addr, data )
#endif
#ifndef GET_BE16
#define GET_BE16( addr ) get_be16( addr )
#endif
#ifndef GET_BE32
#define GET_BE32( addr ) get_be32( addr )
#endif
#ifndef SET_BE16
#define SET_BE16( addr, data ) set_be16( addr, data )
#endif
#ifndef SET_BE32
#define SET_BE32( addr, data ) set_be32( addr, data )
#endif
// auto-selecting versions
inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
inline void set_le( BOOST::uint32_t* p, unsigned long n ) { SET_LE32( p, n ); }
inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
inline void set_be( BOOST::uint32_t* p, unsigned long n ) { SET_BE32( p, n ); }
inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
inline unsigned long get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
inline unsigned long get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
#endif

View File

@ -0,0 +1,76 @@
// By default, #included at beginning of library source files.
// Can be overridden by #defining BLARGG_SOURCE_BEGIN to path of alternate file.
// Copyright (C) 2005 Shay Green.
#ifndef BLARGG_SOURCE_H
#define BLARGG_SOURCE_H
// If debugging is enabled, abort program if expr is false. Meant for checking
// internal state and consistency. A failed assertion indicates a bug in the module.
// void assert( bool expr );
#include <assert.h>
// If debugging is enabled and expr is false, abort program. Meant for checking
// caller-supplied parameters and operations that are outside the control of the
// module. A failed requirement indicates a bug outside the module.
// void require( bool expr );
#undef require
#define require( expr ) assert( expr )
// Like printf() except output goes to debug log file. Might be defined to do
// nothing (not even evaluate its arguments).
// void dprintf( const char* format, ... );
#undef dprintf
#ifdef BLARGG_DPRINTF
#define dprintf BLARGG_DPRINTF
#else
inline void blargg_dprintf_( const char*, ... ) { }
#define dprintf (1) ? (void) 0 : blargg_dprintf_
#endif
// If enabled, evaluate expr and if false, make debug log entry with source file
// and line. Meant for finding situations that should be examined further, but that
// don't indicate a problem. In all cases, execution continues normally.
#undef check
#ifdef BLARGG_CHECK
#define check( expr ) BLARGG_CHECK( expr )
#else
#define check( expr ) ((void) 0)
#endif
// If expr returns non-NULL error string, return it from current function, otherwise continue.
#define BLARGG_RETURN_ERR( expr ) do { \
blargg_err_t blargg_return_err_ = (expr); \
if ( blargg_return_err_ ) return blargg_return_err_; \
} while ( 0 )
// If ptr is NULL, return out of memory error string.
#define BLARGG_CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 )
// Avoid any macros which evaluate their arguments multiple times
#undef min
#undef max
// using const references generates crappy code, and I am currenly only using these
// for built-in types, so they take arguments by value
template<class T>
inline T min( T x, T y )
{
if ( x < y )
return x;
return y;
}
template<class T>
inline T max( T x, T y )
{
if ( x < y )
return y;
return x;
}
#endif

Some files were not shown because too many files have changed in this diff Show More