@@ -70,7 +70,8 @@ struct GeneratorSample {
70
70
uint8_t flags;
71
71
};
72
72
73
- const uint16_t kBlockSize = 16 ;
73
+ const size_t kNumBlocks = 2 ;
74
+ const size_t kBlockSize = 16 ;
74
75
75
76
struct FrequencyRatio {
76
77
uint32_t p;
@@ -113,11 +114,6 @@ class Generator {
113
114
}
114
115
115
116
void set_slope (int16_t slope) {
116
- #ifndef WAVETABLE_HACK
117
- if (range_ == GENERATOR_RANGE_HIGH) {
118
- CONSTRAIN (slope, -32512 , 32512 );
119
- }
120
- #endif // WAVETABLE_HACK
121
117
slope_ = slope;
122
118
}
123
119
@@ -129,10 +125,6 @@ class Generator {
129
125
frequency_ratio_ = ratio;
130
126
}
131
127
132
- void set_waveshaper_antialiasing (bool antialiasing) {
133
- antialiasing_ = antialiasing;
134
- }
135
-
136
128
void set_sync (bool sync) {
137
129
if (!sync_ && sync ) {
138
130
pattern_predictor_.Init ();
@@ -145,51 +137,56 @@ class Generator {
145
137
inline GeneratorRange range () const { return range_; }
146
138
inline bool sync () const { return sync_; }
147
139
148
- inline GeneratorSample Process (uint8_t control) {
149
- input_buffer_.Overwrite (control);
150
- return output_buffer_.ImmediateRead ();
140
+ inline const GeneratorSample& Process (uint8_t control) {
141
+ input_samples_[playback_block_][current_sample_] = control;
142
+ const GeneratorSample& out = output_samples_[playback_block_][current_sample_];
143
+ current_sample_ = current_sample_ + 1 ;
144
+ if (current_sample_ >= kBlockSize ) {
145
+ current_sample_ = 0 ;
146
+ playback_block_ = (playback_block_ + 1 ) % kNumBlocks ;
147
+ }
148
+ return out;
151
149
}
152
150
153
151
inline bool writable_block () const {
154
- return output_buffer_. writable () >= kBlockSize ;
152
+ return render_block_ != playback_block_ ;
155
153
}
156
154
157
- inline bool FillBufferSafe () {
158
- if (!writable_block ()) {
159
- return false ;
160
- } else {
161
- FillBuffer ();
162
- return true ;
155
+ inline void Process () {
156
+ while (render_block_ != playback_block_) {
157
+ uint8_t * in = input_samples_[render_block_];
158
+ GeneratorSample* out = output_samples_[render_block_];
159
+ #ifndef WAVETABLE_HACK
160
+ if (range_ == GENERATOR_RANGE_HIGH) {
161
+ ProcessAudioRate (in, out, kBlockSize );
162
+ } else {
163
+ ProcessControlRate (in, out, kBlockSize );
164
+ }
165
+ ProcessFilterWavefolder (out, kBlockSize );
166
+ #else
167
+ ProcessWavetable (in, out, kBlockSize );
168
+ #endif
169
+ render_block_ = (render_block_ + 1 ) % kNumBlocks ;
163
170
}
164
171
}
165
172
166
- inline void FillBuffer () {
167
- #ifndef WAVETABLE_HACK
168
- if (range_ == GENERATOR_RANGE_HIGH) {
169
- FillBufferAudioRate ();
170
- } else {
171
- FillBufferControlRate ();
172
- }
173
- #else
174
- FillBufferWavetable ();
175
- #endif
176
- }
177
-
178
173
uint32_t clock_divider () const {
179
174
return clock_divider_;
180
175
}
181
176
182
177
private:
183
178
// There are two versions of the rendering code, one optimized for audio, with
184
179
// band-limiting.
185
- void FillBufferAudioRate ();
186
- void FillBufferControlRate ();
187
- void FillBufferWavetable ();
180
+ void ProcessAudioRate (const uint8_t * in, GeneratorSample* out, size_t size);
181
+ void ProcessControlRate (const uint8_t * in, GeneratorSample* out, size_t size);
182
+ void ProcessWavetable (const uint8_t * in, GeneratorSample* out, size_t size);
183
+ void ProcessFilterWavefolder (GeneratorSample* in_out, size_t size);
184
+
188
185
int32_t ComputeAntialiasAttenuation (
189
186
int16_t pitch,
190
187
int16_t slope,
191
188
int16_t shape,
192
- int16_t smoothness);
189
+ int16_t smoothness) const ;
193
190
194
191
inline void ClearFilterState () {
195
192
uni_lp_state_[0 ] = uni_lp_state_[1 ] = 0 ;
@@ -201,12 +198,37 @@ class Generator {
201
198
int32_t ComputeCutoffFrequency (int16_t pitch, int16_t smoothness);
202
199
void ComputeFrequencyRatio (int16_t pitch);
203
200
204
- stmlib::RingBuffer<uint8_t , kBlockSize * 2 > input_buffer_;
205
- stmlib::RingBuffer<GeneratorSample, kBlockSize * 2 > output_buffer_;
206
-
201
+ inline int32_t NextIntegratedBlepSample (uint32_t t) const {
202
+ if (t >= 65535 ) {
203
+ t = 65535 ;
204
+ }
205
+ const int32_t t1 = t >> 1 ;
206
+ const int32_t t2 = t1 * t1 >> 16 ;
207
+ const int32_t t4 = t2 * t2 >> 16 ;
208
+ return 12288 - t1 + (3 * t2 >> 1 ) - t4;
209
+ }
210
+
211
+ inline int32_t ThisIntegratedBlepSample (uint32_t t) const {
212
+ if (t >= 65535 ) {
213
+ t = 65535 ;
214
+ }
215
+ t = 65535 - t;
216
+ const int32_t t1 = t >> 1 ;
217
+ const int32_t t2 = t1 * t1 >> 16 ;
218
+ const int32_t t4 = t2 * t2 >> 16 ;
219
+ return 12288 - t1 + (3 * t2 >> 1 ) - t4;
220
+ }
221
+
222
+ GeneratorSample output_samples_[kNumBlocks ][kBlockSize ];
223
+ uint8_t input_samples_[kNumBlocks ][kBlockSize ];
224
+ size_t current_sample_;
225
+ volatile size_t playback_block_;
226
+ volatile size_t render_block_;
227
+
207
228
GeneratorMode mode_;
208
229
GeneratorRange range_;
209
230
GeneratorSample previous_sample_;
231
+ GeneratorSample buffer_[kBlockSize ];
210
232
211
233
uint32_t clock_divider_;
212
234
@@ -217,11 +239,10 @@ class Generator {
217
239
int16_t slope_;
218
240
int32_t smoothed_slope_;
219
241
int16_t smoothness_;
220
- bool antialiasing_ ;
242
+ int16_t attenuation_ ;
221
243
222
244
uint32_t phase_;
223
245
uint32_t phase_increment_;
224
- uint32_t sub_phase_;
225
246
uint16_t x_;
226
247
uint16_t y_;
227
248
uint16_t z_;
@@ -245,6 +266,11 @@ class Generator {
245
266
246
267
bool running_;
247
268
269
+ // Polyblep status.
270
+ int32_t next_sample_;
271
+ bool slope_up_;
272
+ uint32_t mid_point_;
273
+
248
274
static const FrequencyRatio frequency_ratios_[];
249
275
static const int16_t num_frequency_ratios_;
250
276
0 commit comments