| 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.3. 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. |
| 16 | const int blip_low_quality = 1; |
| 17 | const int blip_med_quality = 2; |
| 18 | const int blip_good_quality = 3; |
| 19 | const 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). |
| 30 | template<int quality,int range> |
| 31 | class 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 | public: |
| 48 | Blip_Synth() { impulse.init( impulses, width, res, fine_bits ); } |
| 49 | |
| 50 | // Configure low-pass filter (see notes.txt). Not optimized for real-time control |
| 51 | void treble_eq( const blip_eq_t& eq ) { impulse.treble_eq( eq ); } |
| 52 | |
| 53 | // Set volume of a transition at amplitude 'range' by setting volume_unit |
| 54 | // to v / range |
| 55 | void volume( double v ) { impulse.volume_unit( v * (1.0 / abs_range) ); } |
| 56 | |
| 57 | // Set base volume unit of transitions, where 1.0 is a full swing between the |
| 58 | // positive and negative extremes. Not optimized for real-time control. |
| 59 | void volume_unit( double unit ) { impulse.volume_unit( unit ); } |
| 60 | |
| 61 | // Default Blip_Buffer used for output when none is specified for a given call |
| 62 | Blip_Buffer* output() const { return impulse.buf; } |
| 63 | void output( Blip_Buffer* b ) { impulse.buf = b; } |
| 64 | |
| 65 | // Add an amplitude offset (transition) with a magnitude of delta * volume_unit |
| 66 | // into the specified buffer (default buffer if none specified) at the |
| 67 | // specified source time. Delta can be positive or negative. To increase |
| 68 | // performance by inlining code at the call site, use offset_inline(). |
| 69 | void offset( blip_time_t, int delta, Blip_Buffer* ) const; |
| 70 | |
| 71 | void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const; |
| 72 | void offset_resampled( blip_resampled_time_t t, int o ) const { |
| 73 | offset_resampled( t, o, impulse.buf ); |
| 74 | } |
| 75 | void offset( blip_time_t t, int delta ) const { |
| 76 | offset( t, delta, impulse.buf ); |
| 77 | } |
| 78 | void offset_inline( blip_time_t time, int delta, Blip_Buffer* buf ) const { |
| 79 | offset_resampled( time * buf->factor_ + buf->offset_, delta, buf ); |
| 80 | } |
| 81 | void offset_inline( blip_time_t time, int delta ) const { |
| 82 | offset_inline( time, delta, impulse.buf ); |
| 83 | } |
| 84 | }; |
| 85 | |
| 86 | // Blip_Wave is a synthesizer for adding a *single* waveform to a Blip_Buffer. |
| 87 | // A wave is built from a series of delays and new amplitudes. This provides a |
| 88 | // simpler interface than Blip_Synth, nothing more. |
| 89 | template<int quality,int range> |
| 90 | class Blip_Wave { |
| 91 | Blip_Synth<quality,range> synth; |
| 92 | blip_time_t time_; |
| 93 | int last_amp; |
| 94 | public: |
| 95 | // Start wave at time 0 and amplitude 0 |
| 96 | Blip_Wave() : time_( 0 ), last_amp( 0 ) { } |
| 97 | |
| 98 | // See Blip_Synth for description |
| 99 | void volume( double v ) { synth.volume( v ); } |
| 100 | void volume_unit( double v ) { synth.volume_unit( v ); } |
| 101 | void treble_eq( const blip_eq_t& eq){ synth.treble_eq( eq ); } |
| 102 | Blip_Buffer* output() const { return synth.output(); } |
| 103 | void output( Blip_Buffer* b ) { synth.output( b ); if ( !b ) time_ = last_amp = 0; } |
| 104 | |
| 105 | // Current time in frame |
| 106 | blip_time_t time() const { return time_; } |
| 107 | void time( blip_time_t t ) { time_ = t; } |
| 108 | |
| 109 | // Current amplitude of wave |
| 110 | int amplitude() const { return last_amp; } |
| 111 | void amplitude( int ); |
| 112 | |
| 113 | // Move forward by 't' time units |
| 114 | void delay( blip_time_t t ) { time_ += t; } |
| 115 | |
| 116 | // End time frame of specified duration. Localize time to new frame. |
| 117 | void end_frame( blip_time_t duration ) { |
| 118 | assert(( "Blip_Wave::end_frame(): Wave hadn't yet been run for entire frame" , |
| 119 | duration <= time_ )); |
| 120 | time_ -= duration; |
| 121 | } |
| 122 | }; |
| 123 | |
| 124 | |
| 125 | // End of public interface |
| 126 | |
| 127 | template<int quality,int range> |
| 128 | void Blip_Wave<quality,range>::amplitude( int amp ) { |
| 129 | int delta = amp - last_amp; |
| 130 | last_amp = amp; |
| 131 | synth.offset_inline( time_, delta ); |
| 132 | } |
| 133 | |
| 134 | template<int quality,int range> |
| 135 | inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time, |
| 136 | int delta, Blip_Buffer* blip_buf ) const |
| 137 | { |
| 138 | typedef blip_pair_t_ pair_t; |
| 139 | |
| 140 | unsigned sample_index = (time >> BLIP_BUFFER_ACCURACY) & ~1; |
| 141 | assert(( "Blip_Synth/Blip_wave: Went past end of buffer" , |
| 142 | sample_index < blip_buf->buffer_size_ )); |
| 143 | enum { const_offset = Blip_Buffer::widest_impulse_ / 2 - width / 2 }; |
| 144 | pair_t* buf = (pair_t*) &blip_buf->buffer_ [const_offset + sample_index]; |
| 145 | |
| 146 | enum { shift = BLIP_BUFFER_ACCURACY - blip_res_bits_ }; |
| 147 | enum { mask = res * 2 - 1 }; |
| 148 | const pair_t* imp = &impulses [((time >> shift) & mask) * impulse_size]; |
| 149 | |
| 150 | pair_t offset = impulse.offset * delta; |
| 151 | |
| 152 | if ( !fine_bits ) |
| 153 | { |
| 154 | // normal mode |
| 155 | for ( int n = width / 4; n; --n ) |
| 156 | { |
| 157 | pair_t t0 = buf [0] - offset; |
| 158 | pair_t t1 = buf [1] - offset; |
| 159 | |
| 160 | t0 += imp [0] * delta; |
| 161 | t1 += imp [1] * delta; |
| 162 | imp += 2; |
| 163 | |
| 164 | buf [0] = t0; |
| 165 | buf [1] = t1; |
| 166 | buf += 2; |
| 167 | } |
| 168 | } |
| 169 | else |
| 170 | { |
| 171 | // fine mode |
| 172 | enum { sub_range = 1 << fine_bits }; |
| 173 | delta += sub_range / 2; |
| 174 | int delta2 = (delta & (sub_range - 1)) - sub_range / 2; |
| 175 | delta >>= fine_bits; |
| 176 | |
| 177 | for ( int n = width / 4; n; --n ) |
| 178 | { |
| 179 | pair_t t0 = buf [0] - offset; |
| 180 | pair_t t1 = buf [1] - offset; |
| 181 | |
| 182 | t0 += imp [0] * delta2; |
| 183 | t0 += imp [1] * delta; |
| 184 | |
| 185 | t1 += imp [2] * delta2; |
| 186 | t1 += imp [3] * delta; |
| 187 | |
| 188 | imp += 4; |
| 189 | |
| 190 | buf [0] = t0; |
| 191 | buf [1] = t1; |
| 192 | buf += 2; |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | template<int quality,int range> |
| 198 | void Blip_Synth<quality,range>::offset( blip_time_t time, int delta, Blip_Buffer* buf ) const { |
| 199 | offset_resampled( time * buf->factor_ + buf->offset_, delta, buf ); |
| 200 | } |
| 201 | |
| 202 | #endif |
| 203 | |
| 204 | |