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.
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;
47public:
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.
89template<int quality,int range>
90class Blip_Wave {
91 Blip_Synth<quality,range> synth;
92 blip_time_t time_;
93 int last_amp;
94public:
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
127template<int quality,int range>
128void 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
134template<int quality,int range>
135inline 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
197template<int quality,int range>
198void 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