Blip_Synth.h (7047B)
1 2// Blip_Synth and Blip_Wave are waveform transition synthesizers for adding 3// waveforms to a Blip_Buffer. 4 5// Blip_Buffer 0.3.4. Copyright (C) 2003-2005 Shay Green. GNU LGPL license. 6 7#ifndef BLIP_SYNTH_H 8#define BLIP_SYNTH_H 9 10#ifndef BLIP_BUFFER_H 11 #include "Blip_Buffer.h" 12#endif 13 14// Quality level. Higher levels are slower, and worse in a few cases. 15// Use blip_good_quality as a starting point. 16const int blip_low_quality = 1; 17const int blip_med_quality = 2; 18const int blip_good_quality = 3; 19const int blip_high_quality = 4; 20 21// Blip_Synth is a transition waveform synthesizer which adds band-limited 22// offsets (transitions) into a Blip_Buffer. For a simpler interface, use 23// Blip_Wave (below). 24// 25// Range specifies the greatest expected offset that will occur. For a 26// waveform that goes between +amp and -amp, range should be amp * 2 (half 27// that if it only goes between +amp and 0). When range is large, a higher 28// accuracy scheme is used; to force this even when range is small, pass 29// the negative of range (i.e. -range). 30template<int quality,int range> 31class Blip_Synth { 32 BOOST_STATIC_ASSERT( 1 <= quality && quality <= 5 ); 33 BOOST_STATIC_ASSERT( -32768 <= range && range <= 32767 ); 34 enum { 35 abs_range = (range < 0) ? -range : range, 36 fine_mode = (range > 512 || range < 0), 37 width = (quality < 5 ? quality * 4 : Blip_Buffer::widest_impulse_), 38 res = 1 << blip_res_bits_, 39 impulse_size = width / 2 * (fine_mode + 1), 40 base_impulses_size = width / 2 * (res / 2 + 1), 41 fine_bits = (fine_mode ? (abs_range <= 64 ? 2 : abs_range <= 128 ? 3 : 42 abs_range <= 256 ? 4 : abs_range <= 512 ? 5 : abs_range <= 1024 ? 6 : 43 abs_range <= 2048 ? 7 : 8) : 0) 44 }; 45 blip_pair_t_ impulses [impulse_size * res * 2 + base_impulses_size]; 46 Blip_Impulse_ impulse; 47 void init() { impulse.init( impulses, width, res, fine_bits ); } 48public: 49 Blip_Synth() { init(); } 50 Blip_Synth( double volume ) { init(); this->volume( volume ); } 51 52 // Configure low-pass filter (see notes.txt). Not optimized for real-time control 53 void treble_eq( const blip_eq_t& eq ) { impulse.treble_eq( eq ); } 54 55 // Set volume of a transition at amplitude 'range' by setting volume_unit 56 // to v / range 57 void volume( double v ) { impulse.volume_unit( v * (1.0 / abs_range) ); } 58 59 // Set base volume unit of transitions, where 1.0 is a full swing between the 60 // positive and negative extremes. Not optimized for real-time control. 61 void volume_unit( double unit ) { impulse.volume_unit( unit ); } 62 63 // Default Blip_Buffer used for output when none is specified for a given call 64 Blip_Buffer* output() const { return impulse.buf; } 65 void output( Blip_Buffer* b ) { impulse.buf = b; } 66 67 // Add an amplitude offset (transition) with a magnitude of delta * volume_unit 68 // into the specified buffer (default buffer if none specified) at the 69 // specified source time. Delta can be positive or negative. To increase 70 // performance by inlining code at the call site, use offset_inline(). 71 void offset( blip_time_t, int delta, Blip_Buffer* ) const; 72 73 void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const; 74 void offset_resampled( blip_resampled_time_t t, int o ) const { 75 offset_resampled( t, o, impulse.buf ); 76 } 77 void offset( blip_time_t t, int delta ) const { 78 offset( t, delta, impulse.buf ); 79 } 80 void offset_inline( blip_time_t time, int delta, Blip_Buffer* buf ) const { 81 offset_resampled( time * buf->factor_ + buf->offset_, delta, buf ); 82 } 83 void offset_inline( blip_time_t time, int delta ) const { 84 offset_inline( time, delta, impulse.buf ); 85 } 86}; 87 88// Blip_Wave is a synthesizer for adding a *single* waveform to a Blip_Buffer. 89// A wave is built from a series of delays and new amplitudes. This provides a 90// simpler interface than Blip_Synth, nothing more. 91template<int quality,int range> 92class Blip_Wave { 93 Blip_Synth<quality,range> synth; 94 blip_time_t time_; 95 int last_amp; 96 void init() { time_ = 0; last_amp = 0; } 97public: 98 // Start wave at time 0 and amplitude 0 99 Blip_Wave() { init(); } 100 Blip_Wave( double volume ) { init(); this->volume( volume ); } 101 102 // See Blip_Synth for description 103 void volume( double v ) { synth.volume( v ); } 104 void volume_unit( double v ) { synth.volume_unit( v ); } 105 void treble_eq( const blip_eq_t& eq){ synth.treble_eq( eq ); } 106 Blip_Buffer* output() const { return synth.output(); } 107 void output( Blip_Buffer* b ) { synth.output( b ); if ( !b ) time_ = last_amp = 0; } 108 109 // Current time in frame 110 blip_time_t time() const { return time_; } 111 void time( blip_time_t t ) { time_ = t; } 112 113 // Current amplitude of wave 114 int amplitude() const { return last_amp; } 115 void amplitude( int ); 116 117 // Move forward by 't' time units 118 void delay( blip_time_t t ) { time_ += t; } 119 120 // End time frame of specified duration. Localize time to new frame. 121 // If wave hadn't been run to end of frame, start it at beginning of new frame. 122 void end_frame( blip_time_t duration ) 123 { 124 time_ -= duration; 125 if ( time_ < 0 ) 126 time_ = 0; 127 } 128}; 129 130// End of public interface 131 132template<int quality,int range> 133void Blip_Wave<quality,range>::amplitude( int amp ) { 134 int delta = amp - last_amp; 135 last_amp = amp; 136 synth.offset_inline( time_, delta ); 137} 138 139template<int quality,int range> 140inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time, 141 int delta, Blip_Buffer* blip_buf ) const 142{ 143 typedef blip_pair_t_ pair_t; 144 145 unsigned sample_index = (time >> BLIP_BUFFER_ACCURACY) & ~1; 146 assert(( (void)"Blip_Synth/Blip_wave: Went past end of buffer", 147 sample_index < blip_buf->buffer_size_ )); 148 enum { const_offset = Blip_Buffer::widest_impulse_ / 2 - width / 2 }; 149 pair_t* buf = (pair_t*) &blip_buf->buffer_ [const_offset + sample_index]; 150 151 enum { shift = BLIP_BUFFER_ACCURACY - blip_res_bits_ }; 152 enum { mask = res * 2 - 1 }; 153 const pair_t* imp = &impulses [((time >> shift) & mask) * impulse_size]; 154 155 pair_t offset = impulse.offset * delta; 156 157 if ( !fine_bits ) 158 { 159 // normal mode 160 for ( int n = width / 4; n; --n ) 161 { 162 pair_t t0 = buf [0] - offset; 163 pair_t t1 = buf [1] - offset; 164 165 t0 += imp [0] * delta; 166 t1 += imp [1] * delta; 167 imp += 2; 168 169 buf [0] = t0; 170 buf [1] = t1; 171 buf += 2; 172 } 173 } 174 else 175 { 176 // fine mode 177 enum { sub_range = 1 << fine_bits }; 178 delta += sub_range / 2; 179 int delta2 = (delta & (sub_range - 1)) - sub_range / 2; 180 delta >>= fine_bits; 181 182 for ( int n = width / 4; n; --n ) 183 { 184 pair_t t0 = buf [0] - offset; 185 pair_t t1 = buf [1] - offset; 186 187 t0 += imp [0] * delta2; 188 t0 += imp [1] * delta; 189 190 t1 += imp [2] * delta2; 191 t1 += imp [3] * delta; 192 193 imp += 4; 194 195 buf [0] = t0; 196 buf [1] = t1; 197 buf += 2; 198 } 199 } 200} 201 202template<int quality,int range> 203void Blip_Synth<quality,range>::offset( blip_time_t time, int delta, Blip_Buffer* buf ) const { 204 offset_resampled( time * buf->factor_ + buf->offset_, delta, buf ); 205} 206 207#endif 208