Added VBALink to the SVN code. Note that this is completely untested
This commit is contained in:
commit
8bda069b3b
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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!
|
||||
|
||||
|
|
@ -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 = ®s [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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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] );
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -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);
|
|
@ -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=""$(SolutionDir)zlib""
|
||||
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=""$(SolutionDir)zlib""
|
||||
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>
|
|
@ -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=""$(SolutionDir)zlib""
|
||||
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=""$(SolutionDir)zlib""
|
||||
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>
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
@ -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 $@
|
|
@ -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.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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."
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
Known Bugs:
|
||||
|
||||
- fsMaxScale = 1 in Direct3D fullscreen results in wrong image size
|
||||
- Direct3D: Menu toggle takes a little too long
|
|
@ -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
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
|
@ -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>
|
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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!
|
||||
|
||||
|
|
@ -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 = ®s [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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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] );
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Reference in New Issue