diff --git a/BlipBuffer/BlipBuffer.vcxproj b/BlipBuffer/BlipBuffer.vcxproj
new file mode 100644
index 00000000..7635a70b
--- /dev/null
+++ b/BlipBuffer/BlipBuffer.vcxproj
@@ -0,0 +1,158 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07}
+ Win32Proj
+ BlipBuffer
+
+
+
+ DynamicLibrary
+ true
+ v120
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v120
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v120
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v120
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;BLIPBUFFER_EXPORTS;%(PreprocessorDefinitions)
+
+
+ Windows
+ true
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;BLIPBUFFER_EXPORTS;%(PreprocessorDefinitions)
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;BLIPBUFFER_EXPORTS;%(PreprocessorDefinitions)
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;BLIPBUFFER_EXPORTS;%(PreprocessorDefinitions)
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BlipBuffer/BlipBuffer.vcxproj.filters b/BlipBuffer/BlipBuffer.vcxproj.filters
new file mode 100644
index 00000000..a50d99b8
--- /dev/null
+++ b/BlipBuffer/BlipBuffer.vcxproj.filters
@@ -0,0 +1,23 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/BlipBuffer/Blip_Buffer.cpp b/BlipBuffer/Blip_Buffer.cpp
new file mode 100644
index 00000000..dbde1501
--- /dev/null
+++ b/BlipBuffer/Blip_Buffer.cpp
@@ -0,0 +1,406 @@
+
+// Blip_Buffer 0.4.0. http://www.slack.net/~ant/
+
+#include "Blip_Buffer.h"
+
+#include
+#include
+#include
+#include
+#include
+
+/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
+can redistribute it and/or modify it under the terms of the GNU Lesser
+General Public License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version. This
+module is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+more details. You should have received a copy of the GNU Lesser General
+Public License along with this module; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+int const buffer_extra = blip_widest_impulse_ + 2;
+
+Blip_Buffer::Blip_Buffer()
+{
+ factor_ = LONG_MAX;
+ offset_ = 0;
+ buffer_ = 0;
+ buffer_size_ = 0;
+ sample_rate_ = 0;
+ reader_accum = 0;
+ bass_shift = 0;
+ clock_rate_ = 0;
+ bass_freq_ = 16;
+ length_ = 0;
+
+ // assumptions code makes about implementation-defined features
+ #ifndef NDEBUG
+ // right shift of negative value preserves sign
+ int i = INT_MIN;
+ assert( (i >> 1) == INT_MIN / 2 );
+
+ // casting to smaller signed type truncates bits and extends sign
+ long l = (SHRT_MAX + 1) * 5;
+ assert( (short) l == SHRT_MIN );
+ #endif
+}
+
+Blip_Buffer::~Blip_Buffer()
+{
+ free( buffer_ );
+}
+
+void Blip_Buffer::clear( int entire_buffer )
+{
+ offset_ = 0;
+ reader_accum = 0;
+ if ( buffer_ )
+ {
+ long count = (entire_buffer ? buffer_size_ : samples_avail());
+ memset( buffer_, 0, (count + buffer_extra) * sizeof (buf_t_) );
+ }
+}
+
+Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
+{
+ // start with maximum length that resampled time can represent
+ long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - buffer_extra - 64;
+ if ( msec != blip_max_length )
+ {
+ long s = (new_rate * (msec + 1) + 999) / 1000;
+ if ( s < new_size )
+ new_size = s;
+ else
+ assert( 0 ); // fails if requested buffer length exceeds limit
+ }
+
+ if ( buffer_size_ != new_size )
+ {
+ void* p = realloc( buffer_, (new_size + buffer_extra) * sizeof *buffer_ );
+ if ( !p )
+ return "Out of memory";
+ buffer_ = (buf_t_*) p;
+ }
+
+ buffer_size_ = new_size;
+
+ // update things based on the sample rate
+ sample_rate_ = new_rate;
+ length_ = new_size * 1000 / new_rate - 1;
+ if ( msec )
+ assert( length_ == msec ); // ensure length is same as that passed in
+ if ( clock_rate_ )
+ clock_rate( clock_rate_ );
+ bass_freq( bass_freq_ );
+
+ clear();
+
+ return 0; // success
+}
+
+blip_resampled_time_t Blip_Buffer::clock_rate_factor( long clock_rate ) const
+{
+ double ratio = (double) sample_rate_ / clock_rate;
+ long factor = (long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
+ assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
+ return (blip_resampled_time_t) factor;
+}
+
+void Blip_Buffer::bass_freq( int freq )
+{
+ bass_freq_ = freq;
+ int shift = 31;
+ if ( freq > 0 )
+ {
+ shift = 13;
+ long f = (freq << 16) / sample_rate_;
+ while ( (f >>= 1) && --shift ) { }
+ }
+ bass_shift = shift;
+}
+
+void Blip_Buffer::end_frame( blip_time_t t )
+{
+ offset_ += t * factor_;
+ assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length
+}
+
+void Blip_Buffer::remove_silence( long count )
+{
+ assert( count <= samples_avail() ); // tried to remove more samples than available
+ offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
+}
+
+long Blip_Buffer::count_samples( blip_time_t t ) const
+{
+ unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
+ unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
+ return (long) (last_sample - first_sample);
+}
+
+blip_time_t Blip_Buffer::count_clocks( long count ) const
+{
+ if ( count > buffer_size_ )
+ count = buffer_size_;
+ blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
+ return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
+}
+
+void Blip_Buffer::remove_samples( long count )
+{
+ if ( count )
+ {
+ remove_silence( count );
+
+ // copy remaining samples to beginning and clear old samples
+ long remain = samples_avail() + buffer_extra;
+ memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
+ memset( buffer_ + remain, 0, count * sizeof *buffer_ );
+ }
+}
+
+// Blip_Synth_
+
+Blip_Synth_::Blip_Synth_( short* p, int w ) :
+ impulses( p ),
+ width( w )
+{
+ volume_unit_ = 0.0;
+ kernel_unit = 0;
+ buf = 0;
+ last_amp = 0;
+ delta_factor = 0;
+}
+
+static double const pi = 3.1415926535897932384626433832795029;
+
+static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
+{
+ if ( cutoff >= 0.999 )
+ cutoff = 0.999;
+
+ if ( treble < -300.0 )
+ treble = -300.0;
+ if ( treble > 5.0 )
+ treble = 5.0;
+
+ double const maxh = 4096.0;
+ double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
+ double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
+ double const to_angle = pi / 2 / maxh / oversample;
+ for ( int i = 0; i < count; i++ )
+ {
+ double angle = ((i - count) * 2 + 1) * to_angle;
+ double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
+ double cos_nc_angle = cos( maxh * cutoff * angle );
+ double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
+ double cos_angle = cos( angle );
+
+ c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
+ double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
+ double b = 2.0 - cos_angle - cos_angle;
+ double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
+
+ out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
+ }
+}
+
+void blip_eq_t::generate( float* out, int count ) const
+{
+ // lower cutoff freq for narrow kernels with their wider transition band
+ // (8 points->1.49, 16 points->1.15)
+ double oversample = blip_res * 2.25 / count + 0.85;
+ double half_rate = sample_rate * 0.5;
+ if ( cutoff_freq )
+ oversample = half_rate / cutoff_freq;
+ double cutoff = rolloff_freq * oversample / half_rate;
+
+ gen_sinc( out, count, blip_res * oversample, treble, cutoff );
+
+ // apply (half of) hamming window
+ double to_fraction = pi / (count - 1);
+ for ( int i = count; i--; )
+ out [i] *= (float)(0.54 - 0.46 * cos( i * to_fraction ));
+}
+
+void Blip_Synth_::adjust_impulse()
+{
+ // sum pairs for each phase and add error correction to end of first half
+ int const size = impulses_size();
+ for ( int p = blip_res; p-- >= blip_res / 2; )
+ {
+ int p2 = blip_res - 2 - p;
+ long error = kernel_unit;
+ for ( int i = 1; i < size; i += blip_res )
+ {
+ error -= impulses [i + p ];
+ error -= impulses [i + p2];
+ }
+ if ( p == p2 )
+ error /= 2; // phase = 0.5 impulse uses same half for both sides
+ impulses [size - blip_res + p] += (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 );
+ }
+}
+
+long Blip_Buffer::read_samples( blip_sample_t* out, long max_samples, int stereo )
+{
+ long count = samples_avail();
+ if ( count > max_samples )
+ count = max_samples;
+
+ if ( count )
+ {
+ int const sample_shift = blip_sample_bits - 16;
+ int const bass_shift = this->bass_shift;
+ long accum = reader_accum;
+ buf_t_* in = buffer_;
+
+ if ( !stereo )
+ {
+ for ( long n = count; n--; )
+ {
+ long s = accum >> sample_shift;
+ accum -= accum >> bass_shift;
+ accum += *in++;
+ *out++ = (blip_sample_t) s;
+
+ // clamp sample
+ if ( (blip_sample_t) s != s )
+ out [-1] = (blip_sample_t) (0x7FFF - (s >> 24));
+ }
+ }
+ else
+ {
+ for ( long n = count; n--; )
+ {
+ long s = accum >> sample_shift;
+ accum -= accum >> bass_shift;
+ accum += *in++;
+ *out = (blip_sample_t) s;
+ out += 2;
+
+ // clamp sample
+ if ( (blip_sample_t) s != s )
+ out [-2] = (blip_sample_t) (0x7FFF - (s >> 24));
+ }
+ }
+
+ reader_accum = accum;
+ remove_samples( count );
+ }
+ return count;
+}
+
+void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
+{
+ buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
+
+ int const sample_shift = blip_sample_bits - 16;
+ int prev = 0;
+ while ( count-- )
+ {
+ long s = (long) *in++ << sample_shift;
+ *out += s - prev;
+ prev = s;
+ ++out;
+ }
+ *out -= prev;
+}
+
diff --git a/BlipBuffer/Blip_Buffer.h b/BlipBuffer/Blip_Buffer.h
new file mode 100644
index 00000000..8972bb7e
--- /dev/null
+++ b/BlipBuffer/Blip_Buffer.h
@@ -0,0 +1,354 @@
+
+// Band-limited sound synthesis and buffering
+
+// Blip_Buffer 0.4.0
+
+#ifndef BLIP_BUFFER_H
+#define BLIP_BUFFER_H
+
+// Time unit at source clock rate
+typedef long blip_time_t;
+
+// Output samples are 16-bit signed, with a range of -32767 to 32767
+typedef short blip_sample_t;
+enum { blip_sample_max = 32767 };
+
+class __declspec(dllexport) Blip_Buffer {
+public:
+ typedef const char* blargg_err_t;
+
+ // Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
+ // to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
+ // isn't enough memory, returns error without affecting current buffer setup.
+ blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
+
+ // Set number of source time units per second
+ void clock_rate( long );
+
+ // End current time frame of specified duration and make its samples available
+ // (along with any still-unread samples) for reading with read_samples(). Begins
+ // a new time frame at the end of the current frame.
+ void end_frame( blip_time_t time );
+
+ // Read at most 'max_samples' out of buffer into 'dest', removing them from from
+ // the buffer. Returns number of samples actually read and removed. If stereo is
+ // true, increments 'dest' one extra time after writing each sample, to allow
+ // easy interleving of two channels into a stereo output buffer.
+ long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
+
+// Additional optional features
+
+ // Current output sample rate
+ long sample_rate() const;
+
+ // Length of buffer, in milliseconds
+ int length() const;
+
+ // Number of source time units per second
+ long clock_rate() const;
+
+ // Set frequency high-pass filter frequency, where higher values reduce bass more
+ void bass_freq( int frequency );
+
+ // Number of samples delay from synthesis to samples read out
+ int output_latency() const;
+
+ // Remove all available samples and clear buffer to silence. If 'entire_buffer' is
+ // false, just clears out any samples waiting rather than the entire buffer.
+ void clear( int entire_buffer = 1 );
+
+ // Number of samples available for reading with read_samples()
+ long samples_avail() const;
+
+ // Remove 'count' samples from those waiting to be read
+ void remove_samples( long count );
+
+// Experimental features
+
+ // Number of raw samples that can be mixed within frame of specified duration.
+ long count_samples( blip_time_t duration ) const;
+
+ // Mix 'count' samples from 'buf' into buffer.
+ void mix_samples( blip_sample_t const* buf, long count );
+
+ // Count number of clocks needed until 'count' samples will be available.
+ // If buffer can't even hold 'count' samples, returns number of clocks until
+ // buffer becomes full.
+ blip_time_t count_clocks( long count ) const;
+
+ // not documented yet
+ typedef unsigned long blip_resampled_time_t;
+ void remove_silence( long count );
+ blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
+ blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
+ blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
+public:
+ Blip_Buffer();
+ ~Blip_Buffer();
+
+ // Deprecated
+ typedef blip_resampled_time_t resampled_time_t;
+ blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
+ blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
+private:
+ // noncopyable
+ Blip_Buffer( const Blip_Buffer& );
+ Blip_Buffer& operator = ( const Blip_Buffer& );
+public:
+ typedef long buf_t_;
+ unsigned long factor_;
+ blip_resampled_time_t offset_;
+ buf_t_* buffer_;
+ long buffer_size_;
+private:
+ long reader_accum;
+ int bass_shift;
+ long sample_rate_;
+ long clock_rate_;
+ int bass_freq_;
+ int length_;
+ friend class Blip_Reader;
+};
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
+// but reduce maximum buffer size.
+#ifndef BLIP_BUFFER_ACCURACY
+ #define BLIP_BUFFER_ACCURACY 16
+#endif
+
+// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
+// noticeable broadband noise when synthesizing high frequency square waves.
+// Affects size of Blip_Synth objects since they store the waveform directly.
+#ifndef BLIP_PHASE_BITS
+ #define BLIP_PHASE_BITS 6
+#endif
+
+ // Internal
+ typedef unsigned long blip_resampled_time_t;
+ int const blip_widest_impulse_ = 16;
+ int const blip_res = 1 << BLIP_PHASE_BITS;
+ class blip_eq_t;
+
+ class __declspec(dllexport) Blip_Synth_ {
+ double volume_unit_;
+ short* const impulses;
+ int const width;
+ long kernel_unit;
+ int impulses_size() const { return blip_res / 2 * width + 1; }
+ void adjust_impulse();
+ public:
+ Blip_Buffer* buf;
+ int last_amp;
+ int delta_factor;
+
+ Blip_Synth_( short* impulses, int width );
+ void treble_eq( blip_eq_t const& );
+ void volume_unit( double );
+ };
+
+// Quality level. Start with blip_good_quality.
+const int blip_med_quality = 8;
+const int blip_good_quality = 12;
+const int blip_high_quality = 16;
+
+// Range specifies the greatest expected change in amplitude. Calculate it
+// by finding the difference between the maximum and minimum expected
+// amplitudes (max - min).
+template
+class __declspec(dllexport) Blip_Synth {
+public:
+ // Set overall volume of waveform
+ void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
+
+ // Configure low-pass filter (see notes.txt)
+ void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
+
+ // Get/set Blip_Buffer used for output
+ Blip_Buffer* output() const { return impl.buf; }
+ void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
+
+ // Update amplitude of waveform at given time. Using this requires a separate
+ // Blip_Synth for each waveform.
+ void update( blip_time_t time, int amplitude );
+
+// Low-level interface
+
+ // Add an amplitude transition of specified delta, optionally into specified buffer
+ // rather than the one set with output(). Delta can be positive or negative.
+ // The actual change in amplitude is delta * (volume / range)
+ void offset( blip_time_t, int delta, Blip_Buffer* ) const;
+ void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
+
+ // Works directly in terms of fractional output samples. Contact author for more.
+ void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
+
+ // Same as offset(), except code is inlined for higher performance
+ void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
+ offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
+ }
+ void offset_inline( blip_time_t t, int delta ) const {
+ offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
+ }
+
+public:
+ Blip_Synth() : impl( impulses, quality ) { }
+private:
+ typedef short imp_t;
+ imp_t impulses [blip_res * (quality / 2) + 1];
+ Blip_Synth_ impl;
+};
+
+// Low-pass equalization parameters
+class blip_eq_t {
+public:
+ // Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
+ // treble, small positive values (0 to 5.0) increase treble.
+ blip_eq_t( double treble_db = 0 );
+
+ // See notes.txt
+ blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
+
+private:
+ double treble;
+ long rolloff_freq;
+ long sample_rate;
+ long cutoff_freq;
+ void generate( float* out, int count ) const;
+ friend class Blip_Synth_;
+};
+
+int const blip_sample_bits = 30;
+
+// Optimized inline sample reader for custom sample formats and mixing of Blip_Buffer samples
+class Blip_Reader {
+public:
+ // Begin reading samples from buffer. Returns value to pass to next() (can
+ // be ignored if default bass_freq is acceptable).
+ int begin( Blip_Buffer& );
+
+ // Current sample
+ long read() const { return accum >> (blip_sample_bits - 16); }
+
+ // Current raw sample in full internal resolution
+ long read_raw() const { return accum; }
+
+ // Advance to next sample
+ void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
+
+ // End reading samples from buffer. The number of samples read must now be removed
+ // using Blip_Buffer::remove_samples().
+ void end( Blip_Buffer& b ) { b.reader_accum = accum; }
+
+private:
+ const Blip_Buffer::buf_t_* buf;
+ long accum;
+};
+
+
+// End of public interface
+
+
+#include
+
+// Compatibility with older version
+const long blip_unscaled = 65535;
+const int blip_low_quality = blip_med_quality;
+const int blip_best_quality = blip_high_quality;
+
+#define BLIP_FWD( i ) { \
+ long t0 = i0 * delta + buf [fwd + i]; \
+ long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i]; \
+ i0 = imp [blip_res * (i + 2)]; \
+ buf [fwd + i] = t0; \
+ buf [fwd + 1 + i] = t1; }
+
+#define BLIP_REV( r ) { \
+ long t0 = i0 * delta + buf [rev - r]; \
+ long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r]; \
+ i0 = imp [blip_res * (r - 1)]; \
+ buf [rev - r] = t0; \
+ buf [rev + 1 - r] = t1; }
+
+template
+inline void Blip_Synth::offset_resampled( blip_resampled_time_t time,
+ int delta, Blip_Buffer* blip_buf ) const
+{
+ // Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
+ // need for a longer buffer as set by set_sample_rate().
+ assert( (long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
+ delta *= impl.delta_factor;
+ int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
+ imp_t const* imp = impulses + blip_res - phase;
+ long* buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
+ long i0 = *imp;
+
+ int const fwd = (blip_widest_impulse_ - quality) / 2;
+ int const rev = fwd + quality - 2;
+
+ BLIP_FWD( 0 )
+ if ( quality > 8 ) BLIP_FWD( 2 )
+ if ( quality > 12 ) BLIP_FWD( 4 )
+ {
+ int const mid = quality / 2 - 1;
+ long t0 = i0 * delta + buf [fwd + mid - 1];
+ long t1 = imp [blip_res * mid] * delta + buf [fwd + mid];
+ imp = impulses + phase;
+ i0 = imp [blip_res * mid];
+ buf [fwd + mid - 1] = t0;
+ buf [fwd + mid] = t1;
+ }
+ if ( quality > 12 ) BLIP_REV( 6 )
+ if ( quality > 8 ) BLIP_REV( 4 )
+ BLIP_REV( 2 )
+
+ long t0 = i0 * delta + buf [rev];
+ long t1 = *imp * delta + buf [rev + 1];
+ buf [rev] = t0;
+ buf [rev + 1] = t1;
+}
+
+#undef BLIP_FWD
+#undef BLIP_REV
+
+template
+void Blip_Synth::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
+{
+ offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
+}
+
+template
+void Blip_Synth::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
+
diff --git a/Core/APU.cpp b/Core/APU.cpp
index 6b037d34..57744e94 100644
--- a/Core/APU.cpp
+++ b/Core/APU.cpp
@@ -1,7 +1,12 @@
#include "stdafx.h"
+#include "../BlipBuffer/Blip_Buffer.h"
#include "APU.h"
#include "CPU.h"
-#include "Nes_Apu\apu_snapshot.h"
+#include "SquareChannel.h"
+#include "TriangleChannel.h"
+#include "NoiseChannel.h"
+#include "DeltaModulationChannel.h"
+#include "ApuFrameCounter.h"
APU* APU::Instance = nullptr;
IAudioDevice* APU::AudioDevice = nullptr;
@@ -11,15 +16,31 @@ APU::APU(MemoryManager* memoryManager)
APU::Instance = this;
_memoryManager = memoryManager;
-
- _buf.sample_rate(APU::SampleRate);
- _buf.clock_rate(CPU::ClockRate);
- _apu.output(&_buf);
-
- _apu.dmc_reader(&APU::DMCRead);
- //_apu.irq_notifier(&APU::IRQChanged);
+ _blipBuffer = new Blip_Buffer();
+ _blipBuffer->sample_rate(APU::SampleRate);
+ _blipBuffer->clock_rate(CPU::ClockRate);
_outputBuffer = new int16_t[APU::SamplesPerFrame];
+
+ _squareChannel.push_back(unique_ptr(new SquareChannel(true)));
+ _squareChannel.push_back(unique_ptr(new SquareChannel(false)));
+ _triangleChannel.reset(new TriangleChannel());
+ _noiseChannel.reset(new NoiseChannel());
+ _deltaModulationChannel.reset(new DeltaModulationChannel(_memoryManager));
+ _frameCounter.reset(new ApuFrameCounter(&APU::FrameCounterTick));
+
+ _squareChannel[0]->SetBuffer(_blipBuffer);
+ _squareChannel[1]->SetBuffer(_blipBuffer);
+ _triangleChannel->SetBuffer(_blipBuffer);
+ _noiseChannel->SetBuffer(_blipBuffer);
+ _deltaModulationChannel->SetBuffer(_blipBuffer);
+
+ _memoryManager->RegisterIODevice(_squareChannel[0].get());
+ _memoryManager->RegisterIODevice(_squareChannel[1].get());
+ _memoryManager->RegisterIODevice(_frameCounter.get());
+ _memoryManager->RegisterIODevice(_triangleChannel.get());
+ _memoryManager->RegisterIODevice(_noiseChannel.get());
+ _memoryManager->RegisterIODevice(_deltaModulationChannel.get());
}
APU::~APU()
@@ -29,52 +50,137 @@ APU::~APU()
void APU::Reset()
{
- _apu.reset();
+ //_apu.reset();
}
-int APU::DMCRead(void*, cpu_addr_t addr)
+void APU::FrameCounterTick(FrameType type)
{
- return APU::Instance->_memoryManager->Read(addr);
+ //Quarter & half frame clock envelope & linear counter
+ Instance->_squareChannel[0]->TickEnvelope();
+ Instance->_squareChannel[1]->TickEnvelope();
+ Instance->_triangleChannel->TickLinearCounter();
+ Instance->_noiseChannel->TickEnvelope();
+
+ if(type == FrameType::HalfFrame) {
+ //Half frames clock length counter & sweep
+ Instance->_squareChannel[0]->TickLengthCounter();
+ Instance->_squareChannel[1]->TickLengthCounter();
+ Instance->_triangleChannel->TickLengthCounter();
+ Instance->_noiseChannel->TickLengthCounter();
+
+ Instance->_squareChannel[0]->TickSweep();
+ Instance->_squareChannel[1]->TickSweep();
+ }
}
uint8_t APU::ReadRAM(uint16_t addr)
{
- switch(addr) {
- case 0x4015:
- CPU::ClearIRQSource(IRQSource::FrameCounter);
- return _apu.read_status(_currentClock + 4);
- }
+ //$4015 read
+ Run();
- return 0;
+ uint8_t status = 0;
+ status |= _squareChannel[0]->GetStatus() ? 0x01 : 0x00;
+ status |= _squareChannel[1]->GetStatus() ? 0x02 : 0x00;
+ status |= _triangleChannel->GetStatus() ? 0x04 : 0x00;
+ status |= _noiseChannel->GetStatus() ? 0x08 : 0x00;
+ status |= _deltaModulationChannel->GetStatus() ? 0x10 : 0x00;
+ status |= CPU::HasIRQSource(IRQSource::FrameCounter) ? 0x40 : 0x00;
+ status |= CPU::HasIRQSource(IRQSource::DMC) ? 0x80 : 0x00;
+
+ //Reading $4015 clears the Frame Counter interrupt flag.
+ CPU::ClearIRQSource(IRQSource::FrameCounter);
+
+ return status;
}
void APU::WriteRAM(uint16_t addr, uint8_t value)
{
- _apu.write_register(_currentClock + 4, addr, value);
- if(addr == 0x4017 && (value & 0x40) == 0x40) {
- //Disable frame interrupts
- CPU::ClearIRQSource(IRQSource::FrameCounter);
- }
+ //$4015 write
+ Run();
+ _squareChannel[0]->SetEnabled((value & 0x01) == 0x01);
+ _squareChannel[1]->SetEnabled((value & 0x02) == 0x02);
+ _triangleChannel->SetEnabled((value & 0x04) == 0x04);
+ _noiseChannel->SetEnabled((value & 0x08) == 0x08);
+ _deltaModulationChannel->SetEnabled((value & 0x10) == 0x10);
+
+ //Writing to $4015 clears the DMC interrupt flag.
+ CPU::ClearIRQSource(IRQSource::DMC);
}
-bool APU::Exec(uint32_t currentCPUCycle)
+void APU::GetMemoryRanges(MemoryRanges &ranges)
{
- _currentClock = currentCPUCycle;
+ ranges.AddHandler(MemoryType::RAM, MemoryOperation::Read, 0x4015);
+ ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4015);
+}
- if(_currentClock >= 29780) {
- _apu.end_frame(_currentClock);
- _buf.end_frame(_currentClock);
+void APU::Run()
+{
+ //Update framecounter and all channels
+ //This is called:
+ //-At the end of a frame
+ //-Before APU registers are read/written to
+ //-When a DMC or FrameCounter interrupt needs to be fired
+ uint32_t targetCycle = CPU::GetCycleCount();
+ uint32_t currentCycle = _previousCycle;
+ uint32_t cyclesToRun = targetCycle - _previousCycle;
- _currentClock = 0;
+ while(currentCycle < targetCycle) {
+ currentCycle += _frameCounter->Run(cyclesToRun);
- if(APU::Instance->_apu.earliest_irq() == Nes_Apu::irq_waiting) {
- CPU::SetIRQSource(IRQSource::FrameCounter);
- }
+ _squareChannel[0]->Run(currentCycle);
+ _squareChannel[1]->Run(currentCycle);
+ _noiseChannel->Run(currentCycle);
+ _triangleChannel->Run(currentCycle);
+ _deltaModulationChannel->Run(currentCycle);
+ }
+
+ _previousCycle = targetCycle;
+}
+
+void APU::StaticRun()
+{
+ Instance->Run();
+}
+
+bool APU::IrqPending(uint32_t currentCycle)
+{
+ uint32_t cyclesToRun = currentCycle - _previousCycle;
+ if(_frameCounter->IrqPending(cyclesToRun)) {
+ return true;
+ } else if(_deltaModulationChannel->IrqPending(cyclesToRun)) {
+ return true;
+ }
+ return false;
+}
+
+void APU::ExecStatic(uint32_t currentCpuCycle)
+{
+ Instance->Exec(currentCpuCycle);
+}
+
+bool APU::Exec(uint32_t currentCpuCycle)
+{
+ if(IrqPending(currentCpuCycle)) {
+ Run();
+ }
+
+ if(currentCpuCycle >= 29780) {
+ Run();
+
+ _previousCycle = 0;
+
+ _squareChannel[0]->EndFrame();
+ _squareChannel[1]->EndFrame();
+ _triangleChannel->EndFrame();
+ _noiseChannel->EndFrame();
+ _deltaModulationChannel->EndFrame();
+
+ _blipBuffer->end_frame(currentCpuCycle);
// Read some samples out of Blip_Buffer if there are enough to fill our output buffer
- uint32_t availableSampleCount = _buf.samples_avail();
+ uint32_t availableSampleCount = _blipBuffer->samples_avail();
if(availableSampleCount >= APU::SamplesPerFrame) {
- size_t sampleCount = _buf.read_samples(_outputBuffer, APU::SamplesPerFrame);
+ size_t sampleCount = _blipBuffer->read_samples(_outputBuffer, APU::SamplesPerFrame);
if(APU::AudioDevice) {
APU::AudioDevice->PlayBuffer(_outputBuffer, (uint32_t)(sampleCount * BitsPerSample / 8));
}
@@ -93,9 +199,9 @@ void APU::StopAudio()
void APU::StreamState(bool saving)
{
- apu_snapshot_t snapshot;
+ /*apu_snapshot_t snapshot;
if(saving) {
- _apu.save_snapshot(&snapshot);
+ //_apu.save_snapshot(&snapshot);
}
Stream(_currentClock);
@@ -145,6 +251,6 @@ void APU::StreamState(bool saving)
Stream(snapshot.dmc.irq_flag);
if(!saving) {
- _apu.load_snapshot(snapshot);
- }
+ //_apu.load_snapshot(snapshot);
+ }*/
}
\ No newline at end of file
diff --git a/Core/APU.h b/Core/APU.h
index 3c0862d7..6dc5b026 100644
--- a/Core/APU.h
+++ b/Core/APU.h
@@ -1,28 +1,44 @@
#pragma once
#include "stdafx.h"
-#include "MemoryManager.h"
#include "IMemoryHandler.h"
#include "IAudioDevice.h"
#include "Snapshotable.h"
-#include "Nes_Apu/Nes_Apu.h"
-class APU : public IMemoryHandler, public Snapshotable
+class MemoryManager;
+class SquareChannel;
+class TriangleChannel;
+class NoiseChannel;
+class DeltaModulationChannel;
+class ApuFrameCounter;
+class Blip_Buffer;
+enum class FrameType;
+
+class APU : public Snapshotable, public IMemoryHandler
{
private:
static IAudioDevice* AudioDevice;
static APU* Instance;
uint32_t _currentClock = 0;
+ uint32_t _previousCycle = 0;
- Nes_Apu _apu;
- Blip_Buffer _buf;
+ vector> _squareChannel;
+ unique_ptr _triangleChannel;
+ unique_ptr _noiseChannel;
+ unique_ptr _deltaModulationChannel;
+
+ unique_ptr _frameCounter;
+
+ Blip_Buffer* _blipBuffer;
int16_t* _outputBuffer;
MemoryManager* _memoryManager;
private:
- static int DMCRead(void*, cpu_addr_t addr);
- static void IRQChanged(void* data);
+ bool IrqPending(uint32_t currentCycle);
+ void Run();
+
+ static void FrameCounterTick(FrameType type);
protected:
void StreamState(bool saving);
@@ -38,14 +54,6 @@ class APU : public IMemoryHandler, public Snapshotable
void Reset();
- void GetMemoryRanges(MemoryRanges &ranges)
- {
- ranges.AddHandler(MemoryType::RAM, MemoryOperation::Read, 0x4015);
- ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4000, 0x4013);
- ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4015);
- ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4017);
- }
-
static void RegisterAudioDevice(IAudioDevice *audioDevice)
{
APU::AudioDevice = audioDevice;
@@ -53,7 +61,11 @@ class APU : public IMemoryHandler, public Snapshotable
uint8_t ReadRAM(uint16_t addr);
void WriteRAM(uint16_t addr, uint8_t value);
+ void GetMemoryRanges(MemoryRanges &ranges);
- bool Exec(uint32_t executedCycles);
+ bool Exec(uint32_t currentCpuCycle);
+ static void ExecStatic(uint32_t currentCpuCycle);
+
+ static void StaticRun();
static void StopAudio();
};
\ No newline at end of file
diff --git a/Core/ApuEnvelope.h b/Core/ApuEnvelope.h
new file mode 100644
index 00000000..dee33dac
--- /dev/null
+++ b/Core/ApuEnvelope.h
@@ -0,0 +1,62 @@
+#pragma once
+#include "stdafx.h"
+#include "ApuLengthCounter.h"
+
+class ApuEnvelope : public ApuLengthCounter
+{
+private:
+ bool _constantVolume = false;
+ uint8_t _volume = 0;
+
+ uint8_t _envelope = 0;
+ uint8_t _envelopeCounter = 0;
+
+ bool _start = false;
+ int8_t _divider = 0;
+ uint8_t _counter = 0;
+
+protected:
+ void InitializeEnvelope(uint8_t regValue)
+ {
+ _constantVolume = (regValue & 0x10) == 0x10;
+ _volume = regValue & 0x0F;
+ }
+
+ void ResetEnvelope()
+ {
+ _start = true;
+ }
+
+ uint32_t GetVolume()
+ {
+ if(_lengthCounter > 0) {
+ if(_constantVolume) {
+ return _volume;
+ } else {
+ return _counter;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+public:
+ void TickEnvelope()
+ {
+ if(!_start) {
+ _divider--;
+ if(_divider < 0) {
+ _divider = _volume;
+ if(_counter > 0) {
+ _counter--;
+ } else if(_lengthCounterHalt) {
+ _counter = 15;
+ }
+ }
+ } else {
+ _start = false;
+ _counter = 15;
+ _divider = _volume;
+ }
+ }
+};
diff --git a/Core/ApuFrameCounter.h b/Core/ApuFrameCounter.h
new file mode 100644
index 00000000..8c740ab1
--- /dev/null
+++ b/Core/ApuFrameCounter.h
@@ -0,0 +1,115 @@
+#pragma once
+#include "stdafx.h"
+#include "IMemoryHandler.h"
+#include "CPU.h"
+
+enum class FrameType
+{
+ None = 0,
+ QuarterFrame = 1,
+ HalfFrame = 2,
+};
+
+class ApuFrameCounter : public IMemoryHandler
+{
+private:
+ int32_t _nextIrqCycle = 29828;
+ uint32_t _previousCycle = 0;
+
+ const vector> _stepCycles = { { { 7457, 14913, 22371, 29828, 29829, 29830},
+ { 7457, 14913, 22371, 29829, 37281, 37282} } };
+ const vector> _frameType = { { { FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None },
+ { FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None } } };
+
+ void (*_callback)(FrameType);
+
+ uint32_t _currentStep = 0;
+ uint32_t _stepMode = 0; //0: 4-step mode, 1: 5-step mode
+ bool _inhibitIRQ = false;
+
+public:
+ ApuFrameCounter(void (*frameCounterTickCallback)(FrameType))
+ {
+ _callback = frameCounterTickCallback;
+ }
+
+ uint32_t Run(uint32_t &cyclesToRun)
+ {
+ uint32_t cyclesRan;
+
+ if(_previousCycle + cyclesToRun >= _stepCycles[_stepMode][_currentStep]) {
+ if(!_inhibitIRQ && _stepMode == 0 && _currentStep >= 3) {
+ //Set irq on the last 3 cycles for 4-step mode
+ CPU::SetIRQSource(IRQSource::FrameCounter);
+ _nextIrqCycle++;
+ }
+
+ FrameType type = _frameType[_stepMode][_currentStep];
+ if(type != FrameType::None) {
+ _callback(type);
+ }
+
+ cyclesRan = _stepCycles[_stepMode][_currentStep] - _previousCycle;
+ cyclesToRun -= cyclesRan;
+
+ _currentStep++;
+ if(_currentStep == 6) {
+ _currentStep = 0;
+ _previousCycle = 0;
+ if(_stepMode == 0 && !_inhibitIRQ) {
+ _nextIrqCycle = 29828;
+ }
+ } else {
+ _previousCycle += cyclesRan;
+ }
+ } else {
+ cyclesRan = cyclesToRun;
+ cyclesToRun = 0;
+ _previousCycle += cyclesRan;
+ }
+ return cyclesRan;
+ }
+
+ bool IrqPending(uint32_t cyclesToRun)
+ {
+ if(_nextIrqCycle != -1) {
+ if(_previousCycle + cyclesToRun >= (uint32_t)_nextIrqCycle) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void GetMemoryRanges(MemoryRanges &ranges)
+ {
+ ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4017);
+ }
+
+ uint8_t ReadRAM(uint16_t addr)
+ {
+ return 0;
+ }
+
+ void WriteRAM(uint16_t addr, uint8_t value)
+ {
+ APU::StaticRun();
+ _stepMode = ((value & 0x80) == 0x80) ? 1 : 0;
+ _inhibitIRQ = (value & 0x40) == 0x40;
+ _nextIrqCycle = -1;
+
+ if(_inhibitIRQ) {
+ CPU::ClearIRQSource(IRQSource::FrameCounter);
+ } else if(_stepMode == 0) {
+ _nextIrqCycle = 29828;
+ }
+
+ //Reset sequence when $4017 is written to
+ _previousCycle = 0;
+ _currentStep = 0;
+
+ if(_stepMode == 1) {
+ //Writing to $4017 with bit 7 set will immediately generate a clock for both the quarter frame and the half frame units, regardless of what the sequencer is doing.
+ _callback(FrameType::HalfFrame);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/ApuLengthCounter.h b/Core/ApuLengthCounter.h
new file mode 100644
index 00000000..92e5bd32
--- /dev/null
+++ b/Core/ApuLengthCounter.h
@@ -0,0 +1,47 @@
+#pragma once
+#include "stdafx.h"
+#include "BaseApuChannel.h"
+
+class ApuLengthCounter : public BaseApuChannel<15>
+{
+private:
+ const vector _lcLookupTable = { { 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30 } };
+ bool _enabled = false;
+
+protected:
+ bool _lengthCounterHalt = false;
+ uint8_t _lengthCounter = 0;
+
+ void InitializeLengthCounter(bool haltFlag)
+ {
+ _lengthCounterHalt = haltFlag;
+ }
+
+ void LoadLengthCounter(uint8_t value)
+ {
+ if(_enabled) {
+ _lengthCounter = _lcLookupTable[value];
+ }
+ }
+
+public:
+ bool GetStatus()
+ {
+ return _lengthCounter > 0;
+ }
+
+ void TickLengthCounter()
+ {
+ if(_lengthCounter > 0 && !_lengthCounterHalt) {
+ _lengthCounter--;
+ }
+ }
+
+ void SetEnabled(bool enabled)
+ {
+ if(!enabled) {
+ _lengthCounter = 0;
+ }
+ _enabled = enabled;
+ }
+};
diff --git a/Core/BaseApuChannel.h b/Core/BaseApuChannel.h
new file mode 100644
index 00000000..c44248e3
--- /dev/null
+++ b/Core/BaseApuChannel.h
@@ -0,0 +1,76 @@
+#pragma once
+#include "stdafx.h"
+#include "IMemoryHandler.h"
+#include "../BlipBuffer/Blip_Buffer.h"
+
+template
+class BaseApuChannel : public IMemoryHandler
+{
+private:
+ unique_ptr> _synth;
+ uint16_t _lastOutput = 0;
+ uint32_t _previousCycle = 0;
+ Blip_Buffer *_buffer;
+
+protected:
+ uint16_t _timer = 0;
+ uint16_t _period = 0;
+ uint32_t _clockDivider = 2; //All channels except triangle clock overy other cpu clock
+
+public:
+ virtual void Clock() = 0;
+ virtual bool GetStatus() = 0;
+
+ BaseApuChannel()
+ {
+ _synth.reset(new Blip_Synth());
+ }
+
+ void SetBuffer(Blip_Buffer *buffer)
+ {
+ _buffer = buffer;
+ }
+
+ void SetVolume(double volume)
+ {
+ _synth->volume(volume);
+ }
+
+ virtual void Run(uint32_t targetCycle)
+ {
+ while(_previousCycle < targetCycle) {
+ if(_timer == 0) {
+ Clock();
+ _timer = _period;
+ _previousCycle += _clockDivider;
+ } else {
+ uint32_t cyclesToRun = (targetCycle - _previousCycle) / _clockDivider;
+ uint16_t skipCount = _timer > cyclesToRun ? cyclesToRun : _timer;
+ _timer -= skipCount;
+ _previousCycle += skipCount * _clockDivider;
+
+ if(cyclesToRun == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ uint8_t ReadRAM(uint16_t addr)
+ {
+ return 0;
+ }
+
+ void AddOutput(uint16_t output)
+ {
+ if(output != _lastOutput) {
+ _synth->offset_inline(_previousCycle, output - _lastOutput, _buffer);
+ }
+ _lastOutput = output;
+ }
+
+ void EndFrame()
+ {
+ _previousCycle = 0;
+ }
+};
\ No newline at end of file
diff --git a/Core/CPU.h b/Core/CPU.h
index 175d449b..8d9f8864 100644
--- a/Core/CPU.h
+++ b/Core/CPU.h
@@ -667,6 +667,7 @@ public:
static void SetNMIFlag() { CPU::Instance->_state.NMIFlag = true; }
static void ClearNMIFlag() { CPU::Instance->_state.NMIFlag = false; }
static void SetIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag |= (int)source; }
+ static bool HasIRQSource(IRQSource source) { return (CPU::Instance->_state.IRQFlag & (int)source) != 0; }
static void ClearIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag &= ~(int)source; }
static void RunDMATransfer(uint8_t* spriteRAM, uint32_t &spriteRamAddr, uint8_t offsetValue);
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index cba5d5c3..567751cf 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -266,7 +266,12 @@
+
+
+
+
+
@@ -293,6 +298,8 @@
+
+
@@ -309,23 +316,13 @@
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 700891ee..1fa2998a 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -9,9 +9,6 @@
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;hm;inl;inc;xsd
-
- {c6dc2048-98f6-4551-89dc-830f12f1bb2e}
-
{ca661408-b52a-4378-aef4-80fda1d64cd6}
@@ -30,6 +27,12 @@
{ff3c6e48-3987-41d2-8916-b588a457ff30}
+
+ {d9dec4ba-97e7-4a80-85e1-6b53f5ed7218}
+
+
+ {b99fc308-b28a-48b7-9ca8-6e8005bbc2bf}
+
@@ -53,42 +56,6 @@
Header Files
-
- Header Files
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
-
- Header Files\Nes_Apu
-
Header Files\Interfaces
@@ -224,6 +191,33 @@
Header Files
+
+ Header Files\APU
+
+
+ Header Files\APU
+
+
+ Header Files\APU
+
+
+ Header Files\APU
+
+
+ Header Files\APU
+
+
+ Header Files\APU
+
+
+ Header Files\APU
+
+
+ Header Files\APU
+
+
+ Header Files\APU
+
@@ -244,9 +238,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -295,5 +286,8 @@
Source Files
+
+ Source Files\APU
+
\ No newline at end of file
diff --git a/Core/DeltaModulationChannel.h b/Core/DeltaModulationChannel.h
new file mode 100644
index 00000000..ab1b1005
--- /dev/null
+++ b/Core/DeltaModulationChannel.h
@@ -0,0 +1,154 @@
+#pragma once
+#include "stdafx.h"
+#include "../BlipBuffer/Blip_Buffer.h"
+#include "APU.h"
+#include "IMemoryHandler.h"
+#include "ApuEnvelope.h"
+
+class DeltaModulationChannel : public BaseApuChannel<127>
+{
+private:
+ const vector _dmcPeriodLookupTable = { { 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54 } };
+
+ MemoryManager *_memoryManager = nullptr;
+
+ uint16_t _sampleAddr = 0;
+ uint16_t _sampleLength = 0;
+ uint8_t _outputLevel = 0;
+ bool _irqEnabled = false;
+ bool _loopFlag = false;
+
+ uint16_t _currentAddr = 0;
+ uint16_t _bytesRemaining = 0;
+ uint8_t _readBuffer = 0;
+ bool _bufferEmpty = true;
+
+ uint8_t _shiftRegister = 0;
+ uint8_t _bitsRemaining = 0;
+ bool _silenceFlag = true;
+
+public:
+ DeltaModulationChannel(MemoryManager* memoryManager)
+ {
+ _memoryManager = memoryManager;
+ _clockDivider = 1;
+ SetVolume(0.42545);
+ }
+
+ bool IrqPending(uint32_t cyclesToRun)
+ {
+ if(_irqEnabled && _bytesRemaining > 0) {
+ uint32_t cyclesToEmptyBuffer = (_bitsRemaining + (_bytesRemaining-1)* 8) * _period;
+ if(cyclesToRun >= cyclesToEmptyBuffer) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool GetStatus()
+ {
+ return _bytesRemaining > 0;
+ }
+
+ void GetMemoryRanges(MemoryRanges &ranges)
+ {
+ ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4010, 0x4013);
+ }
+
+ void WriteRAM(uint16_t addr, uint8_t value)
+ {
+ APU::StaticRun();
+ switch(addr & 0x03) {
+ case 0: //4010
+ _irqEnabled = (value & 0x80) == 0x80;
+ _loopFlag = (value & 0x40) == 0x40;
+ _period = _dmcPeriodLookupTable[value & 0x0F];
+
+ if(!_irqEnabled) {
+ CPU::ClearIRQSource(IRQSource::DMC);
+ }
+ break;
+
+ case 1: //4011
+ _outputLevel = value & 0x7F;
+ _shiftRegister = value & 0x7F;
+ break;
+
+ case 2: //4012
+ _sampleAddr = 0xC000 | ((uint32_t)value << 6);
+ break;
+
+ case 3: //4013
+ _sampleLength = (value << 4) | 0x0001;
+ break;
+ }
+ }
+
+ void SetEnabled(bool enabled)
+ {
+ if(!enabled) {
+ _bytesRemaining = 0;
+ } else if(_bytesRemaining == 0) {
+ InitSample();
+ FillReadBuffer();
+ }
+ }
+
+ void InitSample()
+ {
+ _currentAddr = _sampleAddr;
+ _bytesRemaining = _sampleLength;
+ }
+
+ void FillReadBuffer()
+ {
+ if(_bufferEmpty && _bytesRemaining > 0) {
+ _readBuffer = _memoryManager->Read(_currentAddr);
+ _bufferEmpty = false;
+
+ _currentAddr++;
+ _bytesRemaining--;
+
+ if(_bytesRemaining == 0) {
+ if(_loopFlag) {
+ //Looped sample should never set IRQ flag
+ InitSample();
+ } else if(_irqEnabled) {
+ CPU::SetIRQSource(IRQSource::DMC);
+ }
+ }
+ }
+ }
+
+ void Clock()
+ {
+ if(!_silenceFlag) {
+ if(_shiftRegister & 0x01) {
+ if(_outputLevel <= 125) {
+ _outputLevel += 2;
+ }
+ } else {
+ if(_outputLevel >= 2) {
+ _outputLevel -= 2;
+ }
+ }
+ _shiftRegister >>= 1;
+ }
+
+ _bitsRemaining--;
+ if(_bitsRemaining == 0) {
+ _bitsRemaining = 8;
+ if(_bufferEmpty) {
+ _silenceFlag = true;
+ } else {
+ _silenceFlag = false;
+ _shiftRegister = _readBuffer;
+ _bufferEmpty = true;
+ FillReadBuffer();
+ }
+ }
+
+ AddOutput(_outputLevel);
+ }
+};
\ No newline at end of file
diff --git a/Core/Nes_Apu/Blip_Buffer.h b/Core/Nes_Apu/Blip_Buffer.h
deleted file mode 100644
index 19822682..00000000
--- a/Core/Nes_Apu/Blip_Buffer.h
+++ /dev/null
@@ -1,253 +0,0 @@
-
-// Buffer of sound samples into which band-limited waveforms can be synthesized
-// using Blip_Wave or Blip_Synth.
-
-// Blip_Buffer 0.3.3. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef BLIP_BUFFER_H
-#define BLIP_BUFFER_H
-
-#include "blargg_common.h"
-
-class Blip_Reader;
-
-// 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;
-
-class Blip_Buffer {
-public:
- // Construct an empty buffer.
- Blip_Buffer();
- ~Blip_Buffer();
-
- // 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 sample_rate( long samples_per_sec, int msec_length = blip_default_length );
- // to do: rename to set_sample_rate
-
- // 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
- 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 );
-
- // to do:
- // Notify Blip_Buffer that synthesis has been performed until specified time
- //void run_until( blip_time_t );
-
- // 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;
-
-
- // Experimental external buffer mixing support
-
- // 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( const blip_sample_t* buf, long count );
-
-
- // not documented yet
-
- void remove_silence( long count );
-
- typedef unsigned long resampled_time_t;
-
- resampled_time_t resampled_time( blip_time_t t ) const {
- return t * resampled_time_t (factor_) + offset_;
- }
-
- resampled_time_t resampled_duration( int t ) const {
- return t * resampled_time_t (factor_);
- }
-
-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 { widest_impulse_ = 24 };
- typedef BOOST::uint16_t buf_t_;
-
- unsigned long factor_;
- 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
- enum { sample_offset = 0x7F7F }; // repeated byte allows memset to clear buffer
-
- 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 );
-private:
- double treble;
- long cutoff;
- long sample_rate;
- friend class Blip_Impulse_;
-};
-
-// 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;
- }
-};
-
-
-
-// End of public interface
-
-#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_ -= 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;
-}
-
-// MSVC6 fix
-typedef Blip_Buffer::resampled_time_t blip_resampled_time_t;
-
-#include "Blip_Synth.h"
-
-#endif
-
diff --git a/Core/Nes_Apu/Blip_Synth.h b/Core/Nes_Apu/Blip_Synth.h
deleted file mode 100644
index b1665742..00000000
--- a/Core/Nes_Apu/Blip_Synth.h
+++ /dev/null
@@ -1,203 +0,0 @@
-
-// Blip_Synth and Blip_Wave are waveform transition synthesizers for adding
-// waveforms to a Blip_Buffer.
-
-// Blip_Buffer 0.3.3. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef BLIP_SYNTH_H
-#define BLIP_SYNTH_H
-
-#ifndef BLIP_BUFFER_H
- #include "Blip_Buffer.h"
-#endif
-
-// Quality level. Higher levels are slower, and worse in a few cases.
-// Use blip_good_quality as a starting point.
-const int blip_low_quality = 1;
-const int blip_med_quality = 2;
-const int blip_good_quality = 3;
-const int blip_high_quality = 4;
-
-// Blip_Synth is a transition waveform synthesizer which adds band-limited
-// offsets (transitions) into a Blip_Buffer. For a simpler interface, use
-// Blip_Wave (below).
-//
-// Range specifies the greatest expected offset that will occur. For a
-// waveform that goes between +amp and -amp, range should be amp * 2 (half
-// that if it only goes between +amp and 0). When range is large, a higher
-// accuracy scheme is used; to force this even when range is small, pass
-// the negative of range (i.e. -range).
-template
-class Blip_Synth {
- BOOST_STATIC_ASSERT( 1 <= quality && quality <= 5 );
- BOOST_STATIC_ASSERT( -32768 <= range && range <= 32767 );
- enum {
- abs_range = (range < 0) ? -range : range,
- fine_mode = (range > 512 || range < 0),
- width = (quality < 5 ? quality * 4 : Blip_Buffer::widest_impulse_),
- res = 1 << blip_res_bits_,
- impulse_size = width / 2 * (fine_mode + 1),
- base_impulses_size = width / 2 * (res / 2 + 1),
- fine_bits = (fine_mode ? (abs_range <= 64 ? 2 : abs_range <= 128 ? 3 :
- abs_range <= 256 ? 4 : abs_range <= 512 ? 5 : abs_range <= 1024 ? 6 :
- abs_range <= 2048 ? 7 : 8) : 0)
- };
- blip_pair_t_ impulses [impulse_size * res * 2 + base_impulses_size];
- Blip_Impulse_ impulse;
-public:
- Blip_Synth() { impulse.init( impulses, width, res, fine_bits ); }
-
- // Configure low-pass filter (see notes.txt). Not optimized for real-time control
- void treble_eq( const blip_eq_t& eq ) { impulse.treble_eq( eq ); }
-
- // Set volume of a transition at amplitude 'range' by setting volume_unit
- // to v / range
- void volume( double v ) { impulse.volume_unit( v * (1.0 / abs_range) ); }
-
- // Set base volume unit of transitions, where 1.0 is a full swing between the
- // positive and negative extremes. Not optimized for real-time control.
- void volume_unit( double unit ) { impulse.volume_unit( unit ); }
-
- // Default Blip_Buffer used for output when none is specified for a given call
- Blip_Buffer* output() const { return impulse.buf; }
- void output( Blip_Buffer* b ) { impulse.buf = b; }
-
- // Add an amplitude offset (transition) with 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
-class Blip_Wave {
- Blip_Synth synth;
- blip_time_t time_;
- int last_amp;
-public:
- // Start wave at time 0 and amplitude 0
- Blip_Wave() : time_( 0 ), last_amp( 0 ) { }
-
- // See Blip_Synth for description
- void volume( double v ) { synth.volume( v ); }
- void volume_unit( double v ) { synth.volume_unit( v ); }
- void treble_eq( const blip_eq_t& eq){ synth.treble_eq( eq ); }
- Blip_Buffer* output() const { return synth.output(); }
- void output( Blip_Buffer* b ) { synth.output( b ); if ( !b ) time_ = last_amp = 0; }
-
- // Current time in frame
- blip_time_t time() const { return time_; }
- void time( blip_time_t t ) { time_ = t; }
-
- // Current amplitude of wave
- int amplitude() const { return last_amp; }
- void amplitude( int );
-
- // Move forward by 't' time units
- void delay( blip_time_t t ) { time_ += t; }
-
- // End time frame of specified duration. Localize time to new frame.
- void end_frame( blip_time_t duration ) {
- assert(( "Blip_Wave::end_frame(): Wave hadn't yet been run for entire frame",
- duration <= time_ ));
- time_ -= duration;
- }
-};
-
-
-// End of public interface
-
-template
-void Blip_Wave::amplitude( int amp ) {
- int delta = amp - last_amp;
- last_amp = amp;
- synth.offset_inline( time_, delta );
-}
-
-template
-inline void Blip_Synth::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
-void Blip_Synth::offset( blip_time_t time, int delta, Blip_Buffer* buf ) const {
- offset_resampled( time * buf->factor_ + buf->offset_, delta, buf );
-}
-
-#endif
-
diff --git a/Core/Nes_Apu/Multi_Buffer.h b/Core/Nes_Apu/Multi_Buffer.h
deleted file mode 100644
index f7dd3237..00000000
--- a/Core/Nes_Apu/Multi_Buffer.h
+++ /dev/null
@@ -1,157 +0,0 @@
-
-// Multi-channel sound buffer interface, and basic mono and stereo buffers
-
-// Blip_Buffer 0.3.3. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef MULTI_BUFFER_H
-#define MULTI_BUFFER_H
-
-#include "Blip_Buffer.h"
-
-// Multi_Buffer is an interface to one or more Blip_Buffers mapped to one or
-// more channels consisting of left, center, and right buffers.
-class Multi_Buffer {
-public:
- Multi_Buffer( int samples_per_frame );
- virtual ~Multi_Buffer() { }
-
- // Set the number of channels available
- virtual blargg_err_t set_channel_count( int );
-
- // Get indexed channel, from 0 to channel count - 1
- struct channel_t {
- Blip_Buffer* center;
- Blip_Buffer* left;
- Blip_Buffer* right;
- };
- virtual channel_t channel( int index ) = 0;
-
- // See Blip_Buffer.h
- // to do: rename to set_sample_rate
- virtual blargg_err_t sample_rate( long rate, int msec = blip_default_length ) = 0;
- virtual void clock_rate( long ) = 0;
- virtual void bass_freq( int ) = 0;
- virtual void clear() = 0;
- long sample_rate() const;
-
- // Length of buffer, in milliseconds
- int length() const;
-
- // See Blip_Buffer.h. For optimal operation, pass false for 'added_stereo'
- // if nothing was added to the left and right buffers of any channel for
- // this time frame.
- virtual void end_frame( blip_time_t, bool added_stereo = true ) = 0;
-
- // Number of samples per output frame (1 = mono, 2 = stereo)
- int samples_per_frame() const;
-
- // See Blip_Buffer.h
- virtual long read_samples( blip_sample_t*, long ) = 0;
- virtual long samples_avail() const = 0;
-
-private:
- // noncopyable
- Multi_Buffer( const Multi_Buffer& );
- Multi_Buffer& operator = ( const Multi_Buffer& );
-
- long sample_rate_;
- int length_;
- int const samples_per_frame_;
-};
-
-// Mono_Buffer uses a single buffer and outputs mono samples.
-class Mono_Buffer : public Multi_Buffer {
- Blip_Buffer buf;
-public:
- Mono_Buffer();
- ~Mono_Buffer();
-
- // Buffer used for all channels
- Blip_Buffer* center();
-
- // See Multi_Buffer
- blargg_err_t sample_rate( long rate, int msec = blip_default_length );
- Multi_Buffer::sample_rate;
- 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 );
-};
-
-// Stereo_Buffer 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();
- Blip_Buffer* left();
- Blip_Buffer* right();
-
- // See Multi_Buffer
- blargg_err_t sample_rate( long, int msec = blip_default_length );
- Multi_Buffer::sample_rate;
- void clock_rate( long );
- void bass_freq( int );
- void clear();
- channel_t channel( int index );
- void end_frame( blip_time_t, bool added_stereo = true );
-
- long samples_avail() const;
- long read_samples( blip_sample_t*, long );
-
-private:
- enum { buf_count = 3 };
- Blip_Buffer bufs [buf_count];
- channel_t chan;
- bool stereo_added;
- bool was_stereo;
-
- void mix_stereo( blip_sample_t*, long );
- void mix_mono( blip_sample_t*, long );
-};
-
-
-// End of public interface
-
-inline blargg_err_t Multi_Buffer::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 Blip_Buffer* Stereo_Buffer::left() { return &bufs [1]; }
-
-inline Blip_Buffer* Stereo_Buffer::center() { return &bufs [0]; }
-
-inline Blip_Buffer* Stereo_Buffer::right() { return &bufs [2]; }
-
-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 Blip_Buffer* Mono_Buffer::center() { return &buf; }
-
-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
-
diff --git a/Core/Nes_Apu/Nes_Apu.h b/Core/Nes_Apu/Nes_Apu.h
deleted file mode 100644
index 6ce4c986..00000000
--- a/Core/Nes_Apu/Nes_Apu.h
+++ /dev/null
@@ -1,162 +0,0 @@
-
-// NES 2A03 APU sound chip emulator
-
-// Nes_Snd_Emu 0.1.7. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef NES_APU_H
-#define NES_APU_H
-
-typedef long cpu_time_t; // CPU clock cycle count
-typedef unsigned cpu_addr_t; // 16-bit memory address
-
-#include "Nes_Oscs.h"
-
-struct apu_snapshot_t;
-class Nonlinear_Buffer;
-
-class Nes_Apu {
-public:
- Nes_Apu();
- ~Nes_Apu();
-
- // Set buffer to generate all sound into, or disable sound if NULL
- void output( Blip_Buffer* );
-
- // Set memory reader callback used by DMC oscillator to fetch samples.
- // When callback is invoked, 'user_data' is passed unchanged as the
- // first parameter.
- void dmc_reader( int (*callback)( void* user_data, cpu_addr_t ), void* user_data = NULL );
-
- // All time values are the number of CPU clock cycles relative to the
- // beginning of the current time frame. Before resetting the CPU clock
- // count, call end_frame( last_cpu_time ).
-
- // Write to register (0x4000-0x4017, except 0x4014 and 0x4016)
- enum { start_addr = 0x4000 };
- enum { end_addr = 0x4017 };
- void write_register( cpu_time_t, cpu_addr_t, int data );
-
- // Read from status register at 0x4015
- enum { status_addr = 0x4015 };
- int read_status( cpu_time_t );
-
- // Run all oscillators up to specified time, end current time frame, then
- // start a new time frame at time 0. Time frames have no effect on emulation
- // and each can be whatever length is convenient.
- void end_frame( cpu_time_t );
-
-// Additional optional features (can be ignored without any problem)
-
- // Reset internal frame counter, registers, and all oscillators.
- // Use PAL timing if pal_timing is true, otherwise use NTSC timing.
- // Set the DMC oscillator's initial DAC value to initial_dmc_dac without
- // any audible click.
- void reset( bool pal_timing = false, int initial_dmc_dac = 0 );
-
- // Save/load snapshot of exact emulation state
- void save_snapshot( apu_snapshot_t* out ) const;
- void load_snapshot( apu_snapshot_t const& );
-
- // Set overall volume (default is 1.0)
- void volume( double );
-
- // Reset oscillator amplitudes. Must be called when clearing buffer while
- // using non-linear sound.
- void buffer_cleared();
-
- // Set treble equalization (see notes.txt).
- void treble_eq( const blip_eq_t& );
-
- // Set sound output of specific oscillator to buffer. If buffer is NULL,
- // the specified oscillator is muted and emulation accuracy is reduced.
- // The oscillators are indexed as follows: 0) Square 1, 1) Square 2,
- // 2) Triangle, 3) Noise, 4) DMC.
- enum { osc_count = 5 };
- void osc_output( int index, Blip_Buffer* buffer );
-
- // Set IRQ time callback that is invoked when the time of earliest IRQ
- // may have changed, or NULL to disable. When callback is invoked,
- // 'user_data' is passed unchanged as the first parameter.
- void irq_notifier( void (*callback)( void* user_data ), void* user_data = NULL );
-
- // Get time that APU-generated IRQ will occur if no further register reads
- // or writes occur. If IRQ is already pending, returns irq_waiting. If no
- // IRQ will occur, returns no_irq.
- enum { no_irq = LONG_MAX / 2 + 1 };
- enum { irq_waiting = 0 };
- cpu_time_t earliest_irq() const;
-
- // Count number of DMC reads that would occur if 'run_until( t )' were executed.
- // If last_read is not NULL, set *last_read to the earliest time that
- // 'count_dmc_reads( time )' would result in the same result.
- int count_dmc_reads( cpu_time_t t, cpu_time_t* last_read = NULL ) const;
-
- // Run APU until specified time, so that any DMC memory reads can be
- // accounted for (i.e. inserting CPU wait states).
- void run_until( cpu_time_t );
-
-// End of public interface.
-private:
- friend class Nes_Nonlinearizer;
- void enable_nonlinear( double volume );
-private:
- // noncopyable
- Nes_Apu( const Nes_Apu& );
- Nes_Apu& operator = ( const Nes_Apu& );
-
- Nes_Osc* oscs [osc_count];
- Nes_Square square1;
- Nes_Square square2;
- Nes_Noise noise;
- Nes_Triangle triangle;
- Nes_Dmc dmc;
-
- cpu_time_t last_time; // has been run until this time in current frame
- cpu_time_t earliest_irq_;
- cpu_time_t next_irq;
- int frame_period;
- int frame_delay; // cycles until frame counter runs next
- int frame; // current frame (0-3)
- int osc_enables;
- int frame_mode;
- bool irq_flag;
- void (*irq_notifier_)( void* user_data );
- void* irq_data;
- Nes_Square::Synth square_synth; // shared by squares
-
- void irq_changed();
- void state_restored();
-
- friend struct Nes_Dmc;
-};
-
-inline void Nes_Apu::osc_output( int osc, Blip_Buffer* buf )
-{
- assert(( "Nes_Apu::osc_output(): Index out of range", 0 <= osc && osc < osc_count ));
- oscs [osc]->output = buf;
-}
-
-inline cpu_time_t Nes_Apu::earliest_irq() const
-{
- return earliest_irq_;
-}
-
-inline void Nes_Apu::dmc_reader( int (*func)( void*, cpu_addr_t ), void* user_data )
-{
- dmc.rom_reader_data = user_data;
- dmc.rom_reader = func;
-}
-
-inline void Nes_Apu::irq_notifier( void (*func)( void* user_data ), void* user_data )
-{
- irq_notifier_ = func;
- irq_data = user_data;
-}
-
-inline int Nes_Apu::count_dmc_reads( cpu_time_t time, cpu_time_t* last_read ) const
-{
- return dmc.count_reads( time, last_read );
-}
-
-#endif
-
diff --git a/Core/Nes_Apu/Nes_Namco.h b/Core/Nes_Apu/Nes_Namco.h
deleted file mode 100644
index 87d65858..00000000
--- a/Core/Nes_Apu/Nes_Namco.h
+++ /dev/null
@@ -1,86 +0,0 @@
-
-// Namco 106 sound chip emulator
-
-// Nes_Snd_Emu 0.1.7. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef NES_NAMCO_H
-#define NES_NAMCO_H
-
-#include "Nes_Apu.h"
-
-struct namco_snapshot_t;
-
-class Nes_Namco {
-public:
- Nes_Namco();
- ~Nes_Namco();
-
- // See Nes_Apu.h for reference.
- void volume( double );
- void treble_eq( const blip_eq_t& );
- void output( Blip_Buffer* );
- enum { osc_count = 8 };
- void osc_output( int index, Blip_Buffer* );
- void reset();
- void end_frame( cpu_time_t );
-
- // Read/write data register is at 0x4800
- enum { data_reg_addr = 0x4800 };
- void write_data( cpu_time_t, int );
- int read_data();
-
- // Write-only address register is at 0xF800
- enum { addr_reg_addr = 0xF800 };
- void write_addr( int );
-
- // to do: implement save/restore
- void save_snapshot( namco_snapshot_t* out );
- void load_snapshot( namco_snapshot_t const& );
-
-private:
- // noncopyable
- Nes_Namco( const Nes_Namco& );
- Nes_Namco& operator = ( const Nes_Namco& );
-
- struct Namco_Osc {
- long delay;
- Blip_Buffer* output;
- short last_amp;
- short wave_pos;
- };
-
- Namco_Osc oscs [osc_count];
-
- cpu_time_t last_time;
- int addr_reg;
-
- enum { reg_count = 0x80 };
- BOOST::uint8_t reg [reg_count];
- Blip_Synth synth;
-
- BOOST::uint8_t& access();
- void run_until( cpu_time_t );
-};
-
-inline void Nes_Namco::volume( double v ) { synth.volume( 0.10 / osc_count * v ); }
-
-inline void Nes_Namco::treble_eq( const blip_eq_t& eq ) { synth.treble_eq( eq ); }
-
-inline void Nes_Namco::write_addr( int v ) { addr_reg = v; }
-
-inline int Nes_Namco::read_data() { return access(); }
-
-inline void Nes_Namco::osc_output( int i, Blip_Buffer* buf )
-{
- assert( (unsigned) i < osc_count );
- oscs [i].output = buf;
-}
-
-inline void Nes_Namco::write_data( cpu_time_t time, int data )
-{
- run_until( time );
- access() = data;
-}
-
-#endif
-
diff --git a/Core/Nes_Apu/Nes_Oscs.h b/Core/Nes_Apu/Nes_Oscs.h
deleted file mode 100644
index c1893041..00000000
--- a/Core/Nes_Apu/Nes_Oscs.h
+++ /dev/null
@@ -1,142 +0,0 @@
-
-// Private oscillators used by Nes_Apu
-
-// Nes_Snd_Emu 0.1.7. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef NES_OSCS_H
-#define NES_OSCS_H
-
-#include "Blip_Buffer.h"
-
-class Nes_Apu;
-
-struct Nes_Osc
-{
- unsigned char regs [4];
- bool reg_written [4];
- Blip_Buffer* output;
- int length_counter;// length counter (0 if unused by oscillator)
- int delay; // delay until next (potential) transition
- int last_amp; // last amplitude oscillator was outputting
-
- void clock_length( int halt_mask );
- int period() const {
- return (regs [3] & 7) * 0x100 + (regs [2] & 0xff);
- }
- void reset() {
- delay = 0;
- last_amp = 0;
- }
- int update_amp( int amp ) {
- int delta = amp - last_amp;
- last_amp = amp;
- return delta;
- }
-};
-
-struct Nes_Envelope : Nes_Osc
-{
- int envelope;
- int env_delay;
-
- void clock_envelope();
- int volume() const;
- void reset() {
- envelope = 0;
- env_delay = 0;
- Nes_Osc::reset();
- }
-};
-
-// Nes_Square
-struct Nes_Square : Nes_Envelope
-{
- enum { negate_flag = 0x08 };
- enum { shift_mask = 0x07 };
- enum { phase_range = 8 };
- int phase;
- int sweep_delay;
-
- typedef Blip_Synth Synth;
- const Synth* synth; // shared between squares
-
- void clock_sweep( int adjust );
- void run( cpu_time_t, cpu_time_t );
- void reset() {
- sweep_delay = 0;
- Nes_Envelope::reset();
- }
-};
-
-// Nes_Triangle
-struct Nes_Triangle : Nes_Osc
-{
- enum { phase_range = 16 };
- int phase;
- int linear_counter;
- Blip_Synth synth;
-
- int calc_amp() const;
- void run( cpu_time_t, cpu_time_t );
- void clock_linear_counter();
- void reset() {
- linear_counter = 0;
- phase = phase_range;
- Nes_Osc::reset();
- }
-};
-
-// Nes_Noise
-struct Nes_Noise : Nes_Envelope
-{
- int noise;
- Blip_Synth synth;
-
- void run( cpu_time_t, cpu_time_t );
- void reset() {
- noise = 1 << 14;
- Nes_Envelope::reset();
- }
-};
-
-// Nes_Dmc
-struct Nes_Dmc : Nes_Osc
-{
- int address; // address of next byte to read
- int period;
- //int length_counter; // bytes remaining to play (already defined in Nes_Osc)
- int buf;
- int bits_remain;
- int bits;
- bool buf_empty;
- bool silence;
-
- enum { loop_flag = 0x40 };
-
- int dac;
-
- cpu_time_t next_irq;
- bool irq_enabled;
- bool irq_flag;
- bool pal_mode;
- bool nonlinear;
-
- int (*rom_reader)( void*, cpu_addr_t ); // needs to be initialized to rom read function
- void* rom_reader_data;
-
- Nes_Apu* apu;
-
- Blip_Synth synth;
-
- void start();
- void write_register( int, int );
- void run( cpu_time_t, cpu_time_t );
- void recalc_irq();
- void fill_buffer();
- void reload_sample();
- void reset();
- int count_reads( cpu_time_t, cpu_time_t* ) const;
-};
-
-#endif
-
diff --git a/Core/Nes_Apu/Nes_Vrc6.h b/Core/Nes_Apu/Nes_Vrc6.h
deleted file mode 100644
index 038cd587..00000000
--- a/Core/Nes_Apu/Nes_Vrc6.h
+++ /dev/null
@@ -1,85 +0,0 @@
-
-// Konami VRC6 sound chip emulator
-
-// Nes_Snd_Emu 0.1.7. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef NES_VRC6_H
-#define NES_VRC6_H
-
-#include "Nes_Apu.h"
-
-struct vrc6_snapshot_t;
-
-class Nes_Vrc6 {
-public:
- Nes_Vrc6();
- ~Nes_Vrc6();
-
- // See Nes_Apu.h for reference
- void reset();
- void volume( double );
- void treble_eq( blip_eq_t const& );
- void output( Blip_Buffer* );
- enum { osc_count = 3 };
- void osc_output( int index, Blip_Buffer* );
- void end_frame( cpu_time_t );
- void save_snapshot( vrc6_snapshot_t* ) const;
- void load_snapshot( vrc6_snapshot_t const& );
-
- // Oscillator 0 write-only registers are at $9000-$9002
- // Oscillator 1 write-only registers are at $A000-$A002
- // Oscillator 2 write-only registers are at $B000-$B002
- enum { reg_count = 3 };
- enum { base_addr = 0x9000 };
- enum { addr_step = 0x1000 };
- void write_osc( cpu_time_t, int osc, int reg, int data );
-
-private:
- // noncopyable
- Nes_Vrc6( const Nes_Vrc6& );
- Nes_Vrc6& operator = ( const Nes_Vrc6& );
-
- struct Vrc6_Osc
- {
- BOOST::uint8_t regs [3];
- Blip_Buffer* output;
- int delay;
- int last_amp;
- int phase;
- int amp; // only used by saw
-
- int period() const
- {
- return (regs [2] & 0x0f) * 0x100L + regs [1] + 1;
- }
- };
-
- Vrc6_Osc oscs [osc_count];
- cpu_time_t last_time;
-
- Blip_Synth saw_synth;
- Blip_Synth square_synth;
-
- void run_until( cpu_time_t );
- void run_square( Vrc6_Osc& osc, cpu_time_t );
- void run_saw( cpu_time_t );
-};
-
-struct vrc6_snapshot_t
-{
- BOOST::uint8_t regs [3] [3];
- BOOST::uint8_t saw_amp;
- BOOST::uint16_t delays [3];
- BOOST::uint8_t phases [3];
- BOOST::uint8_t unused;
-};
-BOOST_STATIC_ASSERT( sizeof (vrc6_snapshot_t) == 20 );
-
-inline void Nes_Vrc6::osc_output( int i, Blip_Buffer* buf )
-{
- assert( (unsigned) i < osc_count );
- oscs [i].output = buf;
-}
-
-#endif
-
diff --git a/Core/Nes_Apu/Nonlinear_Buffer.h b/Core/Nes_Apu/Nonlinear_Buffer.h
deleted file mode 100644
index 8856b544..00000000
--- a/Core/Nes_Apu/Nonlinear_Buffer.h
+++ /dev/null
@@ -1,65 +0,0 @@
-
-// NES non-linear audio output handling.
-
-// Nes_Snd_Emu 0.1.7. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef NONLINEAR_BUFFER_H
-#define NONLINEAR_BUFFER_H
-
-#include "Multi_Buffer.h"
-class Nes_Apu;
-
-// Use to make samples non-linear in Blip_Buffer used for triangle, noise, and DMC only
-class Nes_Nonlinearizer {
-public:
- Nes_Nonlinearizer();
-
- // Must be called when buffer is cleared
- void clear() { accum = 0x8000; }
-
- // Enable/disable non-linear output
- void enable( Nes_Apu&, bool = true );
-
- // Make at most 'count' samples in buffer non-linear and return number
- // of samples modified. This many samples must then be read out of the buffer.
- long make_nonlinear( Blip_Buffer&, long count );
-
-private:
- enum { shift = 5 };
- enum { half = 0x8000 >> shift };
- enum { entry_mask = half * 2 - 1 };
- BOOST::uint16_t table [half * 2];
- long accum;
- bool nonlinear;
-};
-
-class Nonlinear_Buffer : public Multi_Buffer {
-public:
- Nonlinear_Buffer();
- ~Nonlinear_Buffer();
-
- // Enable/disable non-linear output
- void enable_nonlinearity( Nes_Apu&, bool = true );
-
- // Blip_Buffer to output other sound chips to
- Blip_Buffer* buffer() { return &buf; }
-
- // See Multi_Buffer.h
- blargg_err_t sample_rate( long rate, int msec = blip_default_length );
- Multi_Buffer::sample_rate;
- 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 );
-
-private:
- Blip_Buffer buf;
- Blip_Buffer tnd;
- Nes_Nonlinearizer nonlinearizer;
-};
-
-#endif
-
diff --git a/Core/Nes_Apu/apu_snapshot.h b/Core/Nes_Apu/apu_snapshot.h
deleted file mode 100644
index 5b894cc1..00000000
--- a/Core/Nes_Apu/apu_snapshot.h
+++ /dev/null
@@ -1,75 +0,0 @@
-
-// NES APU snapshot support
-
-// Nes_Snd_Emu 0.1.7. Copyright (C) 2003-2005 Shay Green. GNU LGPL license.
-
-#ifndef APU_SNAPSHOT_H
-#define APU_SNAPSHOT_H
-
-#include "blargg_common.h"
-
-struct apu_snapshot_t
-{
- typedef BOOST::uint8_t byte;
-
- typedef byte env_t [3];
- /*struct env_t {
- byte delay;
- byte env;3
- byte written;
- };*/
-
- byte w40xx [0x14]; // $4000-$4013
- byte w4015; // enables
- byte w4017; // mode
- BOOST::uint16_t delay;
- byte step;
- byte irq_flag;
-
- struct square_t {
- BOOST::uint16_t delay;
- env_t env;
- byte length;
- byte phase;
- byte swp_delay;
- byte swp_reset;
- byte unused [1];
- };
-
- square_t square1;
- square_t square2;
-
- struct triangle_t {
- BOOST::uint16_t delay;
- byte length;
- byte phase;
- byte linear_counter;
- byte linear_mode;
- } triangle;
-
- struct noise_t {
- BOOST::uint16_t delay;
- env_t env;
- byte length;
- BOOST::uint16_t shift_reg;
- } noise;
-
- struct dmc_t {
- BOOST::uint16_t delay;
- BOOST::uint16_t remain;
- BOOST::uint16_t addr;
- byte buf;
- byte bits_remain;
- byte bits;
- byte buf_empty;
- byte silence;
- byte irq_flag;
- } dmc;
-
- enum { tag = 'APUR' };
- void swap();
-};
-BOOST_STATIC_ASSERT( sizeof (apu_snapshot_t) == 72 );
-
-#endif
-
diff --git a/Core/Nes_Apu/blargg_common.h b/Core/Nes_Apu/blargg_common.h
deleted file mode 100644
index 941c192b..00000000
--- a/Core/Nes_Apu/blargg_common.h
+++ /dev/null
@@ -1,181 +0,0 @@
-
-// 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.
-
-#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
-#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)
- #define BLARGG_COMPILER_HAS_NAMESPACE 1
- // 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 BLARGG_NEW new
- #define STATIC_CAST( type ) (type)
-
-#endif
-
-// STATIC_CAST(T) (expr) -> static_cast< T > (expr)
-#ifndef STATIC_CAST
- #define STATIC_CAST( type ) static_cast< type >
-#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
- #endif
- #ifndef BLARGG_COMPILER_HAS_BOOL
- #define BLARGG_COMPILER_HAS_BOOL 1
- #endif
-#endif
-
-// Bool support
-#ifndef BLARGG_COMPILER_HAS_BOOL
- #define BLARGG_COMPILER_HAS_BOOL 1
-#elif !BLARGG_COMPILER_HAS_BOOL
- typedef int bool;
- const bool true = 1;
- const bool false = 0;
-#endif
-
-// Set up namespace support
-
-#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 }
-#else
- #define BLARGG_BEGIN_NAMESPACE( name )
- #define BLARGG_END_NAMESPACE
-#endif
-
-#if BLARGG_USE_NAMESPACE
- #define STD std
-#else
- #define STD
-#endif
-
-// BOOST::uint8_t, BOOST::int16_t, etc.
-#include "boost/cstdint.hpp"
-
-// BOOST_STATIC_ASSERT( expr )
-#include "boost/static_assert.hpp"
-
-// Common standard headers
-#if BLARGG_COMPILER_HAS_NAMESPACE
- #include
- #include
- #include
-#else
- #include
- #include
-#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,
-// nothrow new is used.
-#ifndef BLARGG_NEW
- #define BLARGG_NEW new (STD::nothrow)
-#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
-#endif
-
-#endif
-
diff --git a/Core/Nes_Apu/blargg_source.h b/Core/Nes_Apu/blargg_source.h
deleted file mode 100644
index f74f311a..00000000
--- a/Core/Nes_Apu/blargg_source.h
+++ /dev/null
@@ -1,43 +0,0 @@
-
-// By default, #included at beginning of library source files
-
-// Copyright (C) 2005 Shay Green.
-
-#ifndef BLARGG_SOURCE_H
-#define BLARGG_SOURCE_H
-
-// If debugging is enabled, abort program if expr is false. Meant for checking
-// internal state and consistency. A failed assertion indicates a bug in the module.
-// void assert( bool expr );
-#include
-
-// If debugging is enabled and expr is false, abort program. Meant for checking
-// caller-supplied parameters and operations that are outside the control of the
-// module. A failed requirement indicates a bug outside the module.
-// void require( bool expr );
-#undef require
-#define require( expr ) assert(( "unmet requirement", 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)
-
-// If enabled, evaluate expr and if false, make debug log entry with source file
-// and line. Meant for finding situations that should be examined further, but that
-// don't indicate a problem. In all cases, execution continues normally.
-#undef check
-#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 { \
- 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 )
-
-#endif
-
diff --git a/Core/Nes_Apu/boost/config.hpp b/Core/Nes_Apu/boost/config.hpp
deleted file mode 100644
index f271715c..00000000
--- a/Core/Nes_Apu/boost/config.hpp
+++ /dev/null
@@ -1,13 +0,0 @@
-
-// Boost substitute. For full boost library see http://boost.org
-
-#ifndef BOOST_CONFIG_HPP
-#define BOOST_CONFIG_HPP
-
-#define BOOST_MINIMAL 1
-
-#define BLARGG_BEGIN_NAMESPACE( name )
-#define BLARGG_END_NAMESPACE
-
-#endif
-
diff --git a/Core/Nes_Apu/boost/cstdint.hpp b/Core/Nes_Apu/boost/cstdint.hpp
deleted file mode 100644
index e446dfdd..00000000
--- a/Core/Nes_Apu/boost/cstdint.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-
-// Boost substitute. For full boost library see http://boost.org
-
-#ifndef BOOST_CSTDINT_HPP
-#define BOOST_CSTDINT_HPP
-
-#if BLARGG_USE_NAMESPACE
- #include
-#else
- #include
-#endif
-
-BLARGG_BEGIN_NAMESPACE( boost )
-
-#if UCHAR_MAX != 0xFF || SCHAR_MAX != 0x7F
-# error "No suitable 8-bit type available"
-#endif
-
-typedef unsigned char uint8_t;
-typedef signed char int8_t;
-
-#if USHRT_MAX != 0xFFFF
-# error "No suitable 16-bit type available"
-#endif
-
-typedef short int16_t;
-typedef unsigned short uint16_t;
-
-#if ULONG_MAX == 0xFFFFFFFF
- typedef long int32_t;
- typedef unsigned long uint32_t;
-#elif UINT_MAX == 0xFFFFFFFF
- typedef int int32_t;
- typedef unsigned int uint32_t;
-#else
-# error "No suitable 32-bit type available"
-#endif
-
-BLARGG_END_NAMESPACE
-
-#endif
-
diff --git a/Core/Nes_Apu/boost/static_assert.hpp b/Core/Nes_Apu/boost/static_assert.hpp
deleted file mode 100644
index 66927ccb..00000000
--- a/Core/Nes_Apu/boost/static_assert.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-
-// Boost substitute. For full boost library see http://boost.org
-
-#ifndef BOOST_STATIC_ASSERT_HPP
-#define BOOST_STATIC_ASSERT_HPP
-
-#if defined (_MSC_VER) && _MSC_VER <= 1200
- // MSVC6 can't handle the ##line concatenation
- #define BOOST_STATIC_ASSERT( expr ) struct { int n [1 / ((expr) ? 1 : 0)]; }
-
-#else
- #define BOOST_STATIC_ASSERT3( expr, line ) \
- typedef int boost_static_assert_##line [1 / ((expr) ? 1 : 0)]
-
- #define BOOST_STATIC_ASSERT2( expr, line ) BOOST_STATIC_ASSERT3( expr, line )
-
- #define BOOST_STATIC_ASSERT( expr ) BOOST_STATIC_ASSERT2( expr, __LINE__ )
-
-#endif
-
-#endif
-
diff --git a/Core/NoiseChannel.h b/Core/NoiseChannel.h
new file mode 100644
index 00000000..7dee885f
--- /dev/null
+++ b/Core/NoiseChannel.h
@@ -0,0 +1,70 @@
+#pragma once
+#include "stdafx.h"
+#include "../BlipBuffer/Blip_Buffer.h"
+#include "APU.h"
+#include "IMemoryHandler.h"
+#include "ApuEnvelope.h"
+
+class NoiseChannel : public ApuEnvelope
+{
+private:
+ const vector _noisePeriodLookupTable = { { 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068 } };
+
+ //On power-up, the shift register is loaded with the value 1.
+ uint16_t _shiftRegister = 1;
+ bool _modeFlag = false;
+
+ bool IsMuted()
+ {
+ //The mixer receives the current envelope volume except when Bit 0 of the shift register is set, or The length counter is zero
+ return (_shiftRegister & 0x01) == 0x01;
+ }
+
+public:
+ NoiseChannel()
+ {
+ SetVolume(0.0741);
+ }
+
+ void GetMemoryRanges(MemoryRanges &ranges)
+ {
+ ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x400C, 0x400F);
+ }
+
+ void WriteRAM(uint16_t addr, uint8_t value)
+ {
+ APU::StaticRun();
+ switch(addr & 0x03) {
+ case 0: //400C
+ InitializeLengthCounter((value & 0x20) == 0x20);
+ InitializeEnvelope(value);
+ break;
+
+ case 2: //400E
+ _period = _noisePeriodLookupTable[value & 0x0F];
+ break;
+
+ case 3: //400F
+ LoadLengthCounter(value >> 3);
+
+ //The envelope is also restarted.
+ ResetEnvelope();
+ break;
+ }
+ }
+
+ void Clock()
+ {
+ uint32_t volume = GetVolume();
+ //Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1.
+ uint16_t feedback = (_shiftRegister & 0x01) ^ ((_shiftRegister >> (_modeFlag ? 6 : 1)) & 0x01);
+ _shiftRegister >>= 1;
+ _shiftRegister |= (feedback << 14);
+
+ if(IsMuted()) {
+ AddOutput(0);
+ } else {
+ AddOutput(GetVolume());
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/SquareChannel.h b/Core/SquareChannel.h
new file mode 100644
index 00000000..8b730b7c
--- /dev/null
+++ b/Core/SquareChannel.h
@@ -0,0 +1,154 @@
+#pragma once
+#include "stdafx.h"
+#include "../BlipBuffer/Blip_Buffer.h"
+#include "APU.h"
+#include "IMemoryHandler.h"
+#include "ApuEnvelope.h"
+
+class SquareChannel : public ApuEnvelope
+{
+private:
+ const vector> _dutySequences = { {
+ { 0, 1, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 1, 1, 1, 0, 0, 0 },
+ { 1, 0, 0, 1, 1, 1, 1, 1 }
+ } };
+
+ bool _isChannel1 = false;
+
+ uint8_t _duty = 0;
+ uint8_t _dutyPos = 0;
+
+ bool _sweepEnabled = false;
+ uint8_t _sweepPeriod = 0;
+ bool _sweepNegate = false;
+ uint8_t _sweepShift = 0;
+ bool _reloadSweep = false;
+ uint8_t _sweepDivider = 0;
+ uint32_t _sweepTargetPeriod = 0;
+
+ bool IsMuted()
+ {
+ //A period of t < 8, either set explicitly or via a sweep period update, silences the corresponding pulse channel.
+ return _period < 8 || _sweepTargetPeriod > 0x7FF;
+ }
+
+public:
+ SquareChannel(bool isChannel1)
+ {
+ SetVolume(0.1128);
+ _isChannel1 = isChannel1;
+ }
+
+ void GetMemoryRanges(MemoryRanges &ranges)
+ {
+ if(_isChannel1) {
+ ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4000, 0x4003);
+ } else {
+ ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4004, 0x4007);
+ }
+ }
+
+ void WriteRAM(uint16_t addr, uint8_t value)
+ {
+ APU::StaticRun();
+ switch(addr & 0x03) {
+ case 0: //4000 & 4004
+ InitializeLengthCounter((value & 0x20) == 0x20);
+ InitializeEnvelope(value);
+
+ _duty = (value & 0xC0) >> 6;
+ break;
+
+ case 1: //4001 & 4005
+ InitializeSweep(value);
+ break;
+
+ case 2: //4002 & 4006
+ _period &= ~0x00FF;
+ _period |= value;
+ break;
+
+ case 3: //4003 & 4007
+ LoadLengthCounter(value >> 3);
+
+ _period &= ~0x0700;
+ _period |= (value & 0x07) << 8;
+
+ //The sequencer is restarted at the first value of the current sequence.
+ _timer = _period + 1;
+ _dutyPos = 0;
+
+ //The envelope is also restarted.
+ ResetEnvelope();
+ break;
+ }
+ }
+
+ void InitializeSweep(uint8_t regValue)
+ {
+ _sweepEnabled = (regValue & 0x80) == 0x80;
+ _sweepNegate = (regValue & 0x08) == 0x08;
+
+ //The divider's period is set to P + 1
+ _sweepPeriod = ((regValue & 0x70) >> 4) + 1;
+ _sweepShift = (regValue & 0x07);
+
+ //Side effects: Sets the reload flag
+ _reloadSweep = true;
+ }
+
+ void UpdateTargetPeriod(bool setPeriod)
+ {
+ uint16_t shiftResult = (_period >> _sweepShift);
+ if(_sweepNegate) {
+ _sweepTargetPeriod = _period - shiftResult;
+ if(_isChannel1) {
+ // As a result, a negative sweep on pulse channel 1 will subtract the shifted period value minus 1
+ _sweepTargetPeriod++;
+ }
+ } else {
+ _sweepTargetPeriod = _period + shiftResult;
+ }
+ if(setPeriod && _sweepShift > 0 && _period >= 8 && _sweepTargetPeriod <= 0x7FF) {
+ _period = _sweepTargetPeriod;
+ }
+ }
+
+ void TickSweep()
+ {
+ if(_reloadSweep) {
+ if(_sweepDivider == 0 && _sweepEnabled) {
+ //If the divider's counter was zero before the reload and the sweep is enabled, the pulse's period is also adjusted
+ UpdateTargetPeriod(true);
+ }
+ _sweepDivider = _sweepPeriod;
+ _reloadSweep = false;
+ } else {
+ if(_sweepDivider > 0) {
+ _sweepDivider--;
+ } else if(_sweepEnabled) {
+ UpdateTargetPeriod(true);
+ _sweepDivider = _sweepPeriod;
+ }
+ }
+ }
+
+ void Run(uint32_t targetCycle)
+ {
+ UpdateTargetPeriod(false);
+ BaseApuChannel::Run(targetCycle);
+ }
+
+ void Clock()
+ {
+ _dutyPos = (_dutyPos - 1) & 0x07;
+
+ if(IsMuted()) {
+ AddOutput(0);
+ } else {
+ AddOutput(_dutySequences[_duty][_dutyPos] * GetVolume());
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/TriangleChannel.h b/Core/TriangleChannel.h
new file mode 100644
index 00000000..a25c9855
--- /dev/null
+++ b/Core/TriangleChannel.h
@@ -0,0 +1,82 @@
+#pragma once
+#include "stdafx.h"
+#include "../BlipBuffer/Blip_Buffer.h"
+#include "APU.h"
+#include "IMemoryHandler.h"
+#include "ApuEnvelope.h"
+
+class TriangleChannel : public ApuLengthCounter
+{
+private:
+ const vector _sequence = { { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } };
+
+ uint8_t _linearCounter = 0;
+ uint8_t _linearCounterReload = 0;
+ bool _linearReloadFlag = false;
+ bool _linearControlFlag = false;
+
+ uint8_t _sequencePosition = 0;
+
+public:
+ TriangleChannel()
+ {
+ _clockDivider = 1; //Triangle clocks at the same speed as the cpu
+ SetVolume(0.12765);
+ }
+
+ void GetMemoryRanges(MemoryRanges &ranges)
+ {
+ ranges.AddHandler(MemoryType::RAM, MemoryOperation::Write, 0x4008, 0x400B);
+ }
+
+ void WriteRAM(uint16_t addr, uint8_t value)
+ {
+ APU::StaticRun();
+ switch(addr & 0x03) {
+ case 0: //4008
+ _linearControlFlag = (value & 0x80) == 0x80;
+ _linearCounterReload = value & 0x7F;
+
+ InitializeLengthCounter(_linearControlFlag);
+ break;
+
+ case 2: //400A
+ _period &= ~0x00FF;
+ _period |= value;
+ break;
+
+ case 3: //400B
+ LoadLengthCounter(value >> 3);
+
+ _period &= ~0xFF00;
+ _period |= (value & 0x03) << 8;
+
+ //Side effects Sets the linear counter reload flag
+ _linearReloadFlag = true;
+ break;
+ }
+ }
+
+ void Clock()
+ {
+ //The sequencer is clocked by the timer as long as both the linear counter and the length counter are nonzero.
+ if(_lengthCounter > 0 && _linearCounter > 0) {
+ _sequencePosition = (_sequencePosition + 1) & 0x1F;
+
+ AddOutput(_sequence[_sequencePosition]);
+ }
+ }
+
+ void TickLinearCounter()
+ {
+ if(_linearReloadFlag) {
+ _linearCounter = _linearCounterReload;
+ } else if(_linearCounter > 0) {
+ _linearCounter--;
+ }
+
+ if(!_linearControlFlag) {
+ _linearReloadFlag = false;
+ }
+ }
+};
\ No newline at end of file
diff --git a/Dependencies/Nes_Apu.Debug.x64.lib b/Dependencies/Nes_Apu.Debug.x64.lib
deleted file mode 100644
index 1aaa7dbb..00000000
Binary files a/Dependencies/Nes_Apu.Debug.x64.lib and /dev/null differ
diff --git a/Dependencies/Nes_Apu.Debug.x86.lib b/Dependencies/Nes_Apu.Debug.x86.lib
deleted file mode 100644
index 6301f7f7..00000000
Binary files a/Dependencies/Nes_Apu.Debug.x86.lib and /dev/null differ
diff --git a/Dependencies/Nes_Apu.Release.x64.lib b/Dependencies/Nes_Apu.Release.x64.lib
deleted file mode 100644
index c7a4c7f4..00000000
Binary files a/Dependencies/Nes_Apu.Release.x64.lib and /dev/null differ
diff --git a/Dependencies/Nes_Apu.Release.x86.lib b/Dependencies/Nes_Apu.Release.x86.lib
deleted file mode 100644
index 4984a22d..00000000
Binary files a/Dependencies/Nes_Apu.Release.x86.lib and /dev/null differ
diff --git a/InteropDLL/InteropDLL.vcxproj b/InteropDLL/InteropDLL.vcxproj
index 37813e44..a010a5c7 100644
--- a/InteropDLL/InteropDLL.vcxproj
+++ b/InteropDLL/InteropDLL.vcxproj
@@ -254,6 +254,16 @@
Create
+
+
+ {cf35d78c-f710-41d2-968f-c46accff6f07}
+ false
+ true
+ false
+ true
+ false
+
+
diff --git a/InteropDLL/stdafx.h b/InteropDLL/stdafx.h
index ac798d3c..1f5931ee 100644
--- a/InteropDLL/stdafx.h
+++ b/InteropDLL/stdafx.h
@@ -45,6 +45,5 @@
#pragma comment(lib, MESEN_LIBRARY_PATH"Utilities.lib")
#pragma comment(lib, MESEN_LIBRARY_PATH"Windows.lib")
#pragma comment(lib, "../Dependencies/DirectXTK"MESEN_LIBRARY_SUFFIX)
-#pragma comment(lib, "../Dependencies/Nes_Apu"MESEN_LIBRARY_SUFFIX)
#define DllExport __declspec(dllexport)
\ No newline at end of file
diff --git a/NES.sln b/NES.sln
index b523a3ee..93f7b0f5 100644
--- a/NES.sln
+++ b/NES.sln
@@ -6,6 +6,7 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "Core\Core.vcxproj", "{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}"
ProjectSection(ProjectDependencies) = postProject
{B5330148-E8C7-46BA-B54E-69BE59EA337D} = {B5330148-E8C7-46BA-B54E-69BE59EA337D}
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07} = {CF35D78C-F710-41D2-968F-C46ACCFF6F07}
{7761E790-B42C-4179-8550-8365FF9EB23E} = {7761E790-B42C-4179-8550-8365FF9EB23E}
EndProjectSection
EndProject
@@ -29,6 +30,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PGOHelper", "PGOHelper\PGOH
{37749BB2-FA78-4EC9-8990-5628FC0BBA19} = {37749BB2-FA78-4EC9-8990-5628FC0BBA19}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlipBuffer", "BlipBuffer\BlipBuffer.vcxproj", "{CF35D78C-F710-41D2-968F-C46ACCFF6F07}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -85,6 +88,13 @@ Global
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|x64.Build.0 = Release|x64
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|x86.ActiveCfg = Release|Win32
{38D74EE1-5276-4D24-AABC-104B912A27D2}.Release|x86.Build.0 = Release|Win32
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07}.Debug|x64.ActiveCfg = Debug|x64
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07}.Debug|x64.Build.0 = Debug|x64
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07}.Debug|x86.ActiveCfg = Debug|Win32
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07}.Debug|x86.Build.0 = Debug|Win32
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07}.Release|x64.ActiveCfg = Release|x64
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07}.Release|x86.ActiveCfg = Release|Win32
+ {CF35D78C-F710-41D2-968F-C46ACCFF6F07}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE