Remove blargg apu
git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@48 a31d4220-a93d-0410-bf67-fe4944624d44
This commit is contained in:
parent
2c223782fe
commit
3a344edb3c
|
@ -1,406 +0,0 @@
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,354 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,204 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,504 +0,0 @@
|
||||||
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!
|
|
||||||
|
|
||||||
|
|
|
@ -1,318 +0,0 @@
|
||||||
|
|
||||||
// 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(igba);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,388 +0,0 @@
|
||||||
|
|
||||||
// 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 ? 1 : 0);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Gb_Noise::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 + (gba ? 1 : 0));
|
|
||||||
enabled = true;
|
|
||||||
if ( length == 0 )
|
|
||||||
length = 64;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
{
|
|
||||||
bool gba;
|
|
||||||
typedef Blip_Synth<blip_med_quality,1> Synth;
|
|
||||||
Synth const* synth;
|
|
||||||
unsigned bits;
|
|
||||||
|
|
||||||
bool write_register( int, int );
|
|
||||||
void reset(bool igba)
|
|
||||||
{
|
|
||||||
gba = igba;
|
|
||||||
Gb_Env::reset();
|
|
||||||
}
|
|
||||||
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
|
|
||||||
|
|
|
@ -1,215 +0,0 @@
|
||||||
|
|
||||||
// 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] );
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,242 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,156 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
Loading…
Reference in New Issue