Updated Freeboy files from Game Music Emu 0.6.1. (#3618)
Uses upstream files to fix #326
This commit is contained in:
committed by
Tres Finocchiaro
parent
98952636b5
commit
aaf09bb4db
@@ -14,15 +14,11 @@ 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 */
|
||||
|
||||
gb_time_t const frame_length = 70224;
|
||||
blip_time_t const frame_length = 70224;
|
||||
|
||||
Basic_Gb_Apu::Basic_Gb_Apu()
|
||||
{
|
||||
time = 0;
|
||||
|
||||
// Adjust frequency equalization to make it sound like a tiny speaker
|
||||
apu.treble_eq( -20.0 ); // lower values muffle it more
|
||||
buf.bass_freq( 461 ); // higher values simulate smaller speaker
|
||||
}
|
||||
|
||||
Basic_Gb_Apu::~Basic_Gb_Apu()
|
||||
@@ -36,12 +32,12 @@ blargg_err_t Basic_Gb_Apu::set_sample_rate( long rate )
|
||||
return buf.set_sample_rate( rate );
|
||||
}
|
||||
|
||||
void Basic_Gb_Apu::write_register( gb_addr_t addr, int data )
|
||||
void Basic_Gb_Apu::write_register( blip_time_t addr, int data )
|
||||
{
|
||||
apu.write_register( clock(), addr, data );
|
||||
}
|
||||
|
||||
int Basic_Gb_Apu::read_register( gb_addr_t addr )
|
||||
int Basic_Gb_Apu::read_register( blip_time_t addr )
|
||||
{
|
||||
return apu.read_register( clock(), addr );
|
||||
}
|
||||
@@ -49,8 +45,8 @@ int Basic_Gb_Apu::read_register( gb_addr_t addr )
|
||||
void Basic_Gb_Apu::end_frame()
|
||||
{
|
||||
time = 0;
|
||||
bool stereo = apu.end_frame( frame_length );
|
||||
buf.end_frame( frame_length, stereo );
|
||||
apu.end_frame( frame_length );
|
||||
buf.end_frame( frame_length );
|
||||
}
|
||||
|
||||
long Basic_Gb_Apu::samples_avail() const
|
||||
|
||||
@@ -15,23 +15,23 @@ class Basic_Gb_Apu {
|
||||
public:
|
||||
Basic_Gb_Apu();
|
||||
~Basic_Gb_Apu();
|
||||
|
||||
|
||||
// Set output sample rate
|
||||
blargg_err_t set_sample_rate( long rate );
|
||||
|
||||
|
||||
// Pass reads and writes in the range 0xff10-0xff3f
|
||||
void write_register( gb_addr_t, int data );
|
||||
int read_register( gb_addr_t );
|
||||
|
||||
void write_register( blip_time_t, int data );
|
||||
int read_register( blip_time_t );
|
||||
|
||||
// End a 1/60 sound frame and add samples to buffer
|
||||
void end_frame();
|
||||
|
||||
|
||||
// Samples are generated in stereo, left first. Sample counts are always
|
||||
// a multiple of 2.
|
||||
|
||||
|
||||
// Number of samples in buffer
|
||||
long samples_avail() const;
|
||||
|
||||
|
||||
// Read at most 'count' samples out of buffer and return number actually read
|
||||
typedef blip_sample_t sample_t;
|
||||
long read_samples( sample_t* out, long count );
|
||||
@@ -41,12 +41,12 @@ public:
|
||||
void treble_eq( const blip_eq_t& eq );
|
||||
void bass_freq( int bf );
|
||||
//<---
|
||||
|
||||
|
||||
private:
|
||||
Gb_Apu apu;
|
||||
Stereo_Buffer buf;
|
||||
blip_time_t time;
|
||||
|
||||
|
||||
// faked CPU timing
|
||||
blip_time_t clock() { return time += 4; }
|
||||
};
|
||||
|
||||
@@ -3,4 +3,4 @@ INCLUDE(BuildPlugin)
|
||||
# Disable C++11
|
||||
REMOVE_DEFINITIONS(-std=c++0x)
|
||||
|
||||
BUILD_PLUGIN(papu papu_instrument.cpp papu_instrument.h Basic_Gb_Apu.cpp Basic_Gb_Apu.h gb_apu/Gb_Oscs.cpp gb_apu/Gb_Apu.h gb_apu/Blip_Buffer.cpp gb_apu/Gb_Apu.cpp gb_apu/Gb_Oscs.h gb_apu/blargg_common.h gb_apu/Blip_Buffer.h gb_apu/Multi_Buffer.cpp gb_apu/blargg_source.h gb_apu/Blip_Synth.h gb_apu/Multi_Buffer.h MOCFILES papu_instrument.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
|
||||
BUILD_PLUGIN(papu papu_instrument.cpp papu_instrument.h Basic_Gb_Apu.cpp Basic_Gb_Apu.h gb_apu/Gb_Oscs.cpp gb_apu/Gb_Apu.h gb_apu/Blip_Buffer.cpp gb_apu/Gb_Apu.cpp gb_apu/Gb_Oscs.h gb_apu/blargg_common.h gb_apu/Blip_Buffer.h gb_apu/Multi_Buffer.cpp gb_apu/blargg_source.h gb_apu/Multi_Buffer.h MOCFILES papu_instrument.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
|
||||
|
||||
@@ -1,429 +1,460 @@
|
||||
|
||||
// Blip_Buffer 0.3.4. http://www.slack.net/~ant/libs/
|
||||
// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
|
||||
|
||||
#include "Blip_Buffer.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copyright (C) 2003-2005 Shay Green. This module is free software; you
|
||||
/* 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 */
|
||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
#ifdef BLARGG_ENABLE_OPTIMIZER
|
||||
#include BLARGG_ENABLE_OPTIMIZER
|
||||
#endif
|
||||
|
||||
int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
|
||||
|
||||
Blip_Buffer::Blip_Buffer()
|
||||
{
|
||||
samples_per_sec = 44100;
|
||||
buffer_ = NULL;
|
||||
|
||||
// try to cause assertion failure if buffer is used before these are set
|
||||
clocks_per_sec = 0;
|
||||
factor_ = ~0ul;
|
||||
offset_ = 0;
|
||||
buffer_size_ = 0;
|
||||
length_ = 0;
|
||||
|
||||
bass_freq_ = 16;
|
||||
}
|
||||
factor_ = (blip_ulong)-1 / 2;
|
||||
offset_ = 0;
|
||||
buffer_ = 0;
|
||||
buffer_size_ = 0;
|
||||
sample_rate_ = 0;
|
||||
reader_accum_ = 0;
|
||||
bass_shift_ = 0;
|
||||
clock_rate_ = 0;
|
||||
bass_freq_ = 16;
|
||||
length_ = 0;
|
||||
|
||||
void Blip_Buffer::clear( bool entire_buffer )
|
||||
{
|
||||
long count = (entire_buffer ? buffer_size_ : samples_avail());
|
||||
offset_ = 0;
|
||||
reader_accum = 0;
|
||||
if ( buffer_ )
|
||||
memset( buffer_, sample_offset_ & 0xFF, (count + widest_impulse_) * sizeof (buf_t_) );
|
||||
}
|
||||
// assumptions code makes about implementation-defined features
|
||||
#ifndef NDEBUG
|
||||
// right shift of negative value preserves sign
|
||||
buf_t_ i = -0x7FFFFFFE;
|
||||
assert( (i >> 1) == -0x3FFFFFFF );
|
||||
|
||||
blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
|
||||
{
|
||||
unsigned new_size = (0xFFFFFFFF >> BLIP_BUFFER_ACCURACY) + 1 - widest_impulse_ - 64;
|
||||
if ( msec != blip_default_length )
|
||||
{
|
||||
size_t s = (new_rate * (msec + 1) + 999) / 1000;
|
||||
if ( s < new_size )
|
||||
new_size = s;
|
||||
else
|
||||
require( false ); // requested buffer length exceeds limit
|
||||
}
|
||||
|
||||
if ( buffer_size_ != new_size )
|
||||
{
|
||||
delete [] buffer_;
|
||||
buffer_ = NULL; // allow for exception in allocation below
|
||||
buffer_size_ = 0;
|
||||
offset_ = 0;
|
||||
|
||||
int const count_clocks_extra = 2;
|
||||
buffer_ = BLARGG_NEW buf_t_ [new_size + widest_impulse_ + count_clocks_extra];
|
||||
BLARGG_CHECK_ALLOC( buffer_ );
|
||||
}
|
||||
|
||||
buffer_size_ = new_size;
|
||||
length_ = new_size * 1000 / new_rate - 1;
|
||||
if ( msec )
|
||||
assert( length_ == msec ); // ensure length is same as that passed in
|
||||
|
||||
samples_per_sec = new_rate;
|
||||
if ( clocks_per_sec )
|
||||
clock_rate( clocks_per_sec ); // recalculate factor
|
||||
|
||||
bass_freq( bass_freq_ ); // recalculate shift
|
||||
|
||||
clear();
|
||||
|
||||
return blargg_success;
|
||||
}
|
||||
|
||||
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long clock_rate ) const
|
||||
{
|
||||
blip_resampled_time_t factor = (unsigned long) floor(
|
||||
(double) samples_per_sec / clock_rate * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
|
||||
require( factor > 0 ); // clock_rate/sample_rate ratio is too large
|
||||
return factor;
|
||||
// casting to short truncates to 16 bits and sign-extends
|
||||
i = 0x18000;
|
||||
assert( (short) i == -0x8000 );
|
||||
#endif
|
||||
}
|
||||
|
||||
Blip_Buffer::~Blip_Buffer()
|
||||
{
|
||||
delete [] buffer_;
|
||||
if ( buffer_size_ != silent_buf_size )
|
||||
free( buffer_ );
|
||||
}
|
||||
|
||||
Silent_Blip_Buffer::Silent_Blip_Buffer()
|
||||
{
|
||||
factor_ = 0;
|
||||
buffer_ = buf;
|
||||
buffer_size_ = silent_buf_size;
|
||||
memset( buf, 0, sizeof buf ); // in case machine takes exception for signed overflow
|
||||
}
|
||||
|
||||
void Blip_Buffer::clear( int entire_buffer )
|
||||
{
|
||||
offset_ = 0;
|
||||
reader_accum_ = 0;
|
||||
modified_ = 0;
|
||||
if ( buffer_ )
|
||||
{
|
||||
long count = (entire_buffer ? buffer_size_ : samples_avail());
|
||||
memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) );
|
||||
}
|
||||
}
|
||||
|
||||
Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
|
||||
{
|
||||
if ( buffer_size_ == silent_buf_size )
|
||||
{
|
||||
assert( 0 );
|
||||
return "Internal (tried to resize Silent_Blip_Buffer)";
|
||||
}
|
||||
|
||||
// start with maximum length that resampled time can represent
|
||||
long new_size = (UINT_MAX >> BLIP_BUFFER_ACCURACY) - blip_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 + blip_buffer_extra_) * sizeof *buffer_ );
|
||||
if ( !p )
|
||||
return "Out of memory";
|
||||
buffer_ = (buf_t_*) p;
|
||||
}
|
||||
|
||||
buffer_size_ = new_size;
|
||||
assert( buffer_size_ != silent_buf_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 rate ) const
|
||||
{
|
||||
double ratio = (double) sample_rate_ / rate;
|
||||
blip_long factor = (blip_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;
|
||||
if ( freq == 0 )
|
||||
int shift = 31;
|
||||
if ( freq > 0 )
|
||||
{
|
||||
bass_shift = 31; // 32 or greater invokes undefined behavior elsewhere
|
||||
return;
|
||||
shift = 13;
|
||||
long f = (freq << 16) / sample_rate_;
|
||||
while ( (f >>= 1) && --shift ) { }
|
||||
}
|
||||
bass_shift = 1 + (int) floor( 1.442695041 * log( 0.124 * samples_per_sec / freq ) );
|
||||
if ( bass_shift < 0 )
|
||||
bass_shift = 0;
|
||||
if ( bass_shift > 24 )
|
||||
bass_shift = 24;
|
||||
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
|
||||
{
|
||||
return (resampled_time( t ) >> BLIP_BUFFER_ACCURACY) - (offset_ >> BLIP_BUFFER_ACCURACY);
|
||||
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 > (long) buffer_size_ )
|
||||
if ( !factor_ )
|
||||
{
|
||||
assert( 0 ); // sample rate and clock rates must be set first
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( count > buffer_size_ )
|
||||
count = buffer_size_;
|
||||
|
||||
return ((count << BLIP_BUFFER_ACCURACY) - offset_ + (factor_ - 1)) / factor_;
|
||||
}
|
||||
|
||||
void Blip_Impulse_::init( blip_pair_t_* imps, int w, int r, int fb )
|
||||
{
|
||||
fine_bits = fb;
|
||||
width = w;
|
||||
impulses = (imp_t*) imps;
|
||||
generate = true;
|
||||
volume_unit_ = -1.0;
|
||||
res = r;
|
||||
buf = NULL;
|
||||
|
||||
impulse = &impulses [width * res * 2 * (fine_bits ? 2 : 1)];
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
const int impulse_bits = 15;
|
||||
const long impulse_amp = 1L << impulse_bits;
|
||||
const long impulse_offset = impulse_amp / 2;
|
||||
|
||||
void Blip_Impulse_::scale_impulse( int unit, imp_t* imp_in ) const
|
||||
{
|
||||
long offset = ((long) unit << impulse_bits) - impulse_offset * unit +
|
||||
(1 << (impulse_bits - 1));
|
||||
imp_t* imp = imp_in;
|
||||
imp_t* fimp = impulse;
|
||||
for ( int n = res / 2 + 1; n--; )
|
||||
{
|
||||
int error = unit;
|
||||
for ( int nn = width; nn--; )
|
||||
{
|
||||
long a = ((long) *fimp++ * unit + offset) >> impulse_bits;
|
||||
error -= a - unit;
|
||||
*imp++ = (imp_t) a;
|
||||
}
|
||||
|
||||
// add error to middle
|
||||
imp [-width / 2 - 1] += (imp_t) error;
|
||||
}
|
||||
|
||||
if ( res > 2 )
|
||||
{
|
||||
// second half is mirror-image
|
||||
const imp_t* rev = imp - width - 1;
|
||||
for ( int nn = (res / 2 - 1) * width - 1; nn--; )
|
||||
*imp++ = *--rev;
|
||||
*imp++ = (imp_t) unit;
|
||||
}
|
||||
|
||||
// copy to odd offset
|
||||
*imp++ = (imp_t) unit;
|
||||
memcpy( imp, imp_in, (res * width - 1) * sizeof *imp );
|
||||
|
||||
/*
|
||||
for ( int i = 0; i < res; i++ )
|
||||
{
|
||||
for ( int j = 0; j < width; j++ )
|
||||
printf( "%6d,", imp_in [i * width + j] - 0x8000 );
|
||||
printf( "\n" );
|
||||
}*/
|
||||
}
|
||||
|
||||
const int max_res = 1 << blip_res_bits_;
|
||||
|
||||
void Blip_Impulse_::fine_volume_unit()
|
||||
{
|
||||
// to do: find way of merging in-place without temporary buffer
|
||||
|
||||
imp_t temp [max_res * 2 * Blip_Buffer::widest_impulse_];
|
||||
scale_impulse( (offset & 0xffff) << fine_bits, temp );
|
||||
imp_t* imp2 = impulses + res * 2 * width;
|
||||
scale_impulse( offset & 0xffff, imp2 );
|
||||
|
||||
// merge impulses
|
||||
imp_t* imp = impulses;
|
||||
imp_t* src2 = temp;
|
||||
for ( int n = res / 2 * 2 * width; n--; )
|
||||
{
|
||||
*imp++ = *imp2++;
|
||||
*imp++ = *imp2++;
|
||||
*imp++ = *src2++;
|
||||
*imp++ = *src2++;
|
||||
}
|
||||
}
|
||||
|
||||
void Blip_Impulse_::volume_unit( double new_unit )
|
||||
{
|
||||
if ( new_unit == volume_unit_ )
|
||||
return;
|
||||
|
||||
if ( generate )
|
||||
treble_eq( blip_eq_t( -8.87, 8800, 44100 ) );
|
||||
|
||||
volume_unit_ = new_unit;
|
||||
|
||||
offset = 0x10001 * (unsigned long) floor( volume_unit_ * 0x10000 + 0.5 );
|
||||
|
||||
if ( fine_bits )
|
||||
fine_volume_unit();
|
||||
else
|
||||
scale_impulse( offset & 0xffff, impulses );
|
||||
}
|
||||
|
||||
static const double pi = 3.1415926535897932384626433832795029L;
|
||||
|
||||
void Blip_Impulse_::treble_eq( const blip_eq_t& new_eq )
|
||||
{
|
||||
if ( !generate && new_eq.treble == eq.treble && new_eq.cutoff == eq.cutoff &&
|
||||
new_eq.sample_rate == eq.sample_rate )
|
||||
return; // already calculated with same parameters
|
||||
|
||||
generate = false;
|
||||
eq = new_eq;
|
||||
|
||||
double treble = pow( 10.0, 1.0 / 20 * eq.treble ); // dB (-6dB = 0.50)
|
||||
if ( treble < 0.000005 )
|
||||
treble = 0.000005;
|
||||
|
||||
const double treble_freq = 22050.0; // treble level at 22 kHz harmonic
|
||||
const double sample_rate = eq.sample_rate;
|
||||
const double pt = treble_freq * 2 / sample_rate;
|
||||
double cutoff = eq.cutoff * 2 / sample_rate;
|
||||
if ( cutoff >= pt * 0.95 || cutoff >= 0.95 )
|
||||
{
|
||||
cutoff = 0.5;
|
||||
treble = 1.0;
|
||||
}
|
||||
|
||||
// DSF Synthesis (See T. Stilson & J. Smith (1996),
|
||||
// Alias-free digital synthesis of classic analog waveforms)
|
||||
|
||||
// reduce adjacent impulse interference by using small part of wide impulse
|
||||
const double n_harm = 4096;
|
||||
const double rolloff = pow( treble, 1.0 / (n_harm * pt - n_harm * cutoff) );
|
||||
const double rescale = 1.0 / pow( rolloff, n_harm * cutoff );
|
||||
|
||||
const double pow_a_n = rescale * pow( rolloff, n_harm );
|
||||
const double pow_a_nc = rescale * pow( rolloff, n_harm * cutoff );
|
||||
|
||||
double total = 0.0;
|
||||
const double to_angle = pi / 2 / n_harm / max_res;
|
||||
|
||||
float buf [max_res * (Blip_Buffer::widest_impulse_ - 2) / 2];
|
||||
const int size = max_res * (width - 2) / 2;
|
||||
for ( int i = size; i--; )
|
||||
{
|
||||
double angle = (i * 2 + 1) * to_angle;
|
||||
|
||||
// equivalent
|
||||
//double y = dsf( angle, n_harm * cutoff, 1.0 );
|
||||
//y -= rescale * dsf( angle, n_harm * cutoff, rolloff );
|
||||
//y += rescale * dsf( angle, n_harm, rolloff );
|
||||
|
||||
const double cos_angle = cos( angle );
|
||||
const double cos_nc_angle = cos( n_harm * cutoff * angle );
|
||||
const double cos_nc1_angle = cos( (n_harm * cutoff - 1.0) * angle );
|
||||
|
||||
double b = 2.0 - 2.0 * cos_angle;
|
||||
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
|
||||
|
||||
double d = 1.0 + rolloff * (rolloff - 2.0 * cos_angle);
|
||||
double c = pow_a_n * rolloff * cos( (n_harm - 1.0) * angle ) -
|
||||
pow_a_n * cos( n_harm * angle ) -
|
||||
pow_a_nc * rolloff * cos_nc1_angle +
|
||||
pow_a_nc * cos_nc_angle;
|
||||
|
||||
// optimization of a / b + c / d
|
||||
double y = (a * d + c * b) / (b * d);
|
||||
|
||||
// fixed window which affects wider impulses more
|
||||
if ( width > 12 )
|
||||
{
|
||||
double window = cos( n_harm / 1.25 / Blip_Buffer::widest_impulse_ * angle );
|
||||
y *= window * window;
|
||||
}
|
||||
|
||||
total += (float) y;
|
||||
buf [i] = (float) y;
|
||||
}
|
||||
|
||||
// integrate runs of length 'max_res'
|
||||
double factor = impulse_amp * 0.5 / total; // 0.5 accounts for other mirrored half
|
||||
imp_t* imp = impulse;
|
||||
const int step = max_res / res;
|
||||
int offset = res > 1 ? max_res : max_res / 2;
|
||||
for ( int n = res / 2 + 1; n--; offset -= step )
|
||||
{
|
||||
for ( int w = -width / 2; w < width / 2; w++ )
|
||||
{
|
||||
double sum = 0;
|
||||
for ( int i = max_res; i--; )
|
||||
{
|
||||
int index = w * max_res + offset + i;
|
||||
if ( index < 0 )
|
||||
index = -index - 1;
|
||||
if ( index < size )
|
||||
sum += buf [index];
|
||||
}
|
||||
*imp++ = (imp_t) floor( sum * factor + (impulse_offset + 0.5) );
|
||||
}
|
||||
}
|
||||
|
||||
// rescale
|
||||
double unit = volume_unit_;
|
||||
if ( unit >= 0 )
|
||||
{
|
||||
volume_unit_ = -1;
|
||||
volume_unit( unit );
|
||||
}
|
||||
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 )
|
||||
{
|
||||
require( buffer_ ); // sample rate must have been set
|
||||
|
||||
if ( !count ) // optimization
|
||||
return;
|
||||
|
||||
remove_silence( count );
|
||||
|
||||
// Allows synthesis slightly past time passed to end_frame(), as long as it's
|
||||
// not more than an output sample.
|
||||
// to do: kind of hacky, could add run_until() which keeps track of extra synthesis
|
||||
int const copy_extra = 1;
|
||||
|
||||
// copy remaining samples to beginning and clear old samples
|
||||
long remain = samples_avail() + widest_impulse_ + copy_extra;
|
||||
if ( count >= remain )
|
||||
memmove( buffer_, buffer_ + count, remain * sizeof (buf_t_) );
|
||||
else
|
||||
memcpy( buffer_, buffer_ + count, remain * sizeof (buf_t_) );
|
||||
memset( buffer_ + remain, sample_offset_ & 0xFF, count * sizeof (buf_t_) );
|
||||
if ( count )
|
||||
{
|
||||
remove_silence( count );
|
||||
|
||||
// copy remaining samples to beginning and clear old samples
|
||||
long remain = samples_avail() + blip_buffer_extra_;
|
||||
memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
|
||||
memset( buffer_ + remain, 0, count * sizeof *buffer_ );
|
||||
}
|
||||
}
|
||||
|
||||
#include BLARGG_ENABLE_OPTIMIZER
|
||||
// Blip_Synth_
|
||||
|
||||
long Blip_Buffer::read_samples( blip_sample_t* out, long max_samples, bool stereo )
|
||||
Blip_Synth_Fast_::Blip_Synth_Fast_()
|
||||
{
|
||||
buf = 0;
|
||||
last_amp = 0;
|
||||
delta_factor = 0;
|
||||
}
|
||||
|
||||
void Blip_Synth_Fast_::volume_unit( double new_unit )
|
||||
{
|
||||
delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5);
|
||||
}
|
||||
|
||||
#if !BLIP_BUFFER_FAST
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#undef PI
|
||||
#define 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 angle_maxh = angle * maxh;
|
||||
double angle_maxh_mid = angle_maxh * cutoff;
|
||||
|
||||
double y = maxh;
|
||||
|
||||
// 0 to Fs/2*cutoff, flat
|
||||
if ( angle_maxh_mid ) // unstable at t=0
|
||||
y *= sin( angle_maxh_mid ) / angle_maxh_mid;
|
||||
|
||||
// Fs/2*cutoff to Fs/2, logarithmic rolloff
|
||||
double cosa = cos( angle );
|
||||
double den = 1 + rolloff * (rolloff - cosa - cosa);
|
||||
|
||||
// Becomes unstable when rolloff is near 1.0 and t is near 0,
|
||||
// which is the only time den becomes small
|
||||
if ( den > 1e-13 )
|
||||
{
|
||||
double num =
|
||||
(cos( angle_maxh - angle ) * rolloff - cos( angle_maxh )) * pow_a_n -
|
||||
cos( angle_maxh_mid - angle ) * rolloff + cos( angle_maxh_mid );
|
||||
|
||||
y = y * cutoff + num / den;
|
||||
}
|
||||
|
||||
out [i] = (float) y;
|
||||
}
|
||||
}
|
||||
|
||||
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.54f - 0.46f * (float) 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] += (short) 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 );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
long Blip_Buffer::read_samples( blip_sample_t* BLIP_RESTRICT out, long max_samples, int stereo )
|
||||
{
|
||||
require( buffer_ ); // sample rate must have been set
|
||||
|
||||
long count = samples_avail();
|
||||
if ( count > max_samples )
|
||||
count = max_samples;
|
||||
|
||||
if ( !count )
|
||||
return 0; // optimization
|
||||
|
||||
int sample_offset_ = this->sample_offset_;
|
||||
int bass_shift = this->bass_shift;
|
||||
buf_t_* buf = buffer_;
|
||||
long accum = reader_accum;
|
||||
|
||||
if ( !stereo )
|
||||
|
||||
if ( count )
|
||||
{
|
||||
for ( long n = count; n--; )
|
||||
int const bass = BLIP_READER_BASS( *this );
|
||||
BLIP_READER_BEGIN( reader, *this );
|
||||
|
||||
if ( !stereo )
|
||||
{
|
||||
long s = accum >> accum_fract;
|
||||
accum -= accum >> bass_shift;
|
||||
accum += (long (*buf++) - sample_offset_) << accum_fract;
|
||||
*out++ = (blip_sample_t) s;
|
||||
|
||||
// clamp sample
|
||||
if ( (BOOST::int16_t) s != s )
|
||||
out [-1] = blip_sample_t (0x7FFF - (s >> 24));
|
||||
for ( blip_long n = count; n; --n )
|
||||
{
|
||||
blip_long s = BLIP_READER_READ( reader );
|
||||
if ( (blip_sample_t) s != s )
|
||||
s = 0x7FFF - (s >> 24);
|
||||
*out++ = (blip_sample_t) s;
|
||||
BLIP_READER_NEXT( reader, bass );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( long n = count; n--; )
|
||||
else
|
||||
{
|
||||
long s = accum >> accum_fract;
|
||||
accum -= accum >> bass_shift;
|
||||
accum += (long (*buf++) - sample_offset_) << accum_fract;
|
||||
*out = (blip_sample_t) s;
|
||||
out += 2;
|
||||
|
||||
// clamp sample
|
||||
if ( (BOOST::int16_t) s != s )
|
||||
out [-2] = blip_sample_t (0x7FFF - (s >> 24));
|
||||
for ( blip_long n = count; n; --n )
|
||||
{
|
||||
blip_long s = BLIP_READER_READ( reader );
|
||||
if ( (blip_sample_t) s != s )
|
||||
s = 0x7FFF - (s >> 24);
|
||||
*out = (blip_sample_t) s;
|
||||
out += 2;
|
||||
BLIP_READER_NEXT( reader, bass );
|
||||
}
|
||||
}
|
||||
BLIP_READER_END( reader, *this );
|
||||
|
||||
remove_samples( count );
|
||||
}
|
||||
|
||||
reader_accum = accum;
|
||||
|
||||
remove_samples( count );
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void Blip_Buffer::mix_samples( const blip_sample_t* in, long count )
|
||||
void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
|
||||
{
|
||||
buf_t_* buf = &buffer_ [(offset_ >> BLIP_BUFFER_ACCURACY) + (widest_impulse_ / 2 - 1)];
|
||||
|
||||
if ( buffer_size_ == silent_buf_size )
|
||||
{
|
||||
assert( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
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-- )
|
||||
{
|
||||
int s = *in++;
|
||||
*buf += s - prev;
|
||||
blip_long s = (blip_long) *in++ << sample_shift;
|
||||
*out += s - prev;
|
||||
prev = s;
|
||||
++buf;
|
||||
++out;
|
||||
}
|
||||
*buf -= *--in;
|
||||
*out -= prev;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,259 +1,488 @@
|
||||
// Band-limited sound synthesis buffer
|
||||
|
||||
// Buffer of sound samples into which band-limited waveforms can be synthesized
|
||||
// using Blip_Wave or Blip_Synth.
|
||||
|
||||
// Blip_Buffer 0.3.4. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
|
||||
|
||||
// Blip_Buffer 0.4.1
|
||||
#ifndef BLIP_BUFFER_H
|
||||
#define BLIP_BUFFER_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
// internal
|
||||
#include <limits.h>
|
||||
#if INT_MAX < 0x7FFFFFFF
|
||||
#error "int must be at least 32 bits"
|
||||
#endif
|
||||
|
||||
typedef int blip_long;
|
||||
typedef unsigned blip_ulong;
|
||||
|
||||
class Blip_Reader;
|
||||
// Time unit at source clock rate
|
||||
typedef blip_long blip_time_t;
|
||||
|
||||
// Source time unit.
|
||||
typedef long blip_time_t;
|
||||
|
||||
// Type of sample produced. Signed 16-bit format.
|
||||
typedef BOOST::int16_t blip_sample_t;
|
||||
|
||||
// Make buffer as large as possible (currently about 65000 samples)
|
||||
const int blip_default_length = 0;
|
||||
|
||||
typedef unsigned long blip_resampled_time_t; // not documented
|
||||
// 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:
|
||||
// Construct an empty buffer.
|
||||
Blip_Buffer();
|
||||
~Blip_Buffer();
|
||||
typedef const char* blargg_err_t;
|
||||
|
||||
// Set output sample rate and buffer length in milliseconds (1/1000 sec),
|
||||
// then clear buffer. If length is not specified, make as large as possible.
|
||||
// If there is insufficient memory for the buffer, sets the buffer length
|
||||
// to 0 and returns error string (or propagates exception if compiler supports it).
|
||||
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = blip_default_length );
|
||||
// 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;
|
||||
|
||||
// Current output sample rate
|
||||
long sample_rate() const;
|
||||
|
||||
// Number of source time units per second
|
||||
void clock_rate( long );
|
||||
long clock_rate() const;
|
||||
|
||||
// Set frequency at which high-pass filter attenuation passes -3dB
|
||||
// Set frequency high-pass filter frequency, where higher values reduce bass more
|
||||
void bass_freq( int frequency );
|
||||
|
||||
// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
|
||||
// false, just clear out any samples waiting rather than the entire buffer.
|
||||
void clear( bool entire_buffer = true );
|
||||
|
||||
// End current time frame of specified duration and make its samples available
|
||||
// (along with any still-unread samples) for reading with read_samples(). Begin
|
||||
// a new time frame at the end of the current frame. All transitions must have
|
||||
// been added before 'time'.
|
||||
void end_frame( blip_time_t time );
|
||||
|
||||
// Number of samples available for reading with read_samples()
|
||||
long samples_avail() const;
|
||||
|
||||
// Read at most 'max_samples' out of buffer into 'dest', removing them from from
|
||||
// the buffer. Return number of samples actually read and removed. If stereo is
|
||||
// true, increment '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, bool stereo = false );
|
||||
|
||||
// Remove 'count' samples from those waiting to be read
|
||||
void remove_samples( long count );
|
||||
|
||||
// Number of samples delay from synthesis to samples read out
|
||||
int output_latency() const;
|
||||
|
||||
// Beta features
|
||||
// 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 raw samples that can be mixed within frame of specified duration
|
||||
long count_samples( blip_time_t duration ) const;
|
||||
// Number of samples available for reading with read_samples()
|
||||
long samples_avail() const;
|
||||
|
||||
// Mix 'count' samples from 'buf' into buffer.
|
||||
void mix_samples( const blip_sample_t* buf, long count );
|
||||
// Remove 'count' samples from those waiting to be read
|
||||
void remove_samples( long count );
|
||||
|
||||
// Experimental features
|
||||
|
||||
// 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 is full.
|
||||
// buffer becomes full.
|
||||
blip_time_t count_clocks( long count ) const;
|
||||
|
||||
// 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 );
|
||||
|
||||
// not documented yet
|
||||
|
||||
void set_modified() { modified_ = 1; }
|
||||
int clear_modified() { int b = modified_; modified_ = 0; return b; }
|
||||
typedef blip_ulong blip_resampled_time_t;
|
||||
void remove_silence( long count );
|
||||
|
||||
blip_resampled_time_t resampled_time( blip_time_t t ) const
|
||||
{
|
||||
return t * blip_resampled_time_t (factor_) + offset_;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
blip_resampled_time_t resampled_duration( int t ) const
|
||||
{
|
||||
return t * blip_resampled_time_t (factor_);
|
||||
}
|
||||
|
||||
// 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& );
|
||||
|
||||
// Don't use the following members. They are public only for technical reasons.
|
||||
public:
|
||||
enum { sample_offset_ = 0x7F7F }; // repeated byte allows memset to clear buffer
|
||||
enum { widest_impulse_ = 24 };
|
||||
typedef BOOST::uint16_t buf_t_;
|
||||
|
||||
unsigned long factor_;
|
||||
blip_resampled_time_t offset_;
|
||||
buf_t_* buffer_;
|
||||
unsigned buffer_size_;
|
||||
private:
|
||||
long reader_accum;
|
||||
int bass_shift;
|
||||
long samples_per_sec;
|
||||
long clocks_per_sec;
|
||||
int bass_freq_;
|
||||
int length_;
|
||||
|
||||
enum { accum_fract = 15 }; // less than 16 to give extra sample range
|
||||
|
||||
friend class Blip_Reader;
|
||||
};
|
||||
|
||||
// Low-pass equalization parameters (see notes.txt)
|
||||
class blip_eq_t {
|
||||
public:
|
||||
blip_eq_t( double treble = 0 );
|
||||
blip_eq_t( double treble, long cutoff, long sample_rate );
|
||||
typedef blip_time_t buf_t_;
|
||||
blip_ulong factor_;
|
||||
blip_resampled_time_t offset_;
|
||||
buf_t_* buffer_;
|
||||
blip_long buffer_size_;
|
||||
blip_long reader_accum_;
|
||||
int bass_shift_;
|
||||
private:
|
||||
double treble;
|
||||
long cutoff;
|
||||
long sample_rate;
|
||||
friend class Blip_Impulse_;
|
||||
long sample_rate_;
|
||||
long clock_rate_;
|
||||
int bass_freq_;
|
||||
int length_;
|
||||
int modified_;
|
||||
friend class Blip_Reader;
|
||||
};
|
||||
|
||||
// not documented yet (see Multi_Buffer.cpp for an example of use)
|
||||
class Blip_Reader {
|
||||
const Blip_Buffer::buf_t_* buf;
|
||||
long accum;
|
||||
#ifdef __MWERKS__
|
||||
void operator = ( struct foobar ); // helps optimizer
|
||||
#endif
|
||||
public:
|
||||
// avoid anything which might cause optimizer to put object in memory
|
||||
|
||||
int begin( Blip_Buffer& blip_buf ) {
|
||||
buf = blip_buf.buffer_;
|
||||
accum = blip_buf.reader_accum;
|
||||
return blip_buf.bass_shift;
|
||||
}
|
||||
|
||||
int read() const {
|
||||
return accum >> Blip_Buffer::accum_fract;
|
||||
}
|
||||
|
||||
void next( int bass_shift = 9 ) {
|
||||
accum -= accum >> bass_shift;
|
||||
accum += ((long) *buf++ - Blip_Buffer::sample_offset_) << Blip_Buffer::accum_fract;
|
||||
}
|
||||
|
||||
void end( Blip_Buffer& blip_buf ) {
|
||||
blip_buf.reader_accum = accum;
|
||||
}
|
||||
};
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// End of public interface
|
||||
|
||||
// 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
|
||||
|
||||
const int blip_res_bits_ = 5;
|
||||
|
||||
typedef BOOST::uint32_t blip_pair_t_;
|
||||
|
||||
class Blip_Impulse_ {
|
||||
typedef BOOST::uint16_t imp_t;
|
||||
|
||||
blip_eq_t eq;
|
||||
double volume_unit_;
|
||||
imp_t* impulses;
|
||||
imp_t* impulse;
|
||||
int width;
|
||||
int fine_bits;
|
||||
int res;
|
||||
bool generate;
|
||||
|
||||
void fine_volume_unit();
|
||||
void scale_impulse( int unit, imp_t* ) const;
|
||||
public:
|
||||
Blip_Buffer* buf;
|
||||
BOOST::uint32_t offset;
|
||||
|
||||
void init( blip_pair_t_* impulses, int width, int res, int fine_bits = 0 );
|
||||
void volume_unit( double );
|
||||
void treble_eq( const blip_eq_t& );
|
||||
};
|
||||
|
||||
inline blip_eq_t::blip_eq_t( double t ) :
|
||||
treble( t ), cutoff( 0 ), sample_rate( 44100 ) {
|
||||
}
|
||||
|
||||
inline blip_eq_t::blip_eq_t( double t, long c, long sr ) :
|
||||
treble( t ), cutoff( c ), sample_rate( sr ) {
|
||||
}
|
||||
|
||||
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 samples_per_sec;
|
||||
}
|
||||
|
||||
inline void Blip_Buffer::end_frame( blip_time_t t ) {
|
||||
offset_ += t * factor_;
|
||||
/* assert(( "Blip_Buffer::end_frame(): Frame went past end of buffer",
|
||||
samples_avail() <= (long) buffer_size_ ));*/
|
||||
}
|
||||
|
||||
inline void Blip_Buffer::remove_silence( long count ) {
|
||||
/* assert(( "Blip_Buffer::remove_silence(): Tried to remove more samples than available",
|
||||
count <= samples_avail() ));*/
|
||||
offset_ -= blip_resampled_time_t (count) << BLIP_BUFFER_ACCURACY;
|
||||
}
|
||||
|
||||
inline int Blip_Buffer::output_latency() const {
|
||||
return widest_impulse_ / 2;
|
||||
}
|
||||
|
||||
inline long Blip_Buffer::clock_rate() const {
|
||||
return clocks_per_sec;
|
||||
}
|
||||
|
||||
inline void Blip_Buffer::clock_rate( long cps )
|
||||
{
|
||||
clocks_per_sec = cps;
|
||||
factor_ = clock_rate_factor( cps );
|
||||
}
|
||||
|
||||
#include "Blip_Synth.h"
|
||||
|
||||
// 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
|
||||
#if BLIP_BUFFER_FAST
|
||||
#define BLIP_PHASE_BITS 8
|
||||
#else
|
||||
#define BLIP_PHASE_BITS 6
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Internal
|
||||
typedef blip_ulong blip_resampled_time_t;
|
||||
int const blip_widest_impulse_ = 16;
|
||||
int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
|
||||
int const blip_res = 1 << BLIP_PHASE_BITS;
|
||||
class blip_eq_t;
|
||||
|
||||
class Blip_Synth_Fast_ {
|
||||
public:
|
||||
Blip_Buffer* buf;
|
||||
int last_amp;
|
||||
int delta_factor;
|
||||
|
||||
void volume_unit( double );
|
||||
Blip_Synth_Fast_();
|
||||
void treble_eq( blip_eq_t const& ) { }
|
||||
};
|
||||
|
||||
class Blip_Synth_ {
|
||||
public:
|
||||
Blip_Buffer* buf;
|
||||
int last_amp;
|
||||
int delta_factor;
|
||||
|
||||
void volume_unit( double );
|
||||
Blip_Synth_( short* impulses, int width );
|
||||
void treble_eq( blip_eq_t const& );
|
||||
private:
|
||||
double volume_unit_;
|
||||
short* const impulses;
|
||||
int const width;
|
||||
blip_long kernel_unit;
|
||||
int impulses_size() const { return blip_res / 2 * width + 1; }
|
||||
void adjust_impulse();
|
||||
};
|
||||
|
||||
// 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 blip_buffer.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 info.
|
||||
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 );
|
||||
}
|
||||
|
||||
private:
|
||||
#if BLIP_BUFFER_FAST
|
||||
Blip_Synth_Fast_ impl;
|
||||
#else
|
||||
Blip_Synth_ impl;
|
||||
typedef short imp_t;
|
||||
imp_t impulses [blip_res * (quality / 2) + 1];
|
||||
public:
|
||||
Blip_Synth() : impl( impulses, quality ) { }
|
||||
#endif
|
||||
};
|
||||
|
||||
// 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 blip_buffer.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;
|
||||
|
||||
// Dummy Blip_Buffer to direct sound output to, for easy muting without
|
||||
// having to stop sound code.
|
||||
class Silent_Blip_Buffer : public Blip_Buffer {
|
||||
buf_t_ buf [blip_buffer_extra_ + 1];
|
||||
public:
|
||||
// The following cannot be used (an assertion will fail if attempted):
|
||||
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
|
||||
blip_time_t count_clocks( long count ) const;
|
||||
void mix_samples( blip_sample_t const* buf, long count );
|
||||
|
||||
Silent_Blip_Buffer();
|
||||
};
|
||||
|
||||
#if defined (__GNUC__) || _MSC_VER >= 1100
|
||||
#define BLIP_RESTRICT __restrict
|
||||
#else
|
||||
#define BLIP_RESTRICT
|
||||
#endif
|
||||
|
||||
// Optimized reading from Blip_Buffer, for use in custom sample output
|
||||
|
||||
// Begin reading from buffer. Name should be unique to the current block.
|
||||
#define BLIP_READER_BEGIN( name, blip_buffer ) \
|
||||
const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
|
||||
blip_long name##_reader_accum = (blip_buffer).reader_accum_
|
||||
|
||||
// Get value to pass to BLIP_READER_NEXT()
|
||||
#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
|
||||
|
||||
// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
|
||||
// code at the cost of having no bass control
|
||||
int const blip_reader_default_bass = 9;
|
||||
|
||||
// Current sample
|
||||
#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))
|
||||
|
||||
// Current raw sample in full internal resolution
|
||||
#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)
|
||||
|
||||
// Advance to next sample
|
||||
#define BLIP_READER_NEXT( name, bass ) \
|
||||
(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
|
||||
|
||||
// End reading samples from buffer. The number of samples read must now be removed
|
||||
// using Blip_Buffer::remove_samples().
|
||||
#define BLIP_READER_END( name, blip_buffer ) \
|
||||
(void) ((blip_buffer).reader_accum_ = name##_reader_accum)
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
// Deprecated; use BLIP_READER macros as follows:
|
||||
// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
|
||||
// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
|
||||
// r.read() -> BLIP_READER_READ( r )
|
||||
// r.read_raw() -> BLIP_READER_READ_RAW( r )
|
||||
// r.next( bass ) -> BLIP_READER_NEXT( r, bass )
|
||||
// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )
|
||||
// r.end( buf ) -> BLIP_READER_END( r, buf )
|
||||
class Blip_Reader {
|
||||
public:
|
||||
int begin( Blip_Buffer& );
|
||||
blip_long read() const { return accum >> (blip_sample_bits - 16); }
|
||||
blip_long read_raw() const { return accum; }
|
||||
void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
|
||||
void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }
|
||||
|
||||
private:
|
||||
const Blip_Buffer::buf_t_* buf;
|
||||
blip_long accum;
|
||||
};
|
||||
|
||||
// End of public interface
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
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( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
|
||||
delta *= impl.delta_factor;
|
||||
blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
|
||||
int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
|
||||
|
||||
#if BLIP_BUFFER_FAST
|
||||
blip_long left = buf [0] + delta;
|
||||
|
||||
// Kind of crappy, but doing shift after multiply results in overflow.
|
||||
// Alternate way of delaying multiply by delta_factor results in worse
|
||||
// sub-sample resolution.
|
||||
blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
|
||||
left -= right;
|
||||
right += buf [1];
|
||||
|
||||
buf [0] = left;
|
||||
buf [1] = right;
|
||||
#else
|
||||
|
||||
int const fwd = (blip_widest_impulse_ - quality) / 2;
|
||||
int const rev = fwd + quality - 2;
|
||||
int const mid = quality / 2 - 1;
|
||||
|
||||
imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
|
||||
|
||||
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
|
||||
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
|
||||
|
||||
// straight forward implementation resulted in better code on GCC for x86
|
||||
|
||||
#define ADD_IMP( out, in ) \
|
||||
buf [out] += (blip_long) imp [blip_res * (in)] * delta
|
||||
|
||||
#define BLIP_FWD( i ) {\
|
||||
ADD_IMP( fwd + i, i );\
|
||||
ADD_IMP( fwd + 1 + i, i + 1 );\
|
||||
}
|
||||
#define BLIP_REV( r ) {\
|
||||
ADD_IMP( rev - r, r + 1 );\
|
||||
ADD_IMP( rev + 1 - r, r );\
|
||||
}
|
||||
|
||||
BLIP_FWD( 0 )
|
||||
if ( quality > 8 ) BLIP_FWD( 2 )
|
||||
if ( quality > 12 ) BLIP_FWD( 4 )
|
||||
{
|
||||
ADD_IMP( fwd + mid - 1, mid - 1 );
|
||||
ADD_IMP( fwd + mid , mid );
|
||||
imp = impulses + phase;
|
||||
}
|
||||
if ( quality > 12 ) BLIP_REV( 6 )
|
||||
if ( quality > 8 ) BLIP_REV( 4 )
|
||||
BLIP_REV( 2 )
|
||||
|
||||
ADD_IMP( rev , 1 );
|
||||
ADD_IMP( rev + 1, 0 );
|
||||
|
||||
#else
|
||||
|
||||
// for RISC processors, help compiler by reading ahead of writes
|
||||
|
||||
#define BLIP_FWD( i ) {\
|
||||
blip_long t0 = i0 * delta + buf [fwd + i];\
|
||||
blip_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 ) {\
|
||||
blip_long t0 = i0 * delta + buf [rev - r];\
|
||||
blip_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;\
|
||||
}
|
||||
|
||||
blip_long i0 = *imp;
|
||||
BLIP_FWD( 0 )
|
||||
if ( quality > 8 ) BLIP_FWD( 2 )
|
||||
if ( quality > 12 ) BLIP_FWD( 4 )
|
||||
{
|
||||
blip_long t0 = i0 * delta + buf [fwd + mid - 1];
|
||||
blip_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 )
|
||||
|
||||
blip_long t0 = i0 * delta + buf [rev ];
|
||||
blip_long t1 = *imp * delta + buf [rev + 1];
|
||||
buf [rev ] = t0;
|
||||
buf [rev + 1] = t1;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef BLIP_FWD
|
||||
#undef BLIP_REV
|
||||
|
||||
template<int quality,int range>
|
||||
#if BLIP_BUFFER_FAST
|
||||
inline
|
||||
#endif
|
||||
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>
|
||||
#if BLIP_BUFFER_FAST
|
||||
inline
|
||||
#endif
|
||||
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,208 +0,0 @@
|
||||
|
||||
// Blip_Synth and Blip_Wave are waveform transition synthesizers for adding
|
||||
// waveforms to a Blip_Buffer.
|
||||
|
||||
// Blip_Buffer 0.3.4. 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;
|
||||
void init() { impulse.init( impulses, width, res, fine_bits ); }
|
||||
public:
|
||||
Blip_Synth() { init(); }
|
||||
Blip_Synth( double volume ) { init(); this->volume( volume ); }
|
||||
|
||||
// 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 a magnitude of delta * volume_unit
|
||||
// into the specified buffer (default buffer if none specified) at the
|
||||
// specified source time. Delta 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, nothing more.
|
||||
template<int quality,int range>
|
||||
class Blip_Wave {
|
||||
Blip_Synth<quality,range> synth;
|
||||
blip_time_t time_;
|
||||
int last_amp;
|
||||
void init() { time_ = 0; last_amp = 0; }
|
||||
public:
|
||||
// Start wave at time 0 and amplitude 0
|
||||
Blip_Wave() { init(); }
|
||||
Blip_Wave( double volume ) { init(); this->volume( volume ); }
|
||||
|
||||
// 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.
|
||||
// If wave hadn't been run to end of frame, start it at beginning of new frame.
|
||||
void end_frame( blip_time_t duration )
|
||||
{
|
||||
time_ -= duration;
|
||||
if ( time_ < 0 )
|
||||
time_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// 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,28 +1,29 @@
|
||||
|
||||
// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/libs/
|
||||
// Gb_Snd_Emu 0.1.5. http://www.slack.net/~ant/
|
||||
|
||||
#include "Gb_Apu.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Copyright (C) 2003-2005 Shay Green. This module is free software; you
|
||||
/* 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 */
|
||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
#include "blargg_source.h"
|
||||
|
||||
unsigned const vol_reg = 0xFF24;
|
||||
unsigned const status_reg = 0xFF26;
|
||||
|
||||
Gb_Apu::Gb_Apu()
|
||||
{
|
||||
square1.synth = &square_synth;
|
||||
square2.synth = &square_synth;
|
||||
square1.has_sweep = true;
|
||||
wave.synth = &other_synth;
|
||||
noise.synth = &other_synth;
|
||||
|
||||
@@ -31,25 +32,37 @@ Gb_Apu::Gb_Apu()
|
||||
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 = 0;
|
||||
osc.outputs [0] = 0;
|
||||
osc.outputs [1] = 0;
|
||||
osc.outputs [2] = 0;
|
||||
osc.outputs [3] = 0;
|
||||
}
|
||||
|
||||
set_tempo( 1.0 );
|
||||
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::volume( double vol )
|
||||
void Gb_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
|
||||
{
|
||||
vol *= 0.60 / osc_count;
|
||||
square_synth.volume( vol );
|
||||
other_synth.volume( vol );
|
||||
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 )
|
||||
@@ -58,44 +71,62 @@ void Gb_Apu::output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right
|
||||
osc_output( i, center, left, right );
|
||||
}
|
||||
|
||||
void Gb_Apu::update_volume()
|
||||
{
|
||||
// TODO: doesn't handle differing left/right global volume (support would
|
||||
// require modification to all oscillator code)
|
||||
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 [0x20] = {
|
||||
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
|
||||
};
|
||||
|
||||
void Gb_Apu::set_tempo( double t )
|
||||
{
|
||||
frame_period = 4194304 / 256; // 256 Hz
|
||||
if ( t != 1.0 )
|
||||
frame_period = blip_time_t (frame_period / t);
|
||||
}
|
||||
|
||||
void Gb_Apu::reset()
|
||||
{
|
||||
next_frame_time = 0;
|
||||
last_time = 0;
|
||||
frame_count = 0;
|
||||
stereo_found = false;
|
||||
last_time = 0;
|
||||
frame_count = 0;
|
||||
|
||||
square1.reset();
|
||||
square2.reset();
|
||||
wave.reset();
|
||||
noise.reset();
|
||||
noise.bits = 1;
|
||||
wave.wave_pos = 0;
|
||||
|
||||
memset( regs, 0, sizeof regs );
|
||||
// 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 );
|
||||
|
||||
static unsigned char const initial_wave [] = {
|
||||
0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table
|
||||
0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA
|
||||
};
|
||||
memcpy( wave.wave, initial_wave, sizeof wave.wave );
|
||||
}
|
||||
|
||||
void Gb_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
|
||||
{
|
||||
require( (unsigned) index < osc_count );
|
||||
|
||||
Gb_Osc& osc = *oscs [index];
|
||||
if ( center && !left && !right )
|
||||
{
|
||||
// mono
|
||||
left = center;
|
||||
right = center;
|
||||
}
|
||||
else
|
||||
{
|
||||
// must be silenced or stereo
|
||||
require( (!left && !right) || (left && right) );
|
||||
}
|
||||
osc.outputs [1] = right;
|
||||
osc.outputs [2] = left;
|
||||
osc.outputs [3] = center;
|
||||
osc.output = osc.outputs [osc.output_select];
|
||||
}
|
||||
|
||||
void Gb_Apu::run_until( gb_time_t end_time )
|
||||
void Gb_Apu::run_until( blip_time_t end_time )
|
||||
{
|
||||
require( end_time >= last_time ); // end_time must not be before previous time
|
||||
if ( end_time == last_time )
|
||||
@@ -103,17 +134,28 @@ void Gb_Apu::run_until( gb_time_t end_time )
|
||||
|
||||
while ( true )
|
||||
{
|
||||
gb_time_t time = next_frame_time;
|
||||
blip_time_t time = next_frame_time;
|
||||
if ( time > end_time )
|
||||
time = end_time;
|
||||
|
||||
// run oscillators
|
||||
for ( int i = 0; i < osc_count; ++i ) {
|
||||
for ( int i = 0; i < osc_count; ++i )
|
||||
{
|
||||
Gb_Osc& osc = *oscs [i];
|
||||
if ( osc.output ) {
|
||||
if ( osc.output != osc.outputs [3] )
|
||||
stereo_found = true;
|
||||
osc.run( last_time, time );
|
||||
if ( osc.output )
|
||||
{
|
||||
osc.output->set_modified(); // TODO: misses optimization opportunities?
|
||||
int playing = false;
|
||||
if ( osc.enabled && osc.volume &&
|
||||
(!(osc.regs [4] & osc.len_enabled_mask) || osc.length) )
|
||||
playing = -1;
|
||||
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;
|
||||
@@ -121,7 +163,7 @@ void Gb_Apu::run_until( gb_time_t end_time )
|
||||
if ( time == end_time )
|
||||
break;
|
||||
|
||||
next_frame_time += 4194304 / 256; // 256 Hz
|
||||
next_frame_time += frame_period;
|
||||
|
||||
// 256 Hz actions
|
||||
square1.clock_length();
|
||||
@@ -130,7 +172,8 @@ void Gb_Apu::run_until( gb_time_t end_time )
|
||||
noise.clock_length();
|
||||
|
||||
frame_count = (frame_count + 1) & 3;
|
||||
if ( frame_count == 0 ) {
|
||||
if ( frame_count == 0 )
|
||||
{
|
||||
// 64 Hz actions
|
||||
square1.clock_envelope();
|
||||
square2.clock_envelope();
|
||||
@@ -142,7 +185,7 @@ void Gb_Apu::run_until( gb_time_t end_time )
|
||||
}
|
||||
}
|
||||
|
||||
bool Gb_Apu::end_frame( gb_time_t end_time )
|
||||
void Gb_Apu::end_frame( blip_time_t end_time )
|
||||
{
|
||||
if ( end_time > last_time )
|
||||
run_until( end_time );
|
||||
@@ -152,13 +195,9 @@ bool Gb_Apu::end_frame( gb_time_t 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 )
|
||||
void Gb_Apu::write_register( blip_time_t time, unsigned addr, int data )
|
||||
{
|
||||
require( (unsigned) data < 0x100 );
|
||||
|
||||
@@ -168,48 +207,39 @@ void Gb_Apu::write_register( gb_time_t time, gb_addr_t addr, int data )
|
||||
|
||||
run_until( time );
|
||||
|
||||
int old_reg = regs [reg];
|
||||
regs [reg] = data;
|
||||
|
||||
if ( addr < 0xff24 )
|
||||
if ( addr < vol_reg )
|
||||
{
|
||||
// oscillator
|
||||
int index = reg / 5;
|
||||
oscs [index]->write_register( reg - index * 5, data );
|
||||
write_osc( reg / 5, reg, data );
|
||||
}
|
||||
// added
|
||||
else if ( addr == 0xff24 )
|
||||
else if ( addr == vol_reg && data != old_reg ) // global volume
|
||||
{
|
||||
int global_volume = data & 7;
|
||||
int old_volume = square1.global_volume;
|
||||
if ( old_volume != global_volume )
|
||||
// return all oscs to 0
|
||||
for ( int i = 0; i < osc_count; i++ )
|
||||
{
|
||||
int any_enabled = false;
|
||||
for ( int i = 0; i < osc_count; i++ )
|
||||
{
|
||||
Gb_Osc& osc = *oscs [i];
|
||||
if ( osc.enabled )
|
||||
{
|
||||
if ( osc.last_amp )
|
||||
{
|
||||
int new_amp = osc.last_amp * global_volume / osc.global_volume;
|
||||
if ( osc.output )
|
||||
square_synth.offset( time, new_amp - osc.last_amp, osc.output );
|
||||
osc.last_amp = new_amp;
|
||||
}
|
||||
any_enabled |= osc.volume;
|
||||
}
|
||||
osc.global_volume = global_volume;
|
||||
}
|
||||
|
||||
if ( !any_enabled && square1.outputs [3] )
|
||||
square_synth.offset( time, (global_volume - old_volume) * 15 * 2, square1.outputs [3] );
|
||||
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 == 0xff26 )
|
||||
else if ( addr == 0xFF25 || addr == status_reg )
|
||||
{
|
||||
int mask = (regs [0xff26 - start_addr] & 0x80) ? ~0 : 0;
|
||||
int flags = regs [0xff25 - start_addr] & mask;
|
||||
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++ )
|
||||
@@ -220,42 +250,57 @@ void Gb_Apu::write_register( gb_time_t time, gb_addr_t addr, int data )
|
||||
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 && osc.last_amp )
|
||||
if ( osc.output != old_output )
|
||||
{
|
||||
if ( old_output )
|
||||
square_synth.offset( time, -osc.last_amp, 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 ( unsigned i = 0; i < sizeof powerup_regs; i++ )
|
||||
{
|
||||
if ( i != status_reg - start_addr )
|
||||
write_register( time, i + start_addr, powerup_regs [i] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//debug_printf( "APU powered on\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( addr >= 0xff30 )
|
||||
else if ( addr >= 0xFF30 )
|
||||
{
|
||||
int index = (addr & 0x0f) * 2;
|
||||
int index = (addr & 0x0F) * 2;
|
||||
wave.wave [index] = data >> 4;
|
||||
wave.wave [index + 1] = data & 0x0f;
|
||||
wave.wave [index + 1] = data & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
int Gb_Apu::read_register( gb_time_t time, gb_addr_t addr )
|
||||
int Gb_Apu::read_register( blip_time_t time, unsigned addr )
|
||||
{
|
||||
// function now takes actual address, i.e. 0xFFXX
|
||||
require( start_addr <= addr && addr < end_addr );
|
||||
|
||||
run_until( time );
|
||||
|
||||
int data = regs [addr - start_addr];
|
||||
int index = addr - start_addr;
|
||||
require( (unsigned) index < register_count );
|
||||
int data = regs [index];
|
||||
|
||||
if ( addr == 0xff26 )
|
||||
if ( addr == status_reg )
|
||||
{
|
||||
data &= 0xf0;
|
||||
data = (data & 0x80) | 0x70;
|
||||
for ( int i = 0; i < osc_count; i++ )
|
||||
{
|
||||
const Gb_Osc& osc = *oscs [i];
|
||||
if ( osc.enabled && (osc.length || !osc.length_enabled) )
|
||||
if ( osc.enabled && (osc.length || !(osc.regs [4] & osc.len_enabled_mask)) )
|
||||
data |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
|
||||
// Nintendo Game Boy PAPU sound chip emulator
|
||||
|
||||
// Gb_Snd_Emu 0.1.4. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
|
||||
|
||||
// Gb_Snd_Emu 0.1.5
|
||||
#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:
|
||||
Gb_Apu();
|
||||
~Gb_Apu();
|
||||
|
||||
// Set overall volume of all oscillators, where 1.0 is full volume
|
||||
void volume( double );
|
||||
@@ -22,63 +15,76 @@ public:
|
||||
// Set treble equalization
|
||||
void treble_eq( const blip_eq_t& );
|
||||
|
||||
// Reset oscillators and internal state
|
||||
void reset();
|
||||
// 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, silence all oscillators.
|
||||
// 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, silence oscillator.
|
||||
// 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();
|
||||
|
||||
// Reads and writes at addr must satisfy start_addr <= addr <= end_addr
|
||||
enum { start_addr = 0xff10 };
|
||||
enum { end_addr = 0xff3f };
|
||||
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 );
|
||||
void write_register( blip_time_t, unsigned addr, int data );
|
||||
|
||||
// Read from address at specified time
|
||||
int read_register( gb_time_t, gb_addr_t );
|
||||
int read_register( blip_time_t, unsigned addr );
|
||||
|
||||
// Run all oscillators up to specified time, end current time frame, then
|
||||
// start a new frame at time 0. Return 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 );
|
||||
// start a new frame at time 0.
|
||||
void end_frame( blip_time_t );
|
||||
|
||||
void set_tempo( double );
|
||||
|
||||
public:
|
||||
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;
|
||||
blip_time_t next_frame_time;
|
||||
blip_time_t last_time;
|
||||
blip_time_t frame_period;
|
||||
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; // shared between squares
|
||||
Gb_Wave::Synth other_synth; // shared between wave and noise
|
||||
Gb_Square::Synth square_synth; // used by squares
|
||||
Gb_Wave::Synth other_synth; // used by wave and noise
|
||||
|
||||
void run_until( gb_time_t );
|
||||
void update_volume();
|
||||
void run_until( blip_time_t );
|
||||
void write_osc( int index, int reg, int data );
|
||||
};
|
||||
|
||||
inline void Gb_Apu::output( Blip_Buffer* b ) { output( b, NULL, NULL ); }
|
||||
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, NULL, NULL ); }
|
||||
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,144 +1,100 @@
|
||||
|
||||
// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/libs/
|
||||
// Gb_Snd_Emu 0.1.5. http://www.slack.net/~ant/
|
||||
|
||||
#include "Gb_Apu.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Copyright (C) 2003-2005 Shay Green. This module is free software; you
|
||||
/* 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 */
|
||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
|
||||
const int trigger = 0x80;
|
||||
#include "blargg_source.h"
|
||||
|
||||
// Gb_Osc
|
||||
|
||||
Gb_Osc::Gb_Osc()
|
||||
{
|
||||
output = NULL;
|
||||
outputs [0] = NULL;
|
||||
outputs [1] = NULL;
|
||||
outputs [2] = NULL;
|
||||
outputs [3] = NULL;
|
||||
}
|
||||
|
||||
void Gb_Osc::reset()
|
||||
{
|
||||
delay = 0;
|
||||
last_amp = 0;
|
||||
period = 2048;
|
||||
volume = 0;
|
||||
global_volume = 7; // added
|
||||
frequency = 0;
|
||||
length = 0;
|
||||
enabled = false;
|
||||
length_enabled = false;
|
||||
output_select = 3;
|
||||
output = outputs [output_select];
|
||||
}
|
||||
|
||||
void Gb_Osc::clock_length()
|
||||
{
|
||||
if ( length_enabled && length )
|
||||
--length;
|
||||
}
|
||||
|
||||
void Gb_Osc::write_register( int reg, int value )
|
||||
{
|
||||
if ( reg == 4 )
|
||||
length_enabled = value & 0x40;
|
||||
if ( (regs [4] & len_enabled_mask) && length )
|
||||
length--;
|
||||
}
|
||||
|
||||
// Gb_Env
|
||||
|
||||
void Gb_Env::reset()
|
||||
{
|
||||
env_period = 0;
|
||||
env_dir = 0;
|
||||
env_delay = 0;
|
||||
new_volume = 0;
|
||||
Gb_Osc::reset();
|
||||
}
|
||||
|
||||
Gb_Env::Gb_Env()
|
||||
{
|
||||
}
|
||||
|
||||
void Gb_Env::clock_envelope()
|
||||
{
|
||||
if ( env_delay && !--env_delay )
|
||||
{
|
||||
env_delay = env_period;
|
||||
if ( env_dir )
|
||||
{
|
||||
if ( volume < 15 )
|
||||
++volume;
|
||||
}
|
||||
else if ( volume > 0 )
|
||||
{
|
||||
--volume;
|
||||
}
|
||||
env_delay = regs [2] & 7;
|
||||
int v = volume - 1 + (regs [2] >> 2 & 2);
|
||||
if ( (unsigned) v < 15 )
|
||||
volume = v;
|
||||
}
|
||||
}
|
||||
|
||||
void Gb_Env::write_register( int reg, int value )
|
||||
bool Gb_Env::write_register( int reg, int data )
|
||||
{
|
||||
if ( reg == 2 ) {
|
||||
env_period = value & 7;
|
||||
env_dir = value & 8;
|
||||
volume = new_volume = value >> 4;
|
||||
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;
|
||||
}
|
||||
}
|
||||
else if ( reg == 4 && (value & trigger) ) {
|
||||
env_delay = env_period;
|
||||
volume = new_volume;
|
||||
enabled = true;
|
||||
}
|
||||
Gb_Osc::write_register( reg, value );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gb_Square
|
||||
|
||||
void Gb_Square::reset()
|
||||
{
|
||||
phase = 1;
|
||||
duty = 1;
|
||||
|
||||
sweep_period = 0;
|
||||
sweep_delay = 0;
|
||||
sweep_shift = 0;
|
||||
sweep_dir = 0;
|
||||
phase = 0;
|
||||
sweep_freq = 0;
|
||||
|
||||
new_length = 0;
|
||||
|
||||
sweep_delay = 0;
|
||||
Gb_Env::reset();
|
||||
}
|
||||
|
||||
Gb_Square::Gb_Square()
|
||||
{
|
||||
has_sweep = false;
|
||||
}
|
||||
|
||||
void Gb_Square::clock_sweep()
|
||||
{
|
||||
int sweep_period = (regs [0] & period_mask) >> 4;
|
||||
if ( sweep_period && sweep_delay && !--sweep_delay )
|
||||
{
|
||||
sweep_delay = sweep_period;
|
||||
frequency = sweep_freq;
|
||||
regs [3] = sweep_freq & 0xFF;
|
||||
regs [4] = (regs [4] & ~0x07) | (sweep_freq >> 8 & 0x07);
|
||||
|
||||
period = (2048 - frequency) * 4;
|
||||
|
||||
int offset = sweep_freq >> sweep_shift;
|
||||
if ( sweep_dir )
|
||||
int offset = sweep_freq >> (regs [0] & shift_mask);
|
||||
if ( regs [0] & 0x08 )
|
||||
offset = -offset;
|
||||
sweep_freq += offset;
|
||||
|
||||
@@ -148,304 +104,233 @@ void Gb_Square::clock_sweep()
|
||||
}
|
||||
else if ( sweep_freq >= 2048 )
|
||||
{
|
||||
sweep_delay = 0;
|
||||
sweep_freq = 2048; // stop sound output
|
||||
sweep_delay = 0; // don't modify channel frequency any further
|
||||
sweep_freq = 2048; // silence sound immediately
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Gb_Square::write_register( int reg, int value )
|
||||
void Gb_Square::run( blip_time_t time, blip_time_t end_time, int playing )
|
||||
{
|
||||
static unsigned char const duty_table [4] = { 1, 2, 4, 6 };
|
||||
if ( sweep_freq == 2048 )
|
||||
playing = false;
|
||||
|
||||
switch ( reg )
|
||||
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
|
||||
{
|
||||
case 0:
|
||||
sweep_period = (value >> 4) & 7; // changed
|
||||
sweep_shift = value & 7;
|
||||
sweep_dir = value & 0x08;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
new_length = length = 64 - (value & 0x3f);
|
||||
duty = duty_table [value >> 6];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
frequency = (frequency & ~0xFF) + value;
|
||||
length = new_length;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
frequency = (value & 7) * 0x100 + (frequency & 0xFF);
|
||||
length = new_length;
|
||||
if ( value & trigger )
|
||||
{
|
||||
sweep_freq = frequency;
|
||||
if ( has_sweep && sweep_period && sweep_shift )
|
||||
{
|
||||
sweep_delay = 1;
|
||||
clock_sweep();
|
||||
}
|
||||
}
|
||||
break;
|
||||
// really high frequency results in DC at half volume
|
||||
amp = volume >> 1;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
period = (2048 - frequency) * 4;
|
||||
|
||||
Gb_Env::write_register( reg, value );
|
||||
}
|
||||
|
||||
void Gb_Square::run( gb_time_t time, gb_time_t end_time )
|
||||
{
|
||||
// to do: when frequency goes above 20000 Hz output should actually be 1/2 volume
|
||||
// rather than 0
|
||||
|
||||
if ( !enabled || (!length && length_enabled) || !volume || sweep_freq == 2048 ||
|
||||
!frequency || period < 27 )
|
||||
{
|
||||
if ( last_amp )
|
||||
int delta = amp - last_amp;
|
||||
if ( delta )
|
||||
{
|
||||
synth->offset( time, -last_amp, output );
|
||||
last_amp = 0;
|
||||
}
|
||||
delay = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int amp = (phase < duty) ? volume : -volume;
|
||||
amp *= global_volume;
|
||||
if ( amp != last_amp )
|
||||
{
|
||||
synth->offset( time, amp - last_amp, output );
|
||||
last_amp = amp;
|
||||
synth->offset( time, delta, output );
|
||||
}
|
||||
|
||||
time += delay;
|
||||
if ( time < end_time )
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
Blip_Buffer* const output = this->output;
|
||||
const int duty = this->duty;
|
||||
int phase = this->phase;
|
||||
amp *= 2;
|
||||
do
|
||||
phase = (phase + 1) & 7;
|
||||
if ( phase == 0 || phase == duty )
|
||||
{
|
||||
phase = (phase + 1) & 7;
|
||||
if ( phase == 0 || phase == duty )
|
||||
{
|
||||
amp = -amp;
|
||||
synth->offset_inline( time, amp, output );
|
||||
}
|
||||
time += period;
|
||||
delta = -delta;
|
||||
synth->offset_inline( time, delta, output );
|
||||
}
|
||||
while ( time < end_time );
|
||||
|
||||
this->phase = phase;
|
||||
last_amp = amp >> 1;
|
||||
time += period;
|
||||
}
|
||||
delay = time - end_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Gb_Wave
|
||||
|
||||
void Gb_Wave::reset()
|
||||
{
|
||||
volume_shift = 0;
|
||||
wave_pos = 0;
|
||||
new_length = 0;
|
||||
memset( wave, 0, sizeof wave );
|
||||
Gb_Osc::reset();
|
||||
}
|
||||
|
||||
Gb_Wave::Gb_Wave() {
|
||||
}
|
||||
|
||||
void Gb_Wave::write_register( int reg, int value )
|
||||
{
|
||||
switch ( reg )
|
||||
{
|
||||
case 0:
|
||||
new_enabled = value & 0x80;
|
||||
enabled &= new_enabled;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
new_length = length = 256 - value;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
volume = ((value >> 5) & 3);
|
||||
volume_shift = (volume - 1) & 7; // silence = 7
|
||||
break;
|
||||
|
||||
case 3:
|
||||
frequency = (frequency & ~0xFF) + value;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
frequency = (value & 7) * 0x100 + (frequency & 0xFF);
|
||||
if ( new_enabled && (value & trigger) )
|
||||
{
|
||||
wave_pos = 0;
|
||||
length = new_length;
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
period = (2048 - frequency) * 2;
|
||||
|
||||
Gb_Osc::write_register( reg, value );
|
||||
}
|
||||
|
||||
void Gb_Wave::run( gb_time_t time, gb_time_t end_time )
|
||||
{
|
||||
// to do: when frequency goes above 20000 Hz output should actually be 1/2 volume
|
||||
// rather than 0
|
||||
if ( !enabled || (!length && length_enabled) || !volume || !frequency || period < 7 )
|
||||
{
|
||||
if ( last_amp ) {
|
||||
synth->offset( time, -last_amp, output );
|
||||
last_amp = 0;
|
||||
}
|
||||
delay = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int const vol_factor = global_volume * 2;
|
||||
while ( time < end_time );
|
||||
|
||||
// wave data or shift may have changed
|
||||
int diff = (wave [wave_pos] >> volume_shift) * vol_factor - last_amp;
|
||||
if ( diff )
|
||||
{
|
||||
last_amp += diff;
|
||||
synth->offset( time, diff, output );
|
||||
}
|
||||
|
||||
time += delay;
|
||||
if ( time < end_time )
|
||||
{
|
||||
int const volume_shift = this->volume_shift;
|
||||
int wave_pos = this->wave_pos;
|
||||
|
||||
do
|
||||
{
|
||||
wave_pos = unsigned (wave_pos + 1) % wave_size;
|
||||
int amp = (wave [wave_pos] >> volume_shift) * vol_factor;
|
||||
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;
|
||||
}
|
||||
delay = time - end_time;
|
||||
this->phase = phase;
|
||||
last_amp = delta >> 1;
|
||||
}
|
||||
delay = time - end_time;
|
||||
}
|
||||
|
||||
|
||||
// Gb_Noise
|
||||
|
||||
void Gb_Noise::reset()
|
||||
void Gb_Noise::run( blip_time_t time, blip_time_t end_time, int playing )
|
||||
{
|
||||
bits = 1;
|
||||
tap = 14;
|
||||
Gb_Env::reset();
|
||||
}
|
||||
|
||||
Gb_Noise::Gb_Noise() {
|
||||
}
|
||||
|
||||
void Gb_Noise::write_register( int reg, int value )
|
||||
{
|
||||
if ( reg == 1 ) {
|
||||
new_length = length = 64 - (value & 0x3f);
|
||||
}
|
||||
else if ( reg == 2 ) {
|
||||
// based on VBA code, noise is the only exception to the envelope code
|
||||
// while the volume level here is applied when the channel is enabled,
|
||||
// current volume is only affected by writes to this register if volume
|
||||
// is zero and direction is up... (definitely needs verification)
|
||||
int temp = volume;
|
||||
Gb_Env::write_register( reg, value );
|
||||
if ( ( value & 0xF8 ) != 0 ) volume = temp;
|
||||
return;
|
||||
}
|
||||
else if ( reg == 3 ) {
|
||||
tap = 14 - (value & 8);
|
||||
// noise formula and frequency tested against Metroid 2 and Zelda LA
|
||||
int divisor = (value & 7) * 16;
|
||||
if ( !divisor )
|
||||
divisor = 8;
|
||||
period = divisor << (value >> 4);
|
||||
}
|
||||
else if ( reg == 4 && value & trigger ) {
|
||||
bits = ~0u;
|
||||
length = new_length;
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
Gb_Env::write_register( reg, value );
|
||||
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;
|
||||
}
|
||||
|
||||
#include BLARGG_ENABLE_OPTIMIZER
|
||||
// Gb_Wave
|
||||
|
||||
void Gb_Noise::run( gb_time_t time, gb_time_t end_time )
|
||||
inline void Gb_Wave::write_register( int reg, int data )
|
||||
{
|
||||
if ( !enabled || (!length && length_enabled) || !volume ) {
|
||||
if ( last_amp ) {
|
||||
synth->offset( time, -last_amp, output );
|
||||
last_amp = 0;
|
||||
}
|
||||
delay = 0;
|
||||
}
|
||||
else
|
||||
switch ( reg )
|
||||
{
|
||||
int amp = bits & 1 ? -volume : volume;
|
||||
amp *= global_volume;
|
||||
if ( amp != last_amp ) {
|
||||
synth->offset( time, amp - last_amp, output );
|
||||
last_amp = amp;
|
||||
case 0:
|
||||
if ( !(data & 0x80) )
|
||||
enabled = false;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
length = 256 - regs [1];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
volume = data >> 5 & 3;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ( data & trigger & regs [0] )
|
||||
{
|
||||
wave_pos = 0;
|
||||
enabled = true;
|
||||
if ( length == 0 )
|
||||
length = 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Gb_Wave::run( blip_time_t time, blip_time_t end_time, int playing )
|
||||
{
|
||||
int volume_shift = (volume - 1) & 7; // volume = 0 causes shift = 7
|
||||
int frequency;
|
||||
{
|
||||
int amp = (wave [wave_pos] >> volume_shift & playing) * 2;
|
||||
|
||||
frequency = this->frequency();
|
||||
if ( unsigned (frequency - 1) > 2044 ) // frequency < 1 || frequency > 2045
|
||||
{
|
||||
amp = 30 >> volume_shift & playing;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
time += delay;
|
||||
if ( time < end_time )
|
||||
int delta = amp - last_amp;
|
||||
if ( delta )
|
||||
{
|
||||
Blip_Buffer* const output = this->output;
|
||||
// keep parallel resampled time to eliminate multiplication in the loop
|
||||
const blip_resampled_time_t resampled_period =
|
||||
output->resampled_duration( period );
|
||||
blip_resampled_time_t resampled_time = output->resampled_time( time );
|
||||
const unsigned mask = ~(1u << tap);
|
||||
unsigned bits = this->bits;
|
||||
amp *= 2;
|
||||
|
||||
do {
|
||||
unsigned feedback = bits;
|
||||
bits >>= 1;
|
||||
feedback = 1 & (feedback ^ bits);
|
||||
time += period;
|
||||
bits = (feedback << tap) | (bits & mask);
|
||||
// feedback just happens to be true only when the level needs to change
|
||||
// (the previous and current bits are different)
|
||||
if ( feedback ) {
|
||||
amp = -amp;
|
||||
synth->offset_resampled( resampled_time, amp, output );
|
||||
}
|
||||
resampled_time += resampled_period;
|
||||
}
|
||||
while ( time < end_time );
|
||||
|
||||
this->bits = bits;
|
||||
last_amp = amp >> 1;
|
||||
last_amp = amp;
|
||||
synth->offset( time, delta, output );
|
||||
}
|
||||
delay = time - end_time;
|
||||
}
|
||||
|
||||
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 [wave_pos] >> volume_shift) * 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,100 +1,83 @@
|
||||
|
||||
// Private oscillators used by Gb_Apu
|
||||
|
||||
// Gb_Snd_Emu 0.1.4. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
|
||||
|
||||
// Gb_Snd_Emu 0.1.5
|
||||
#ifndef GB_OSCS_H
|
||||
#define GB_OSCS_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
#include "Blip_Buffer.h"
|
||||
|
||||
enum { gb_apu_max_vol = 7 };
|
||||
|
||||
struct Gb_Osc {
|
||||
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 period;
|
||||
int volume;
|
||||
int global_volume;
|
||||
int frequency;
|
||||
int length;
|
||||
int new_length;
|
||||
bool enabled;
|
||||
bool length_enabled;
|
||||
int enabled;
|
||||
|
||||
Gb_Osc();
|
||||
|
||||
void clock_length();
|
||||
void reset();
|
||||
virtual void run( gb_time_t begin, gb_time_t end ) = 0;
|
||||
virtual void write_register( int reg, int value );
|
||||
void clock_length();
|
||||
int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; }
|
||||
};
|
||||
|
||||
struct Gb_Env : Gb_Osc {
|
||||
int env_period;
|
||||
int env_dir;
|
||||
struct Gb_Env : Gb_Osc
|
||||
{
|
||||
int env_delay;
|
||||
int new_volume;
|
||||
|
||||
Gb_Env();
|
||||
void reset();
|
||||
void clock_envelope();
|
||||
void write_register( int, int );
|
||||
bool write_register( int, int );
|
||||
};
|
||||
|
||||
struct Gb_Square : Gb_Env {
|
||||
int phase;
|
||||
int duty;
|
||||
struct Gb_Square : Gb_Env
|
||||
{
|
||||
enum { period_mask = 0x70 };
|
||||
enum { shift_mask = 0x07 };
|
||||
|
||||
int sweep_period;
|
||||
typedef Blip_Synth<blip_good_quality,1> Synth;
|
||||
Synth const* synth;
|
||||
int sweep_delay;
|
||||
int sweep_shift;
|
||||
int sweep_dir;
|
||||
int sweep_freq;
|
||||
bool has_sweep;
|
||||
int phase;
|
||||
|
||||
typedef Blip_Synth<blip_good_quality,15 * gb_apu_max_vol * 2> Synth;
|
||||
const Synth* synth;
|
||||
|
||||
Gb_Square();
|
||||
void reset();
|
||||
void run( gb_time_t, gb_time_t );
|
||||
void write_register( int, int );
|
||||
void clock_sweep();
|
||||
void run( blip_time_t, blip_time_t, int playing );
|
||||
};
|
||||
|
||||
struct Gb_Wave : Gb_Osc {
|
||||
int volume_shift;
|
||||
unsigned wave_pos;
|
||||
struct Gb_Noise : Gb_Env
|
||||
{
|
||||
typedef Blip_Synth<blip_med_quality,1> Synth;
|
||||
Synth const* synth;
|
||||
unsigned bits;
|
||||
|
||||
void run( blip_time_t, blip_time_t, int playing );
|
||||
};
|
||||
|
||||
struct Gb_Wave : Gb_Osc
|
||||
{
|
||||
typedef Blip_Synth<blip_med_quality,1> Synth;
|
||||
Synth const* synth;
|
||||
int wave_pos;
|
||||
enum { wave_size = 32 };
|
||||
bool new_enabled;
|
||||
BOOST::uint8_t wave [wave_size];
|
||||
|
||||
typedef Blip_Synth<blip_med_quality,15 * gb_apu_max_vol * 2> Synth;
|
||||
const Synth* synth;
|
||||
|
||||
Gb_Wave();
|
||||
void reset();
|
||||
void run( gb_time_t, gb_time_t );
|
||||
void write_register( int, int );
|
||||
void run( blip_time_t, blip_time_t, int playing );
|
||||
};
|
||||
|
||||
struct Gb_Noise : Gb_Env {
|
||||
unsigned bits;
|
||||
int tap;
|
||||
|
||||
typedef Blip_Synth<blip_med_quality,15 * gb_apu_max_vol * 2> Synth;
|
||||
const Synth* synth;
|
||||
|
||||
Gb_Noise();
|
||||
void reset();
|
||||
void run( gb_time_t, gb_time_t );
|
||||
void write_register( int, int );
|
||||
};
|
||||
inline void Gb_Env::reset()
|
||||
{
|
||||
env_delay = 0;
|
||||
Gb_Osc::reset();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
|
||||
// Blip_Buffer 0.3.4. http://www.slack.net/~ant/libs/
|
||||
// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
|
||||
|
||||
#include "Multi_Buffer.h"
|
||||
|
||||
/* Copyright (C) 2003-2005 Shay Green. This module is free software; you
|
||||
/* 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 */
|
||||
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
#include "blargg_source.h"
|
||||
|
||||
#ifdef BLARGG_ENABLE_OPTIMIZER
|
||||
#include BLARGG_ENABLE_OPTIMIZER
|
||||
#endif
|
||||
|
||||
Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf )
|
||||
{
|
||||
@@ -23,48 +26,33 @@ Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf )
|
||||
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() );
|
||||
}
|
||||
blargg_err_t Multi_Buffer::set_channel_count( int ) { return 0; }
|
||||
|
||||
// Silent_Buffer
|
||||
|
||||
Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse
|
||||
{
|
||||
chan.left = NULL;
|
||||
chan.center = NULL;
|
||||
chan.right = NULL;
|
||||
// TODO: better to use empty Blip_Buffer so caller never has to check for NULL?
|
||||
chan.left = 0;
|
||||
chan.center = 0;
|
||||
chan.right = 0;
|
||||
}
|
||||
|
||||
// Mono_Buffer
|
||||
|
||||
Mono_Buffer::channel_t Mono_Buffer::channel( int index )
|
||||
Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 )
|
||||
{
|
||||
channel_t ch;
|
||||
ch.center = &buf;
|
||||
ch.left = &buf;
|
||||
ch.right = &buf;
|
||||
return ch;
|
||||
chan.center = &buf;
|
||||
chan.left = &buf;
|
||||
chan.right = &buf;
|
||||
}
|
||||
|
||||
void Mono_Buffer::end_frame( blip_time_t t, bool )
|
||||
Mono_Buffer::~Mono_Buffer() { }
|
||||
|
||||
blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec )
|
||||
{
|
||||
buf.end_frame( t );
|
||||
RETURN_ERR( buf.set_sample_rate( rate, msec ) );
|
||||
return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() );
|
||||
}
|
||||
|
||||
// Stereo_Buffer
|
||||
@@ -76,14 +64,12 @@ Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 )
|
||||
chan.right = &bufs [2];
|
||||
}
|
||||
|
||||
Stereo_Buffer::~Stereo_Buffer()
|
||||
{
|
||||
}
|
||||
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_ERR( bufs [i].set_sample_rate( rate, msec ) );
|
||||
return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() );
|
||||
}
|
||||
|
||||
@@ -101,18 +87,20 @@ void Stereo_Buffer::bass_freq( int bass )
|
||||
|
||||
void Stereo_Buffer::clear()
|
||||
{
|
||||
stereo_added = false;
|
||||
was_stereo = false;
|
||||
stereo_added = 0;
|
||||
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 )
|
||||
void Stereo_Buffer::end_frame( blip_time_t clock_count )
|
||||
{
|
||||
stereo_added = 0;
|
||||
for ( unsigned i = 0; i < buf_count; i++ )
|
||||
{
|
||||
stereo_added |= bufs [i].clear_modified() << i;
|
||||
bufs [i].end_frame( clock_count );
|
||||
|
||||
stereo_added |= stereo;
|
||||
}
|
||||
}
|
||||
|
||||
long Stereo_Buffer::read_samples( blip_sample_t* out, long count )
|
||||
@@ -125,91 +113,120 @@ long Stereo_Buffer::read_samples( blip_sample_t* out, long count )
|
||||
count = avail;
|
||||
if ( count )
|
||||
{
|
||||
if ( stereo_added || was_stereo )
|
||||
int bufs_used = stereo_added | was_stereo;
|
||||
//debug_printf( "%X\n", bufs_used );
|
||||
if ( bufs_used <= 1 )
|
||||
{
|
||||
mix_mono( out, count );
|
||||
bufs [0].remove_samples( count );
|
||||
bufs [1].remove_silence( count );
|
||||
bufs [2].remove_silence( count );
|
||||
}
|
||||
else if ( bufs_used & 1 )
|
||||
{
|
||||
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 );
|
||||
mix_stereo_no_center( out, count );
|
||||
bufs [0].remove_silence( count );
|
||||
bufs [1].remove_samples( count );
|
||||
bufs [2].remove_samples( count );
|
||||
}
|
||||
|
||||
// to do: this might miss opportunities for optimization
|
||||
if ( !bufs [0].samples_avail() ) {
|
||||
was_stereo = stereo_added;
|
||||
stereo_added = false;
|
||||
if ( !bufs [0].samples_avail() )
|
||||
{
|
||||
was_stereo = stereo_added;
|
||||
stereo_added = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count * 2;
|
||||
}
|
||||
|
||||
#include BLARGG_ENABLE_OPTIMIZER
|
||||
|
||||
void Stereo_Buffer::mix_stereo( blip_sample_t* out, long count )
|
||||
void Stereo_Buffer::mix_stereo( blip_sample_t* out_, blargg_long count )
|
||||
{
|
||||
Blip_Reader left;
|
||||
Blip_Reader right;
|
||||
Blip_Reader center;
|
||||
blip_sample_t* BLIP_RESTRICT out = out_;
|
||||
int const bass = BLIP_READER_BASS( bufs [1] );
|
||||
BLIP_READER_BEGIN( left, bufs [1] );
|
||||
BLIP_READER_BEGIN( right, bufs [2] );
|
||||
BLIP_READER_BEGIN( center, bufs [0] );
|
||||
|
||||
left.begin( bufs [1] );
|
||||
right.begin( bufs [2] );
|
||||
int bass = center.begin( bufs [0] );
|
||||
|
||||
while ( count-- )
|
||||
for ( ; count; --count )
|
||||
{
|
||||
int c = center.read();
|
||||
long l = c + left.read();
|
||||
long r = c + right.read();
|
||||
center.next( bass );
|
||||
int c = BLIP_READER_READ( center );
|
||||
blargg_long l = c + BLIP_READER_READ( left );
|
||||
blargg_long r = c + BLIP_READER_READ( right );
|
||||
if ( (BOOST::int16_t) l != l )
|
||||
l = 0x7FFF - (l >> 24);
|
||||
|
||||
BLIP_READER_NEXT( center, bass );
|
||||
if ( (BOOST::int16_t) r != r )
|
||||
r = 0x7FFF - (r >> 24);
|
||||
|
||||
BLIP_READER_NEXT( left, bass );
|
||||
BLIP_READER_NEXT( right, 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] );
|
||||
BLIP_READER_END( center, bufs [0] );
|
||||
BLIP_READER_END( right, bufs [2] );
|
||||
BLIP_READER_END( left, bufs [1] );
|
||||
}
|
||||
|
||||
void Stereo_Buffer::mix_mono( blip_sample_t* out, long count )
|
||||
void Stereo_Buffer::mix_stereo_no_center( blip_sample_t* out_, blargg_long count )
|
||||
{
|
||||
Blip_Reader in;
|
||||
int bass = in.begin( bufs [0] );
|
||||
blip_sample_t* BLIP_RESTRICT out = out_;
|
||||
int const bass = BLIP_READER_BASS( bufs [1] );
|
||||
BLIP_READER_BEGIN( left, bufs [1] );
|
||||
BLIP_READER_BEGIN( right, bufs [2] );
|
||||
|
||||
while ( count-- )
|
||||
for ( ; count; --count )
|
||||
{
|
||||
long s = in.read();
|
||||
in.next( bass );
|
||||
blargg_long l = BLIP_READER_READ( left );
|
||||
if ( (BOOST::int16_t) l != l )
|
||||
l = 0x7FFF - (l >> 24);
|
||||
|
||||
blargg_long r = BLIP_READER_READ( right );
|
||||
if ( (BOOST::int16_t) r != r )
|
||||
r = 0x7FFF - (r >> 24);
|
||||
|
||||
BLIP_READER_NEXT( left, bass );
|
||||
BLIP_READER_NEXT( right, bass );
|
||||
|
||||
out [0] = l;
|
||||
out [1] = r;
|
||||
out += 2;
|
||||
}
|
||||
|
||||
BLIP_READER_END( right, bufs [2] );
|
||||
BLIP_READER_END( left, bufs [1] );
|
||||
}
|
||||
|
||||
void Stereo_Buffer::mix_mono( blip_sample_t* out_, blargg_long count )
|
||||
{
|
||||
blip_sample_t* BLIP_RESTRICT out = out_;
|
||||
int const bass = BLIP_READER_BASS( bufs [0] );
|
||||
BLIP_READER_BEGIN( center, bufs [0] );
|
||||
|
||||
for ( ; count; --count )
|
||||
{
|
||||
blargg_long s = BLIP_READER_READ( center );
|
||||
if ( (BOOST::int16_t) s != s )
|
||||
s = 0x7FFF - (s >> 24);
|
||||
|
||||
BLIP_READER_NEXT( center, 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] );
|
||||
BLIP_READER_END( center, bufs [0] );
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
|
||||
// Multi-channel sound buffer interface, and basic mono and stereo buffers
|
||||
|
||||
// Blip_Buffer 0.3.4. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
|
||||
|
||||
// Blip_Buffer 0.4.1
|
||||
#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
|
||||
@@ -24,7 +23,9 @@ public:
|
||||
Blip_Buffer* left;
|
||||
Blip_Buffer* right;
|
||||
};
|
||||
virtual channel_t channel( int index ) = 0;
|
||||
enum { type_index_mask = 0xFF };
|
||||
enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type };
|
||||
virtual channel_t channel( int index, int type ) = 0;
|
||||
|
||||
// See Blip_Buffer.h
|
||||
virtual blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ) = 0;
|
||||
@@ -36,10 +37,8 @@ public:
|
||||
// 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;
|
||||
// See Blip_Buffer.h
|
||||
virtual void end_frame( blip_time_t ) = 0;
|
||||
|
||||
// Number of samples per output frame (1 = mono, 2 = stereo)
|
||||
int samples_per_frame() const;
|
||||
@@ -52,6 +51,8 @@ public:
|
||||
virtual long read_samples( blip_sample_t*, long ) = 0;
|
||||
virtual long samples_avail() const = 0;
|
||||
|
||||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
protected:
|
||||
void channels_changed() { channels_changed_count_++; }
|
||||
private:
|
||||
@@ -68,55 +69,56 @@ private:
|
||||
// Uses a single buffer and outputs mono samples.
|
||||
class Mono_Buffer : public Multi_Buffer {
|
||||
Blip_Buffer buf;
|
||||
channel_t chan;
|
||||
public:
|
||||
Mono_Buffer();
|
||||
~Mono_Buffer();
|
||||
|
||||
// Buffer used for all channels
|
||||
Blip_Buffer* center() { return &buf; }
|
||||
|
||||
// See Multi_Buffer
|
||||
public:
|
||||
Mono_Buffer();
|
||||
~Mono_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 );
|
||||
void clock_rate( long rate ) { buf.clock_rate( rate ); }
|
||||
void bass_freq( int freq ) { buf.bass_freq( freq ); }
|
||||
void clear() { buf.clear(); }
|
||||
long samples_avail() const { return buf.samples_avail(); }
|
||||
long read_samples( blip_sample_t* p, long s ) { return buf.read_samples( p, s ); }
|
||||
channel_t channel( int, int ) { return chan; }
|
||||
void end_frame( blip_time_t t ) { buf.end_frame( t ); }
|
||||
};
|
||||
|
||||
// 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
|
||||
public:
|
||||
Stereo_Buffer();
|
||||
~Stereo_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 );
|
||||
channel_t channel( int, int ) { return chan; }
|
||||
void end_frame( blip_time_t );
|
||||
|
||||
long samples_avail() const;
|
||||
long samples_avail() const { return bufs [0].samples_avail() * 2; }
|
||||
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;
|
||||
int stereo_added;
|
||||
int was_stereo;
|
||||
|
||||
void mix_stereo( blip_sample_t*, long );
|
||||
void mix_mono( blip_sample_t*, long );
|
||||
void mix_stereo_no_center( blip_sample_t*, blargg_long );
|
||||
void mix_stereo( blip_sample_t*, blargg_long );
|
||||
void mix_mono( blip_sample_t*, blargg_long );
|
||||
};
|
||||
|
||||
// Silent_Buffer generates no samples, useful where no sound is wanted
|
||||
@@ -124,51 +126,33 @@ 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 ) { }
|
||||
channel_t channel( int, int ) { return chan; }
|
||||
void end_frame( blip_time_t ) { }
|
||||
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 0;
|
||||
}
|
||||
|
||||
inline blargg_err_t Silent_Buffer::set_sample_rate( long rate, int msec )
|
||||
{
|
||||
return Multi_Buffer::set_sample_rate( rate, msec );
|
||||
}
|
||||
|
||||
inline blargg_err_t Multi_Buffer::set_sample_rate( long rate, int msec )
|
||||
{
|
||||
sample_rate_ = rate;
|
||||
length_ = msec;
|
||||
return blargg_success;
|
||||
}
|
||||
|
||||
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 index ) { 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,178 +1,196 @@
|
||||
|
||||
// Sets up common environment for Shay Green's libraries.
|
||||
//
|
||||
// Don't modify this file directly; #define HAVE_CONFIG_H and put your
|
||||
// configuration into "config.h".
|
||||
|
||||
// Copyright (C) 2004-2005 Shay Green.
|
||||
// To change configuration options, modify blargg_config.h, not this file.
|
||||
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#define BLARGG_COMMON_H
|
||||
|
||||
// Allow prefix configuration file *which can re-include blargg_common.h*
|
||||
// (probably indirectly).
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#undef BLARGG_COMMON_H
|
||||
#include "config.h"
|
||||
#define BLARGG_COMMON_H
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#undef BLARGG_COMMON_H
|
||||
// allow blargg_config.h to #include blargg_common.h
|
||||
#include "blargg_config.h"
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#define BLARGG_COMMON_H
|
||||
|
||||
// BLARGG_RESTRICT: equivalent to restrict, where supported
|
||||
#if __GNUC__ >= 3 || _MSC_VER >= 1100
|
||||
#define BLARGG_RESTRICT __restrict
|
||||
#else
|
||||
#define BLARGG_RESTRICT
|
||||
#endif
|
||||
|
||||
// Source files use #include BLARGG_ENABLE_OPTIMIZER before performance-critical code
|
||||
#ifndef BLARGG_ENABLE_OPTIMIZER
|
||||
#define BLARGG_ENABLE_OPTIMIZER "blargg_common.h"
|
||||
#endif
|
||||
|
||||
// Source files have #include BLARGG_SOURCE_BEGIN at the beginning
|
||||
#ifndef BLARGG_SOURCE_BEGIN
|
||||
#define BLARGG_SOURCE_BEGIN "blargg_source.h"
|
||||
#endif
|
||||
|
||||
// Determine compiler's language support
|
||||
|
||||
#if defined (__MWERKS__)
|
||||
// Metrowerks CodeWarrior
|
||||
#define BLARGG_COMPILER_HAS_NAMESPACE 1
|
||||
#if !__option(bool)
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
|
||||
#elif defined (_MSC_VER)
|
||||
// Microsoft Visual C++
|
||||
#if _MSC_VER < 1100
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
|
||||
#elif defined (__GNUC__)
|
||||
// GNU C++
|
||||
#define BLARGG_COMPILER_HAS_NAMESPACE 1
|
||||
#define BLARGG_COMPILER_HAS_BOOL 1
|
||||
|
||||
#elif defined (__MINGW32__)
|
||||
// Mingw?
|
||||
#define BLARGG_COMPILER_HAS_BOOL 1
|
||||
|
||||
#elif __cplusplus < 199711
|
||||
// Pre-ISO C++ compiler
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#define STATIC_CAST( type ) (type)
|
||||
|
||||
#endif
|
||||
|
||||
// STATIC_CAST(T) (expr) -> static_cast< T > (expr)
|
||||
// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
|
||||
#ifndef STATIC_CAST
|
||||
#define STATIC_CAST( type ) static_cast< type >
|
||||
#define STATIC_CAST(T,expr) ((T) (expr))
|
||||
#endif
|
||||
|
||||
// Set up boost
|
||||
#include "boost/config.hpp"
|
||||
#ifndef BOOST_MINIMAL
|
||||
#define BOOST boost
|
||||
#ifndef BLARGG_COMPILER_HAS_NAMESPACE
|
||||
#define BLARGG_COMPILER_HAS_NAMESPACE 1
|
||||
// blargg_err_t (0 on success, otherwise error string)
|
||||
#ifndef blargg_err_t
|
||||
typedef const char* blargg_err_t;
|
||||
#endif
|
||||
|
||||
// blargg_vector - very lightweight vector of POD types (no constructor/destructor)
|
||||
template<class T>
|
||||
class blargg_vector {
|
||||
T* begin_;
|
||||
size_t size_;
|
||||
public:
|
||||
blargg_vector() : begin_( 0 ), size_( 0 ) { }
|
||||
~blargg_vector() { free( begin_ ); }
|
||||
size_t size() const { return size_; }
|
||||
T* begin() const { return begin_; }
|
||||
T* end() const { return begin_ + size_; }
|
||||
blargg_err_t resize( size_t n )
|
||||
{
|
||||
void* p = 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; free( p ); }
|
||||
T& operator [] ( size_t n ) const
|
||||
{
|
||||
assert( n <= size_ ); // <= to allow past-the-end value
|
||||
return begin_ [n];
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef BLARGG_DISABLE_NOTHROW
|
||||
// throw spec mandatory in ISO C++ if operator new can return NULL
|
||||
#if __cplusplus >= 199711 || __GNUC__ >= 3
|
||||
#define BLARGG_THROWS( spec ) throw spec
|
||||
#else
|
||||
#define BLARGG_THROWS( spec )
|
||||
#endif
|
||||
#ifndef BLARGG_COMPILER_HAS_BOOL
|
||||
#define BLARGG_COMPILER_HAS_BOOL 1
|
||||
#define BLARGG_DISABLE_NOTHROW \
|
||||
void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\
|
||||
void operator delete ( void* p ) { free( p ); }
|
||||
#define BLARGG_NEW new
|
||||
#else
|
||||
#include <new>
|
||||
#define BLARGG_NEW new (std::nothrow)
|
||||
#endif
|
||||
|
||||
// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant)
|
||||
#define BLARGG_4CHAR( a, b, c, d ) \
|
||||
((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
|
||||
|
||||
// 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 / (int) !!(expr) - 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] [__LINE__] )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Bool support
|
||||
// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
|
||||
// compiler is assumed to support bool. If undefined, availability is determined.
|
||||
#ifndef BLARGG_COMPILER_HAS_BOOL
|
||||
#define BLARGG_COMPILER_HAS_BOOL 1
|
||||
#elif !BLARGG_COMPILER_HAS_BOOL
|
||||
#if defined (__MWERKS__)
|
||||
#if !__option(bool)
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#elif defined (_MSC_VER)
|
||||
#if _MSC_VER < 1100
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#elif defined (__GNUC__)
|
||||
// supports bool
|
||||
#elif __cplusplus < 199711
|
||||
#define BLARGG_COMPILER_HAS_BOOL 0
|
||||
#endif
|
||||
#endif
|
||||
#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
|
||||
// If you get errors here, modify your blargg_config.h file
|
||||
typedef int bool;
|
||||
const bool true = 1;
|
||||
const bool false = 0;
|
||||
#endif
|
||||
|
||||
// Set up namespace support
|
||||
// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough
|
||||
|
||||
#ifndef BLARGG_COMPILER_HAS_NAMESPACE
|
||||
#define BLARGG_COMPILER_HAS_NAMESPACE 0
|
||||
#endif
|
||||
|
||||
#ifndef BLARGG_USE_NAMESPACE
|
||||
#define BLARGG_USE_NAMESPACE BLARGG_COMPILER_HAS_NAMESPACE
|
||||
#endif
|
||||
|
||||
#ifndef BOOST
|
||||
#if BLARGG_USE_NAMESPACE
|
||||
#define BOOST boost
|
||||
#else
|
||||
#define BOOST
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef BLARGG_BEGIN_NAMESPACE
|
||||
#undef BLARGG_END_NAMESPACE
|
||||
#if BLARGG_USE_NAMESPACE
|
||||
#define BLARGG_BEGIN_NAMESPACE( name ) namespace name {
|
||||
#define BLARGG_END_NAMESPACE }
|
||||
#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
|
||||
typedef long blargg_long;
|
||||
#else
|
||||
#define BLARGG_BEGIN_NAMESPACE( name )
|
||||
#define BLARGG_END_NAMESPACE
|
||||
typedef int blargg_long;
|
||||
#endif
|
||||
|
||||
#if BLARGG_USE_NAMESPACE
|
||||
#define STD std
|
||||
#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long blargg_ulong;
|
||||
#else
|
||||
#define STD
|
||||
typedef unsigned blargg_ulong;
|
||||
#endif
|
||||
|
||||
// BOOST::uint8_t, BOOST::int16_t, etc.
|
||||
#include "boost/cstdint.hpp"
|
||||
// BOOST::int8_t etc.
|
||||
|
||||
// BOOST_STATIC_ASSERT( expr )
|
||||
#include "boost/static_assert.hpp"
|
||||
// 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
|
||||
|
||||
// Common standard headers
|
||||
#if BLARGG_COMPILER_HAS_NAMESPACE
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
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_err_t (NULL on success, otherwise error string)
|
||||
typedef const char* blargg_err_t;
|
||||
const blargg_err_t blargg_success = 0;
|
||||
|
||||
// BLARGG_NEW is used in place of 'new' to create objects. By default,
|
||||
// plain new is used.
|
||||
#ifndef BLARGG_NEW
|
||||
#define BLARGG_NEW new
|
||||
#if __GNUC__ >= 3
|
||||
#define BLARGG_DEPRECATED __attribute__ ((deprecated))
|
||||
#else
|
||||
#define BLARGG_DEPRECATED
|
||||
#endif
|
||||
|
||||
// BLARGG_BIG_ENDIAN and BLARGG_LITTLE_ENDIAN
|
||||
// Only needed if modules are used which must know byte order.
|
||||
#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
|
||||
#if defined (__powerc) || defined (macintosh)
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
|
||||
#elif defined (_MSC_VER) && defined (_M_IX86)
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// BLARGG_NONPORTABLE (allow use of nonportable optimizations/features)
|
||||
#ifndef BLARGG_NONPORTABLE
|
||||
#define BLARGG_NONPORTABLE 0
|
||||
#endif
|
||||
#ifdef BLARGG_MOST_PORTABLE
|
||||
#error "BLARGG_MOST_PORTABLE has been removed; use BLARGG_NONPORTABLE."
|
||||
#endif
|
||||
|
||||
// BLARGG_CPU_*
|
||||
#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
|
||||
// Use in place of "= 0;" for a pure virtual, since these cause calls to std C++ lib.
|
||||
// During development, BLARGG_PURE( x ) expands to = 0;
|
||||
// virtual int func() BLARGG_PURE( { return 0; } )
|
||||
#ifndef BLARGG_PURE
|
||||
#define BLARGG_PURE( def ) def
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
43
plugins/papu/gb_apu/blargg_config.h
Normal file
43
plugins/papu/gb_apu/blargg_config.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// Library configuration. Modify this file as necessary.
|
||||
|
||||
#ifndef BLARGG_CONFIG_H
|
||||
#define BLARGG_CONFIG_H
|
||||
|
||||
// Uncomment to use zlib for transparent decompression of gzipped files
|
||||
//#define HAVE_ZLIB_H
|
||||
|
||||
// Uncomment and edit list to support only the listed game music types,
|
||||
// so that the others don't get linked in at all.
|
||||
/*
|
||||
#define GME_TYPE_LIST \
|
||||
gme_ay_type,\
|
||||
gme_gbs_type,\
|
||||
gme_gym_type,\
|
||||
gme_hes_type,\
|
||||
gme_kss_type,\
|
||||
gme_nsf_type,\
|
||||
gme_nsfe_type,\
|
||||
gme_sap_type,\
|
||||
gme_spc_type,\
|
||||
gme_vgm_type,\
|
||||
gme_vgz_type
|
||||
*/
|
||||
|
||||
// Uncomment to enable platform-specific optimizations
|
||||
//#define BLARGG_NONPORTABLE 1
|
||||
|
||||
// Uncomment to use faster, lower quality sound synthesis
|
||||
//#define BLIP_BUFFER_FAST 1
|
||||
|
||||
// Uncomment if automatic byte-order determination doesn't work
|
||||
//#define BLARGG_BIG_ENDIAN 1
|
||||
|
||||
// Uncomment if you get errors in the bool section of blargg_common.h
|
||||
//#define BLARGG_COMPILER_HAS_BOOL 1
|
||||
|
||||
// Use standard config.h if present
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
// By default, #included at beginning of library source files
|
||||
|
||||
// Copyright (C) 2005 Shay Green.
|
||||
/* Included at the beginning of library source files, after all other #include lines.
|
||||
Sets up helpful macros and services used in my source code. They don't need
|
||||
module an annoying module prefix on their names since they are defined after
|
||||
all other #include lines. */
|
||||
|
||||
#ifndef BLARGG_SOURCE_H
|
||||
#define BLARGG_SOURCE_H
|
||||
@@ -16,13 +16,14 @@
|
||||
// module. A failed requirement indicates a bug outside the module.
|
||||
// void require( bool expr );
|
||||
#undef require
|
||||
#define require( expr ) assert((/* "unmet requirement",*/ expr ))
|
||||
#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
|
||||
#define dprintf (1) ? ((void) 0) : (void)
|
||||
// void debug_printf( const char* format, ... );
|
||||
static inline void blargg_dprintf_( const char*, ... ) { }
|
||||
#undef debug_printf
|
||||
#define debug_printf (1) ? (void) 0 : blargg_dprintf_
|
||||
|
||||
// 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
|
||||
@@ -30,22 +31,40 @@
|
||||
#undef check
|
||||
#define check( expr ) ((void) 0)
|
||||
|
||||
// If expr returns non-NULL error string, return it from current function, otherwise continue.
|
||||
#define BLARGG_RETURN_ERR( expr ) do { \
|
||||
// If expr yields error string, return it from current function, otherwise continue.
|
||||
#undef RETURN_ERR
|
||||
#define 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) ) return "Out of memory"; } while ( 0 )
|
||||
// If ptr is 0, return out of memory error string.
|
||||
#undef CHECK_ALLOC
|
||||
#define 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
|
||||
|
||||
#define DEF_MIN_MAX( type ) \
|
||||
static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\
|
||||
static inline type max( type x, type y ) { if ( y < x ) return x; return y; }
|
||||
|
||||
DEF_MIN_MAX( int )
|
||||
DEF_MIN_MAX( unsigned )
|
||||
DEF_MIN_MAX( long )
|
||||
DEF_MIN_MAX( unsigned long )
|
||||
DEF_MIN_MAX( float )
|
||||
DEF_MIN_MAX( double )
|
||||
|
||||
#undef DEF_MIN_MAX
|
||||
|
||||
/*
|
||||
// using const references generates crappy code, and I am currenly only using these
|
||||
// for built-in types, so they take arguments by value
|
||||
|
||||
// TODO: remove
|
||||
inline int min( int x, int y )
|
||||
template<class T>
|
||||
inline T min( T x, T y )
|
||||
{
|
||||
@@ -61,6 +80,31 @@ inline T max( T x, T y )
|
||||
return y;
|
||||
return x;
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: good idea? bad idea?
|
||||
#undef byte
|
||||
#define byte byte_
|
||||
typedef unsigned char byte;
|
||||
|
||||
// Setup compiler defines useful for exporting required public API symbols in gme.cpp
|
||||
#ifndef BLARGG_EXPORT
|
||||
#if defined (_WIN32) && defined(BLARGG_BUILD_DLL)
|
||||
#define BLARGG_EXPORT __declspec(dllexport)
|
||||
#elif defined (LIBGME_VISIBILITY)
|
||||
#define BLARGG_EXPORT __attribute__((visibility ("default")))
|
||||
#else
|
||||
#define BLARGG_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// deprecated
|
||||
#define BLARGG_CHECK_ALLOC CHECK_ALLOC
|
||||
#define BLARGG_RETURN_ERR RETURN_ERR
|
||||
|
||||
// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of debug_printf and check
|
||||
#ifdef BLARGG_SOURCE_BEGIN
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -70,7 +70,7 @@ papuInstrument::papuInstrument( InstrumentTrack * _instrument_track ) :
|
||||
tr( "Sweep RtShift amount" ) ),
|
||||
m_ch1WavePatternDutyModel( 2.0f, 0.0f, 3.0f, 1.0f, this,
|
||||
tr( "Wave Pattern Duty" ) ),
|
||||
m_ch1VolumeModel( 15.0f, 0.0f, 15.0f, 1.0f, this,
|
||||
m_ch1VolumeModel( 15.0f, 0.0f, 15.0f, 1.0f, this,
|
||||
tr( "Channel 1 volume" ) ),
|
||||
m_ch1VolSweepDirModel( false, this,
|
||||
tr( "Volume sweep direction" ) ),
|
||||
@@ -396,7 +396,7 @@ void papuInstrument::playNote( NotePlayHandle * _n,
|
||||
}
|
||||
datalen = framesleft>avail?avail:framesleft;
|
||||
datalen = datalen>buf_size?buf_size:datalen;
|
||||
|
||||
|
||||
long count = papu->read_samples( buf, datalen*2)/2;
|
||||
|
||||
for( fpp_t frame = 0; frame < count; ++frame )
|
||||
|
||||
Reference in New Issue
Block a user