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 | |