Path: blob/a-new-beginning/Cherry/Core/include/audio/Blip_Buffer.h
2 views
// Band-limited sound synthesis buffer12// Blip_Buffer 0.4.13#ifndef BLIP_BUFFER_H4#define BLIP_BUFFER_H56// internal7#include <limits.h>8#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF9typedef long blip_long;10typedef unsigned long blip_ulong;11#else12typedef int blip_long;13typedef unsigned blip_ulong;14#endif1516// Time unit at source clock rate17typedef blip_long blip_time_t;1819// Output samples are 16-bit signed, with a range of -32768 to 3276720typedef short blip_sample_t;21enum { blip_sample_max = 32767 };2223struct blip_buffer_state_t;2425class Blip_Buffer {26public:27typedef const char* blargg_err_t;2829// Sets output sample rate and buffer length in milliseconds (1/1000 sec, defaults30// to 1/4 second) and clears buffer. If there isn't enough memory, leaves buffer31// untouched and returns "Out of memory", otherwise returns NULL.32blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );3334// Sets number of source time units per second35void clock_rate( long clocks_per_sec );3637// Ends current time frame of specified duration and makes its samples available38// (along with any still-unread samples) for reading with read_samples(). Begins39// a new time frame at the end of the current frame.40void end_frame( blip_time_t time );4142// Reads at most 'max_samples' out of buffer into 'dest', removing them from43// the buffer. Returns number of samples actually read and removed. If stereo is44// true, increments 'dest' one extra time after writing each sample, to allow45// easy interleving of two channels into a stereo output buffer.46long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );4748// Additional features4950// Removes all available samples and clear buffer to silence. If 'entire_buffer' is51// false, just clears out any samples waiting rather than the entire buffer.52void clear( int entire_buffer = 1 );5354// Number of samples available for reading with read_samples()55long samples_avail() const;5657// Removes 'count' samples from those waiting to be read58void remove_samples( long count );5960// Sets frequency high-pass filter frequency, where higher values reduce bass more61void bass_freq( int frequency );6263// Current output sample rate64long sample_rate() const;6566// Length of buffer in milliseconds67int length() const;6869// Number of source time units per second70long clock_rate() const;7172// Experimental features7374// Saves state, including high-pass filter and tails of last deltas.75// All samples must have been read from buffer before calling this.76void save_state( blip_buffer_state_t* out );7778// Loads state. State must have been saved from Blip_Buffer with same79// settings during same run of program. States can NOT be stored on disk.80// Clears buffer before loading state.81void load_state( blip_buffer_state_t const& in );8283// Number of samples delay from synthesis to samples read out84int output_latency() const;8586// Counts number of clocks needed until 'count' samples will be available.87// If buffer can't even hold 'count' samples, returns number of clocks until88// buffer becomes full.89blip_time_t count_clocks( long count ) const;9091// Number of raw samples that can be mixed within frame of specified duration.92long count_samples( blip_time_t duration ) const;9394// Mixes in 'count' samples from 'buf_in'95void mix_samples( blip_sample_t const* buf_in, long count );969798// Signals that sound has been added to buffer. Could be done automatically in99// Blip_Synth, but that would affect performance more, as you can arrange that100// this is called only once per time frame rather than for every delta.101void set_modified() { modified_ = this; }102103// not documented yet104blip_ulong unsettled() const;105Blip_Buffer* clear_modified() { Blip_Buffer* b = modified_; modified_ = 0; return b; }106void remove_silence( long count );107typedef blip_ulong blip_resampled_time_t;108blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }109blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }110blip_resampled_time_t clock_rate_factor( long clock_rate ) const;111public:112Blip_Buffer();113~Blip_Buffer();114115// Deprecated116typedef blip_resampled_time_t resampled_time_t;117blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }118blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }119private:120// noncopyable121Blip_Buffer( const Blip_Buffer& );122Blip_Buffer& operator = ( const Blip_Buffer& );123public:124typedef blip_long buf_t_;125blip_ulong factor_;126blip_resampled_time_t offset_;127buf_t_* buffer_;128blip_long buffer_size_;129blip_long reader_accum_;130int bass_shift_;131private:132long sample_rate_;133long clock_rate_;134int bass_freq_;135int length_;136Blip_Buffer* modified_; // non-zero = true (more optimal than using bool, heh)137friend class Blip_Reader;138};139140#ifdef HAVE_CONFIG_H141#include "config.h"142#endif143144// Number of bits in resample ratio fraction. Higher values give a more accurate ratio145// but reduce maximum buffer size.146#ifndef BLIP_BUFFER_ACCURACY147#define BLIP_BUFFER_ACCURACY 16148#endif149150// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in151// noticeable broadband noise when synthesizing high frequency square waves.152// Affects size of Blip_Synth objects since they store the waveform directly.153#ifndef BLIP_PHASE_BITS154#if BLIP_BUFFER_FAST155#define BLIP_PHASE_BITS 8156#else157#define BLIP_PHASE_BITS 6158#endif159#endif160161// Internal162typedef blip_ulong blip_resampled_time_t;163int const blip_widest_impulse_ = 16;164int const blip_buffer_extra_ = blip_widest_impulse_ + 2;165int const blip_res = 1 << BLIP_PHASE_BITS;166class blip_eq_t;167168class Blip_Synth_Fast_ {169public:170Blip_Buffer* buf;171int last_amp;172int delta_factor;173174void volume_unit( double );175Blip_Synth_Fast_();176void treble_eq( blip_eq_t const& ) { }177};178179class Blip_Synth_ {180public:181Blip_Buffer* buf;182int last_amp;183int delta_factor;184185void volume_unit( double );186Blip_Synth_( short* impulses, int width );187void treble_eq( blip_eq_t const& );188private:189double volume_unit_;190short* const impulses;191int const width;192blip_long kernel_unit;193int impulses_size() const { return blip_res / 2 * width + 1; }194void adjust_impulse();195};196197// Quality level, better = slower. In general, use blip_good_quality.198const int blip_med_quality = 8;199const int blip_good_quality = 12;200const int blip_high_quality = 16;201202// Range specifies the greatest expected change in amplitude. Calculate it203// by finding the difference between the maximum and minimum expected204// amplitudes (max - min).205template<int quality,int range>206class Blip_Synth {207public:208// Sets overall volume of waveform209void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }210211// Configures low-pass filter (see blip_buffer.txt)212void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }213214// Gets/sets Blip_Buffer used for output215Blip_Buffer* output() const { return impl.buf; }216void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }217218// Updates amplitude of waveform at given time. Using this requires a separate219// Blip_Synth for each waveform.220void update( blip_time_t time, int amplitude );221222// Low-level interface223224// Adds an amplitude transition of specified delta, optionally into specified buffer225// rather than the one set with output(). Delta can be positive or negative.226// The actual change in amplitude is delta * (volume / range)227void offset( blip_time_t, int delta, Blip_Buffer* ) const;228void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }229230// Works directly in terms of fractional output samples. Contact author for more info.231void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;232233// Same as offset(), except code is inlined for higher performance234void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {235offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );236}237void offset_inline( blip_time_t t, int delta ) const {238offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );239}240241private:242#if BLIP_BUFFER_FAST243Blip_Synth_Fast_ impl;244#else245Blip_Synth_ impl;246typedef short imp_t;247imp_t impulses [blip_res * (quality / 2) + 1];248public:249Blip_Synth() : impl( impulses, quality ) { }250#endif251};252253// Low-pass equalization parameters254class blip_eq_t {255public:256// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce257// treble, small positive values (0 to 5.0) increase treble.258blip_eq_t( double treble_db = 0 );259260// See blip_buffer.txt261blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );262263private:264double treble;265long rolloff_freq;266long sample_rate;267long cutoff_freq;268void generate( float* out, int count ) const;269friend class Blip_Synth_;270};271272int const blip_sample_bits = 30;273274// Dummy Blip_Buffer to direct sound output to, for easy muting without275// having to stop sound code.276class Silent_Blip_Buffer : public Blip_Buffer {277buf_t_ buf [blip_buffer_extra_ + 1];278public:279// The following cannot be used (an assertion will fail if attempted):280blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );281blip_time_t count_clocks( long count ) const;282void mix_samples( blip_sample_t const* buf, long count );283284Silent_Blip_Buffer();285};286287#if __GNUC__ >= 3 || _MSC_VER >= 1100288#define BLIP_RESTRICT __restrict289#else290#define BLIP_RESTRICT291#endif292293// Optimized reading from Blip_Buffer, for use in custom sample output294295// Begins reading from buffer. Name should be unique to the current block.296#define BLIP_READER_BEGIN( name, blip_buffer ) \297const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\298blip_long name##_reader_accum = (blip_buffer).reader_accum_299300// Gets value to pass to BLIP_READER_NEXT()301#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)302303// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal304// code at the cost of having no bass control305int const blip_reader_default_bass = 9;306307// Current sample308#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))309310// Current raw sample in full internal resolution311#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)312313// Advances to next sample314#define BLIP_READER_NEXT( name, bass ) \315(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))316317// Ends reading samples from buffer. The number of samples read must now be removed318// using Blip_Buffer::remove_samples().319#define BLIP_READER_END( name, blip_buffer ) \320(void) ((blip_buffer).reader_accum_ = name##_reader_accum)321322323// experimental324#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset)325326blip_long const blip_reader_idx_factor = sizeof (Blip_Buffer::buf_t_);327328#define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\329name##_reader_accum -= name##_reader_accum >> (bass);\330name##_reader_accum += name##_reader_buf [(idx)];\331}332333#define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\334name##_reader_accum -= name##_reader_accum >> (bass);\335name##_reader_accum +=\336*(Blip_Buffer::buf_t_ const*) ((char const*) name##_reader_buf + (idx));\337}338339// Compatibility with older version340const long blip_unscaled = 65535;341const int blip_low_quality = blip_med_quality;342const int blip_best_quality = blip_high_quality;343344// Deprecated; use BLIP_READER macros as follows:345// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );346// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );347// r.read() -> BLIP_READER_READ( r )348// r.read_raw() -> BLIP_READER_READ_RAW( r )349// r.next( bass ) -> BLIP_READER_NEXT( r, bass )350// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )351// r.end( buf ) -> BLIP_READER_END( r, buf )352class Blip_Reader {353public:354int begin( Blip_Buffer& );355blip_long read() const { return accum >> (blip_sample_bits - 16); }356blip_long read_raw() const { return accum; }357void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }358void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }359private:360const Blip_Buffer::buf_t_* buf;361blip_long accum;362};363364#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \365defined (__x86_64__) || defined (__ia64__) || defined (__i386__)366#define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in367#else368#define BLIP_CLAMP_( in ) (blip_sample_t) in != in369#endif370371// Clamp sample to blip_sample_t range372#define BLIP_CLAMP( sample, out )\373{ if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 24) ^ 0x7FFF; }374375struct blip_buffer_state_t376{377blip_resampled_time_t offset_;378blip_long reader_accum_;379blip_long buf [blip_buffer_extra_];380};381382// End of public interface383384#ifndef assert385#include <assert.h>386#endif387388template<int quality,int range>389inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,390int delta, Blip_Buffer* blip_buf ) const391{392// If this assertion fails, it means that an attempt was made to add a delta393// at a negative time or past the end of the buffer.394assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );395396delta *= impl.delta_factor;397blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);398int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));399400#if BLIP_BUFFER_FAST401blip_long left = buf [0] + delta;402403// Kind of crappy, but doing shift after multiply results in overflow.404// Alternate way of delaying multiply by delta_factor results in worse405// sub-sample resolution.406blip_long right = (delta >> BLIP_PHASE_BITS) * phase;407left -= right;408right += buf [1];409410buf [0] = left;411buf [1] = right;412#else413414int const fwd = (blip_widest_impulse_ - quality) / 2;415int const rev = fwd + quality - 2;416int const mid = quality / 2 - 1;417418imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;419420#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \421defined (__x86_64__) || defined (__ia64__) || defined (__i386__)422423// this straight forward version gave in better code on GCC for x86424425#define ADD_IMP( out, in ) \426buf [out] += (blip_long) imp [blip_res * (in)] * delta427428#define BLIP_FWD( i ) {\429ADD_IMP( fwd + i, i );\430ADD_IMP( fwd + 1 + i, i + 1 );\431}432#define BLIP_REV( r ) {\433ADD_IMP( rev - r, r + 1 );\434ADD_IMP( rev + 1 - r, r );\435}436437BLIP_FWD( 0 )438if ( quality > 8 ) BLIP_FWD( 2 )439if ( quality > 12 ) BLIP_FWD( 4 )440{441ADD_IMP( fwd + mid - 1, mid - 1 );442ADD_IMP( fwd + mid , mid );443imp = impulses + phase;444}445if ( quality > 12 ) BLIP_REV( 6 )446if ( quality > 8 ) BLIP_REV( 4 )447BLIP_REV( 2 )448449ADD_IMP( rev , 1 );450ADD_IMP( rev + 1, 0 );451452#undef ADD_IMP453454#else455456// for RISC processors, help compiler by reading ahead of writes457458#define BLIP_FWD( i ) {\459blip_long t0 = i0 * delta + buf [fwd + i];\460blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\461i0 = imp [blip_res * (i + 2)];\462buf [fwd + i] = t0;\463buf [fwd + 1 + i] = t1;\464}465#define BLIP_REV( r ) {\466blip_long t0 = i0 * delta + buf [rev - r];\467blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\468i0 = imp [blip_res * (r - 1)];\469buf [rev - r] = t0;\470buf [rev + 1 - r] = t1;\471}472473blip_long i0 = *imp;474BLIP_FWD( 0 )475if ( quality > 8 ) BLIP_FWD( 2 )476if ( quality > 12 ) BLIP_FWD( 4 )477{478blip_long t0 = i0 * delta + buf [fwd + mid - 1];479blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ];480imp = impulses + phase;481i0 = imp [blip_res * mid];482buf [fwd + mid - 1] = t0;483buf [fwd + mid ] = t1;484}485if ( quality > 12 ) BLIP_REV( 6 )486if ( quality > 8 ) BLIP_REV( 4 )487BLIP_REV( 2 )488489blip_long t0 = i0 * delta + buf [rev ];490blip_long t1 = *imp * delta + buf [rev + 1];491buf [rev ] = t0;492buf [rev + 1] = t1;493#endif494495#endif496}497498#undef BLIP_FWD499#undef BLIP_REV500501template<int quality,int range>502#if BLIP_BUFFER_FAST503inline504#endif505void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const506{507offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );508}509510template<int quality,int range>511#if BLIP_BUFFER_FAST512inline513#endif514void Blip_Synth<quality,range>::update( blip_time_t t, int amp )515{516int delta = amp - impl.last_amp;517impl.last_amp = amp;518offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );519}520521inline blip_eq_t::blip_eq_t( double t ) :522treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }523inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :524treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }525526inline int Blip_Buffer::length() const { return length_; }527inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }528inline long Blip_Buffer::sample_rate() const { return sample_rate_; }529inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }530inline long Blip_Buffer::clock_rate() const { return clock_rate_; }531inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }532533inline int Blip_Reader::begin( Blip_Buffer& blip_buf )534{535buf = blip_buf.buffer_;536accum = blip_buf.reader_accum_;537return blip_buf.bass_shift_;538}539540inline void Blip_Buffer::remove_silence( long count )541{542// fails if you try to remove more samples than available543assert( count <= samples_avail() );544offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;545}546547inline blip_ulong Blip_Buffer::unsettled() const548{549return reader_accum_ >> (blip_sample_bits - 16);550}551552int const blip_max_length = 0;553int const blip_default_length = 250; // 1/4 second554555#endif556557558