Mercurial > vba-clojure
view src/apu/Blip_Buffer.h @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
line wrap: on
line source
1 // Band-limited sound synthesis buffer3 // Blip_Buffer 0.4.14 #ifndef BLIP_BUFFER_H5 #define BLIP_BUFFER_H7 // internal8 #include <limits.h>9 #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF10 typedef long blip_long;11 typedef unsigned long blip_ulong;12 #else13 typedef int blip_long;14 typedef unsigned blip_ulong;15 #endif17 // Time unit at source clock rate18 typedef blip_long blip_time_t;20 // Output samples are 16-bit signed, with a range of -32768 to 3276721 typedef short blip_sample_t;22 enum { blip_sample_max = 32767 };24 struct blip_buffer_state_t;26 class Blip_Buffer {27 public:28 typedef const char* blargg_err_t;30 // Sets output sample rate and buffer length in milliseconds (1/1000 sec, defaults31 // to 1/4 second) and clears buffer. If there isn't enough memory, leaves buffer32 // untouched and returns "Out of memory", otherwise returns NULL.33 blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );35 // Sets number of source time units per second36 void clock_rate( long clocks_per_sec );38 // Ends current time frame of specified duration and makes its samples available39 // (along with any still-unread samples) for reading with read_samples(). Begins40 // a new time frame at the end of the current frame.41 void end_frame( blip_time_t time );43 // Reads at most 'max_samples' out of buffer into 'dest', removing them from from44 // the buffer. Returns number of samples actually read and removed. If stereo is45 // true, increments 'dest' one extra time after writing each sample, to allow46 // easy interleving of two channels into a stereo output buffer.47 long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );49 // Additional features51 // Removes all available samples and clear buffer to silence. If 'entire_buffer' is52 // false, just clears out any samples waiting rather than the entire buffer.53 void clear( int entire_buffer = 1 );55 // Number of samples available for reading with read_samples()56 long samples_avail() const;58 // Removes 'count' samples from those waiting to be read59 void remove_samples( long count );61 // Sets frequency high-pass filter frequency, where higher values reduce bass more62 void bass_freq( int frequency );64 // Current output sample rate65 long sample_rate() const;67 // Length of buffer in milliseconds68 int length() const;70 // Number of source time units per second71 long clock_rate() const;73 // Experimental features75 // Saves state, including high-pass filter and tails of last deltas.76 // All samples must have been read from buffer before calling this.77 void save_state( blip_buffer_state_t* out );79 // Loads state. State must have been saved from Blip_Buffer with same80 // settings during same run of program. States can NOT be stored on disk.81 // Clears buffer before loading state.82 void load_state( blip_buffer_state_t const& in );84 // Number of samples delay from synthesis to samples read out85 int output_latency() const;87 // Counts number of clocks needed until 'count' samples will be available.88 // If buffer can't even hold 'count' samples, returns number of clocks until89 // buffer becomes full.90 blip_time_t count_clocks( long count ) const;92 // Number of raw samples that can be mixed within frame of specified duration.93 long count_samples( blip_time_t duration ) const;95 // Mixes in 'count' samples from 'buf_in'96 void mix_samples( blip_sample_t const* buf_in, long count );99 // Signals that sound has been added to buffer. Could be done automatically in100 // Blip_Synth, but that would affect performance more, as you can arrange that101 // this is called only once per time frame rather than for every delta.102 void set_modified() { modified_ = this; }104 // not documented yet105 blip_ulong unsettled() const;106 Blip_Buffer* clear_modified() { Blip_Buffer* b = modified_; modified_ = 0; return b; }107 void remove_silence( long count );108 typedef blip_ulong blip_resampled_time_t;109 blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }110 blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }111 blip_resampled_time_t clock_rate_factor( long clock_rate ) const;112 public:113 Blip_Buffer();114 ~Blip_Buffer();116 // Deprecated117 typedef blip_resampled_time_t resampled_time_t;118 blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }119 blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }120 private:121 // noncopyable122 Blip_Buffer( const Blip_Buffer& );123 Blip_Buffer& operator = ( const Blip_Buffer& );124 public:125 typedef blip_long buf_t_;126 blip_ulong factor_;127 blip_resampled_time_t offset_;128 buf_t_* buffer_;129 blip_long buffer_size_;130 blip_long reader_accum_;131 int bass_shift_;132 private:133 long sample_rate_;134 long clock_rate_;135 int bass_freq_;136 int length_;137 Blip_Buffer* modified_; // non-zero = true (more optimal than using bool, heh)138 friend class Blip_Reader;139 };141 #ifdef HAVE_CONFIG_H142 #include "config.h"143 #endif145 // Number of bits in resample ratio fraction. Higher values give a more accurate ratio146 // but reduce maximum buffer size.147 #ifndef BLIP_BUFFER_ACCURACY148 #define BLIP_BUFFER_ACCURACY 16149 #endif151 // Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in152 // noticeable broadband noise when synthesizing high frequency square waves.153 // Affects size of Blip_Synth objects since they store the waveform directly.154 #ifndef BLIP_PHASE_BITS155 #if BLIP_BUFFER_FAST156 #define BLIP_PHASE_BITS 8157 #else158 #define BLIP_PHASE_BITS 6159 #endif160 #endif162 // Internal163 typedef blip_ulong blip_resampled_time_t;164 int const blip_widest_impulse_ = 16;165 int const blip_buffer_extra_ = blip_widest_impulse_ + 2;166 int const blip_res = 1 << BLIP_PHASE_BITS;167 class blip_eq_t;169 class Blip_Synth_Fast_ {170 public:171 Blip_Buffer* buf;172 int last_amp;173 int delta_factor;175 void volume_unit( double );176 Blip_Synth_Fast_();177 void treble_eq( blip_eq_t const& ) { }178 };180 class Blip_Synth_ {181 public:182 Blip_Buffer* buf;183 int last_amp;184 int delta_factor;186 void volume_unit( double );187 Blip_Synth_( short* impulses, int width );188 void treble_eq( blip_eq_t const& );189 private:190 double volume_unit_;191 short* const impulses;192 int const width;193 blip_long kernel_unit;194 int impulses_size() const { return blip_res / 2 * width + 1; }195 void adjust_impulse();196 };198 // Quality level, better = slower. In general, use blip_good_quality.199 const int blip_med_quality = 8;200 const int blip_good_quality = 12;201 const int blip_high_quality = 16;203 // Range specifies the greatest expected change in amplitude. Calculate it204 // by finding the difference between the maximum and minimum expected205 // amplitudes (max - min).206 template<int quality,int range>207 class Blip_Synth {208 public:209 // Sets overall volume of waveform210 void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }212 // Configures low-pass filter (see blip_buffer.txt)213 void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }215 // Gets/sets Blip_Buffer used for output216 Blip_Buffer* output() const { return impl.buf; }217 void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }219 // Updates amplitude of waveform at given time. Using this requires a separate220 // Blip_Synth for each waveform.221 void update( blip_time_t time, int amplitude );223 // Low-level interface225 // Adds an amplitude transition of specified delta, optionally into specified buffer226 // rather than the one set with output(). Delta can be positive or negative.227 // The actual change in amplitude is delta * (volume / range)228 void offset( blip_time_t, int delta, Blip_Buffer* ) const;229 void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }231 // Works directly in terms of fractional output samples. Contact author for more info.232 void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;234 // Same as offset(), except code is inlined for higher performance235 void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {236 offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );237 }238 void offset_inline( blip_time_t t, int delta ) const {239 offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );240 }242 private:243 #if BLIP_BUFFER_FAST244 Blip_Synth_Fast_ impl;245 #else246 Blip_Synth_ impl;247 typedef short imp_t;248 imp_t impulses [blip_res * (quality / 2) + 1];249 public:250 Blip_Synth() : impl( impulses, quality ) { }251 #endif252 };254 // Low-pass equalization parameters255 class blip_eq_t {256 public:257 // Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce258 // treble, small positive values (0 to 5.0) increase treble.259 blip_eq_t( double treble_db = 0 );261 // See blip_buffer.txt262 blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );264 private:265 double treble;266 long rolloff_freq;267 long sample_rate;268 long cutoff_freq;269 void generate( float* out, int count ) const;270 friend class Blip_Synth_;271 };273 int const blip_sample_bits = 30;275 // Dummy Blip_Buffer to direct sound output to, for easy muting without276 // having to stop sound code.277 class Silent_Blip_Buffer : public Blip_Buffer {278 buf_t_ buf [blip_buffer_extra_ + 1];279 public:280 // The following cannot be used (an assertion will fail if attempted):281 blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );282 blip_time_t count_clocks( long count ) const;283 void mix_samples( blip_sample_t const* buf, long count );285 Silent_Blip_Buffer();286 };288 #if __GNUC__ >= 3 || _MSC_VER >= 1400289 #define BLIP_RESTRICT __restrict290 #else291 #define BLIP_RESTRICT292 #endif294 // Optimized reading from Blip_Buffer, for use in custom sample output296 // Begins reading from buffer. Name should be unique to the current block.297 #define BLIP_READER_BEGIN( name, blip_buffer ) \298 const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\299 blip_long name##_reader_accum = (blip_buffer).reader_accum_301 // Gets value to pass to BLIP_READER_NEXT()302 #define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)304 // Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal305 // code at the cost of having no bass control306 int const blip_reader_default_bass = 9;308 // Current sample309 #define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))311 // Current raw sample in full internal resolution312 #define BLIP_READER_READ_RAW( name ) (name##_reader_accum)314 // Advances to next sample315 #define BLIP_READER_NEXT( name, bass ) \316 (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))318 // Ends reading samples from buffer. The number of samples read must now be removed319 // using Blip_Buffer::remove_samples().320 #define BLIP_READER_END( name, blip_buffer ) \321 (void) ((blip_buffer).reader_accum_ = name##_reader_accum)324 // experimental325 #define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset)327 blip_long const blip_reader_idx_factor = sizeof (Blip_Buffer::buf_t_);329 #define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\330 name##_reader_accum -= name##_reader_accum >> (bass);\331 name##_reader_accum += name##_reader_buf [(idx)];\332 }334 #define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\335 name##_reader_accum -= name##_reader_accum >> (bass);\336 name##_reader_accum +=\337 *(Blip_Buffer::buf_t_ const*) ((char const*) name##_reader_buf + (idx));\338 }340 // Compatibility with older version341 const long blip_unscaled = 65535;342 const int blip_low_quality = blip_med_quality;343 const int blip_best_quality = blip_high_quality;345 // Deprecated; use BLIP_READER macros as follows:346 // Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );347 // int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );348 // r.read() -> BLIP_READER_READ( r )349 // r.read_raw() -> BLIP_READER_READ_RAW( r )350 // r.next( bass ) -> BLIP_READER_NEXT( r, bass )351 // r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )352 // r.end( buf ) -> BLIP_READER_END( r, buf )353 class Blip_Reader {354 public:355 int begin( Blip_Buffer& );356 blip_long read() const { return accum >> (blip_sample_bits - 16); }357 blip_long read_raw() const { return accum; }358 void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }359 void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }360 private:361 const Blip_Buffer::buf_t_* buf;362 blip_long accum;363 };365 #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \366 defined (__x86_64__) || defined (__ia64__) || defined (__i386__)367 #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in368 #else369 #define BLIP_CLAMP_( in ) (blip_sample_t) in != in370 #endif372 // Clamp sample to blip_sample_t range373 #define BLIP_CLAMP( sample, out )\374 { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 24) ^ 0x7FFF; }376 struct blip_buffer_state_t377 {378 blip_resampled_time_t offset_;379 blip_long reader_accum_;380 blip_long buf [blip_buffer_extra_];381 };383 // End of public interface385 #ifndef assert386 #include <assert.h>387 #endif389 template<int quality,int range>390 inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,391 int delta, Blip_Buffer* blip_buf ) const392 {393 // If this assertion fails, it means that an attempt was made to add a delta394 // at a negative time or past the end of the buffer.395 assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );397 delta *= impl.delta_factor;398 blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);399 int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));401 #if BLIP_BUFFER_FAST402 blip_long left = buf [0] + delta;404 // Kind of crappy, but doing shift after multiply results in overflow.405 // Alternate way of delaying multiply by delta_factor results in worse406 // sub-sample resolution.407 blip_long right = (delta >> BLIP_PHASE_BITS) * phase;408 left -= right;409 right += buf [1];411 buf [0] = left;412 buf [1] = right;413 #else415 int const fwd = (blip_widest_impulse_ - quality) / 2;416 int const rev = fwd + quality - 2;417 int const mid = quality / 2 - 1;419 imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;421 #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \422 defined (__x86_64__) || defined (__ia64__) || defined (__i386__)424 // this straight forward version gave in better code on GCC for x86426 #define ADD_IMP( out, in ) \427 buf [out] += (blip_long) imp [blip_res * (in)] * delta429 #define BLIP_FWD( i ) {\430 ADD_IMP( fwd + i, i );\431 ADD_IMP( fwd + 1 + i, i + 1 );\432 }433 #define BLIP_REV( r ) {\434 ADD_IMP( rev - r, r + 1 );\435 ADD_IMP( rev + 1 - r, r );\436 }438 BLIP_FWD( 0 )439 if ( quality > 8 ) BLIP_FWD( 2 )440 if ( quality > 12 ) BLIP_FWD( 4 )441 {442 ADD_IMP( fwd + mid - 1, mid - 1 );443 ADD_IMP( fwd + mid , mid );444 imp = impulses + phase;445 }446 if ( quality > 12 ) BLIP_REV( 6 )447 if ( quality > 8 ) BLIP_REV( 4 )448 BLIP_REV( 2 )450 ADD_IMP( rev , 1 );451 ADD_IMP( rev + 1, 0 );453 #undef ADD_IMP455 #else457 // for RISC processors, help compiler by reading ahead of writes459 #define BLIP_FWD( i ) {\460 blip_long t0 = i0 * delta + buf [fwd + i];\461 blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\462 i0 = imp [blip_res * (i + 2)];\463 buf [fwd + i] = t0;\464 buf [fwd + 1 + i] = t1;\465 }466 #define BLIP_REV( r ) {\467 blip_long t0 = i0 * delta + buf [rev - r];\468 blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\469 i0 = imp [blip_res * (r - 1)];\470 buf [rev - r] = t0;\471 buf [rev + 1 - r] = t1;\472 }474 blip_long i0 = *imp;475 BLIP_FWD( 0 )476 if ( quality > 8 ) BLIP_FWD( 2 )477 if ( quality > 12 ) BLIP_FWD( 4 )478 {479 blip_long t0 = i0 * delta + buf [fwd + mid - 1];480 blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ];481 imp = impulses + phase;482 i0 = imp [blip_res * mid];483 buf [fwd + mid - 1] = t0;484 buf [fwd + mid ] = t1;485 }486 if ( quality > 12 ) BLIP_REV( 6 )487 if ( quality > 8 ) BLIP_REV( 4 )488 BLIP_REV( 2 )490 blip_long t0 = i0 * delta + buf [rev ];491 blip_long t1 = *imp * delta + buf [rev + 1];492 buf [rev ] = t0;493 buf [rev + 1] = t1;494 #endif496 #endif497 }499 #undef BLIP_FWD500 #undef BLIP_REV502 template<int quality,int range>503 #if BLIP_BUFFER_FAST504 inline505 #endif506 void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const507 {508 offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );509 }511 template<int quality,int range>512 #if BLIP_BUFFER_FAST513 inline514 #endif515 void Blip_Synth<quality,range>::update( blip_time_t t, int amp )516 {517 int delta = amp - impl.last_amp;518 impl.last_amp = amp;519 offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );520 }522 inline blip_eq_t::blip_eq_t( double t ) :523 treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }524 inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :525 treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }527 inline int Blip_Buffer::length() const { return length_; }528 inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }529 inline long Blip_Buffer::sample_rate() const { return sample_rate_; }530 inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }531 inline long Blip_Buffer::clock_rate() const { return clock_rate_; }532 inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }534 inline int Blip_Reader::begin( Blip_Buffer& blip_buf )535 {536 buf = blip_buf.buffer_;537 accum = blip_buf.reader_accum_;538 return blip_buf.bass_shift_;539 }541 inline void Blip_Buffer::remove_silence( long count )542 {543 // fails if you try to remove more samples than available544 assert( count <= samples_avail() );545 offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;546 }548 inline blip_ulong Blip_Buffer::unsettled() const549 {550 return reader_accum_ >> (blip_sample_bits - 16);551 }553 int const blip_max_length = 0;554 int const blip_default_length = 250; // 1/4 second556 #endif