1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
|
/*----------------------------------------------------------------------------
*
* File:
* eas_reverbdata.h
*
* Contents and purpose:
* Contains the prototypes for the Reverb effect.
*
*
* Copyright Sonic Network Inc. 2006
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*----------------------------------------------------------------------------
* Revision Control:
* $Revision: 499 $
* $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $
*----------------------------------------------------------------------------
*/
#ifndef _EAS_REVERBDATA_H
#define _EAS_REVERBDATA_H
#include "eas_types.h"
#include "eas_audioconst.h"
/*------------------------------------
* defines
*------------------------------------
*/
/*
CIRCULAR() calculates the array index using modulo arithmetic.
The "trick" is that modulo arithmetic is simplified by masking
the effective address where the mask is (2^n)-1. This only works
if the buffer size is a power of two.
*/
#define CIRCULAR(base,offset,size) (EAS_U32)( \
( \
((EAS_I32)(base)) + ((EAS_I32)(offset)) \
) \
& size \
)
/* reverb parameters are updated every 2^(REVERB_UPDATE_PERIOD_IN_BITS) samples */
#if defined (_SAMPLE_RATE_8000)
#define REVERB_UPDATE_PERIOD_IN_BITS 5
#define REVERB_BUFFER_SIZE_IN_SAMPLES 2048
#elif defined (_SAMPLE_RATE_16000)
#define REVERB_UPDATE_PERIOD_IN_BITS 6
#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096
#elif defined (_SAMPLE_RATE_22050)
#define REVERB_UPDATE_PERIOD_IN_BITS 7
#define REVERB_BUFFER_SIZE_IN_SAMPLES 4096
#elif defined (_SAMPLE_RATE_32000)
#define REVERB_UPDATE_PERIOD_IN_BITS 7
#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192
#elif defined (_SAMPLE_RATE_44100)
#define REVERB_UPDATE_PERIOD_IN_BITS 8
#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192
#elif defined (_SAMPLE_RATE_48000)
#define REVERB_UPDATE_PERIOD_IN_BITS 8
#define REVERB_BUFFER_SIZE_IN_SAMPLES 8192
#endif
// Define a mask for circular addressing, so that array index
// can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1)
// The buffer size MUST be a power of two
#define REVERB_BUFFER_MASK (REVERB_BUFFER_SIZE_IN_SAMPLES -1)
#define REVERB_MAX_ROOM_TYPE 4 // any room numbers larger than this are invalid
#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel
/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */
#define REVERB_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(0x1L << REVERB_UPDATE_PERIOD_IN_BITS)
/*
calculate the update counter by bitwise ANDING with this value to
generate a 2^n modulo value
*/
#define REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES (EAS_I32)(REVERB_UPDATE_PERIOD_IN_SAMPLES -1)
/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SECONDS seconds */
#define REVERB_UPDATE_PERIOD_IN_SECONDS (REVERB_UPDATE_PERIOD_IN_SAMPLES / _OUTPUT_SAMPLE_RATE)
// xfade parameters
#define REVERB_XFADE_PERIOD_IN_SECONDS (100.0 / 1000.0) // xfade once every this many seconds
#define REVERB_XFADE_PERIOD_IN_SAMPLES (REVERB_XFADE_PERIOD_IN_SECONDS * _OUTPUT_SAMPLE_RATE)
#define REVERB_XFADE_PHASE_INCREMENT (EAS_I16)(65536 / ((EAS_I16)REVERB_XFADE_PERIOD_IN_SAMPLES/(EAS_I16)REVERB_UPDATE_PERIOD_IN_SAMPLES))
/**********/
/* the entire synth uses various flags in a bit field */
/* if flag is set, synth reset has been requested */
#define REVERB_FLAG_RESET_IS_REQUESTED 0x01 /* bit 0 */
#define MASK_REVERB_RESET_IS_REQUESTED 0x01
#define MASK_REVERB_RESET_IS_NOT_REQUESTED (EAS_U32)(~MASK_REVERB_RESET_IS_REQUESTED)
/*
by default, we always want to update ALL channel parameters
when we reset the synth (e.g., during GM ON)
*/
#define DEFAULT_REVERB_FLAGS 0x0
/* coefficients for generating sin, cos */
#define REVERB_PAN_G2 4294940151 /* -0.82842712474619 = 2 - 4/sqrt(2) */
/*
EAS_I32 nPanG1 = +1.0 for sin
EAS_I32 nPanG1 = -1.0 for cos
*/
#define REVERB_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */
/*************************************************************/
// define the input injection points
#define GUARD 5 // safety guard of this many samples
#define MAX_AP_TIME (double) (20.0/1000.0) // delay time in milliseconds
#define MAX_DELAY_TIME (double) (65.0/1000.0) // delay time in milliseconds
#define MAX_AP_SAMPLES (int)(((double) MAX_AP_TIME) * ((double) _OUTPUT_SAMPLE_RATE))
#define MAX_DELAY_SAMPLES (int)(((double) MAX_DELAY_TIME) * ((double) _OUTPUT_SAMPLE_RATE))
#define AP0_IN 0
#define AP1_IN (AP0_IN + MAX_AP_SAMPLES + GUARD)
#define DELAY0_IN (AP1_IN + MAX_AP_SAMPLES + GUARD)
#define DELAY1_IN (DELAY0_IN + MAX_DELAY_SAMPLES + GUARD)
// Define the max offsets for the end points of each section
// i.e., we don't expect a given section's taps to go beyond
// the following limits
#define AP0_OUT (AP0_IN + MAX_AP_SAMPLES -1)
#define AP1_OUT (AP1_IN + MAX_AP_SAMPLES -1)
#define DELAY0_OUT (DELAY0_IN + MAX_DELAY_SAMPLES -1)
#define DELAY1_OUT (DELAY1_IN + MAX_DELAY_SAMPLES -1)
#define REVERB_DEFAULT_ROOM_NUMBER 1 // default preset number
#define DEFAULT_AP0_LENGTH (int)(((double) (17.0/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE))
#define DEFAULT_AP0_GAIN 19400
#define DEFAULT_AP1_LENGTH (int)(((double) (16.5/1000.0)) * ((double) _OUTPUT_SAMPLE_RATE))
#define DEFAULT_AP1_GAIN -19400
#define REVERB_DEFAULT_WET 32767
#define REVERB_DEFAULT_DRY 0
#define EAS_REVERB_WET_MAX 32767
#define EAS_REVERB_WET_MIN 0
#define EAS_REVERB_DRY_MAX 32767
#define EAS_REVERB_DRY_MIN 0
/* parameters for each allpass */
typedef struct
{
EAS_U16 m_zApOut; // delay offset for ap out
EAS_I16 m_nApGain; // gain for ap
EAS_U16 m_zApIn; // delay offset for ap in
} S_ALLPASS_OBJECT;
/* parameters for each allpass */
typedef struct
{
EAS_PCM m_zLpf; // actual state variable, not a length
EAS_I16 m_nLpfFwd; // lpf forward gain
EAS_I16 m_nLpfFbk; // lpf feedback gain
EAS_U16 m_zDelay[REVERB_MAX_NUM_REFLECTIONS]; // delay offset for ap out
EAS_I16 m_nGain[REVERB_MAX_NUM_REFLECTIONS]; // gain for ap
} S_EARLY_REFLECTION_OBJECT;
//demo
typedef struct
{
EAS_I16 m_nLpfFbk;
EAS_I16 m_nLpfFwd;
EAS_I16 m_nEarly;
EAS_I16 m_nWet;
EAS_I16 m_nDry;
EAS_I16 m_nEarlyL_LpfFbk;
EAS_I16 m_nEarlyL_LpfFwd;
EAS_I16 m_nEarlyL_Delay0; //8
EAS_I16 m_nEarlyL_Gain0;
EAS_I16 m_nEarlyL_Delay1;
EAS_I16 m_nEarlyL_Gain1;
EAS_I16 m_nEarlyL_Delay2;
EAS_I16 m_nEarlyL_Gain2;
EAS_I16 m_nEarlyL_Delay3;
EAS_I16 m_nEarlyL_Gain3;
EAS_I16 m_nEarlyL_Delay4;
EAS_I16 m_nEarlyL_Gain4;
EAS_I16 m_nEarlyR_Delay0; //18
EAS_I16 m_nEarlyR_Gain0;
EAS_I16 m_nEarlyR_Delay1;
EAS_I16 m_nEarlyR_Gain1;
EAS_I16 m_nEarlyR_Delay2;
EAS_I16 m_nEarlyR_Gain2;
EAS_I16 m_nEarlyR_Delay3;
EAS_I16 m_nEarlyR_Gain3;
EAS_I16 m_nEarlyR_Delay4;
EAS_I16 m_nEarlyR_Gain4;
EAS_U16 m_nMaxExcursion; //28
EAS_I16 m_nXfadeInterval;
EAS_I16 m_nAp0_ApGain; //30
EAS_I16 m_nAp0_ApOut;
EAS_I16 m_nAp1_ApGain;
EAS_I16 m_nAp1_ApOut;
EAS_I16 m_rfu4;
EAS_I16 m_rfu5;
EAS_I16 m_rfu6;
EAS_I16 m_rfu7;
EAS_I16 m_rfu8;
EAS_I16 m_rfu9;
EAS_I16 m_rfu10; //43
} S_REVERB_PRESET;
typedef struct
{
S_REVERB_PRESET m_sPreset[REVERB_MAX_ROOM_TYPE]; //array of presets
} S_REVERB_PRESET_BANK;
/* parameters for each reverb */
typedef struct
{
/* controls entire reverb playback volume */
/* to conserve memory, use the MSB and ignore the LSB */
EAS_U8 m_nMasterVolume;
/* update counter keeps track of when synth params need updating */
/* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */
EAS_I16 m_nUpdateCounter;
EAS_U16 m_nMinSamplesToAdd; /* ComputeReverb() generates this many samples */
EAS_U8 m_nFlags; /* misc flags/bit fields */
EAS_PCM *m_pOutputBuffer;
EAS_PCM *m_pInputBuffer;
EAS_U16 m_nNumSamplesInOutputBuffer;
EAS_U16 m_nNumSamplesInInputBuffer;
EAS_U16 m_nNumInputSamplesRead; // if m_nNumInputSamplesRead >= NumSamplesInInputBuffer
// then get a new input buffer
EAS_PCM *m_pNextInputSample;
EAS_U16 m_nBaseIndex; // base index for circular buffer
// reverb delay line offsets, allpass parameters, etc:
EAS_PCM m_nRevOutFbkR; // combine feedback reverb right out with dry left in
S_ALLPASS_OBJECT m_sAp0; // allpass 0 (left channel)
EAS_U16 m_zD0In; // delay offset for delay line D0 in
EAS_PCM m_nRevOutFbkL; // combine feedback reverb left out with dry right in
S_ALLPASS_OBJECT m_sAp1; // allpass 1 (right channel)
EAS_U16 m_zD1In; // delay offset for delay line D1 in
// delay output taps, notice criss cross order
EAS_U16 m_zD0Self; // self feeds forward d0 --> d0
EAS_U16 m_zD1Cross; // cross feeds across d1 --> d0
EAS_PCM m_zLpf0; // actual state variable, not a length
EAS_U16 m_zD1Self; // self feeds forward d1 --> d1
EAS_U16 m_zD0Cross; // cross feeds across d0 --> d1
EAS_PCM m_zLpf1; // actual state variable, not a length
EAS_I16 m_nSin; // gain for self taps
EAS_I16 m_nCos; // gain for cross taps
EAS_I16 m_nSinIncrement; // increment for gain
EAS_I16 m_nCosIncrement; // increment for gain
EAS_I16 m_nLpfFwd; // lpf forward gain (includes scaling for mixer)
EAS_I16 m_nLpfFbk; // lpf feedback gain
EAS_U16 m_nXfadeInterval; // update/xfade after this many samples
EAS_U16 m_nXfadeCounter; // keep track of when to xfade
EAS_I16 m_nPhase; // -1 <= m_nPhase < 1
// but during sin,cos calculations
// use m_nPhase/2
EAS_I16 m_nPhaseIncrement; // add this to m_nPhase each frame
EAS_I16 m_nNoise; // random noise sample
EAS_U16 m_nMaxExcursion; // the taps can excurse +/- this amount
EAS_BOOL m_bUseNoise; // if EAS_TRUE, use noise as input signal
EAS_BOOL m_bBypass; // if EAS_TRUE, then bypass reverb and copy input to output
EAS_I16 m_nCurrentRoom; // preset number for current room
EAS_I16 m_nNextRoom; // preset number for next room
EAS_I16 m_nWet; // gain for wet (processed) signal
EAS_I16 m_nDry; // gain for dry (unprocessed) signal
EAS_I16 m_nEarly; // gain for early (widen) signal
S_EARLY_REFLECTION_OBJECT m_sEarlyL; // left channel early reflections
S_EARLY_REFLECTION_OBJECT m_sEarlyR; // right channel early reflections
EAS_PCM m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES]; // one large delay line for all reverb elements
S_REVERB_PRESET pPreset;
S_REVERB_PRESET_BANK m_sPreset;
//EAS_I8 preset;
} S_REVERB_OBJECT;
/*------------------------------------
* prototypes
*------------------------------------
*/
/*----------------------------------------------------------------------------
* ReverbUpdateXfade
*----------------------------------------------------------------------------
* Purpose:
* Update the xfade parameters as required
*
* Inputs:
* nNumSamplesToAdd - number of samples to write to buffer
*
* Outputs:
*
*
* Side Effects:
* - xfade parameters will be changed
*
*----------------------------------------------------------------------------
*/
static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd);
/*----------------------------------------------------------------------------
* ReverbCalculateNoise
*----------------------------------------------------------------------------
* Purpose:
* Calculate a noise sample and limit its value
*
* Inputs:
* nMaxExcursion - noise value is limited to this value
* pnNoise - return new noise sample in this (not limited)
*
* Outputs:
* new limited noise value
*
* Side Effects:
* - *pnNoise noise value is updated
*
*----------------------------------------------------------------------------
*/
static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise);
/*----------------------------------------------------------------------------
* ReverbCalculateSinCos
*----------------------------------------------------------------------------
* Purpose:
* Calculate a new sin and cosine value based on the given phase
*
* Inputs:
* nPhase - phase angle
* pnSin - input old value, output new value
* pnCos - input old value, output new value
*
* Outputs:
*
* Side Effects:
* - *pnSin, *pnCos are updated
*
*----------------------------------------------------------------------------
*/
static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos);
/*----------------------------------------------------------------------------
* Reverb
*----------------------------------------------------------------------------
* Purpose:
* apply reverb to the given signal
*
* Inputs:
* nNu
* pnSin - input old value, output new value
* pnCos - input old value, output new value
*
* Outputs:
* number of samples actually reverberated
*
* Side Effects:
*
*----------------------------------------------------------------------------
*/
static EAS_RESULT Reverb(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer);
/*----------------------------------------------------------------------------
* ReverbReadInPresets()
*----------------------------------------------------------------------------
* Purpose: sets global reverb preset bank to defaults
*
* Inputs:
*
* Outputs:
*
*----------------------------------------------------------------------------
*/
static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT* pReverbData);
/*----------------------------------------------------------------------------
* ReverbUpdateRoom
*----------------------------------------------------------------------------
* Purpose:
* Update the room's preset parameters as required
*
* Inputs:
*
* Outputs:
*
*
* Side Effects:
* - reverb paramters (fbk, fwd, etc) will be changed
* - m_nCurrentRoom := m_nNextRoom
*----------------------------------------------------------------------------
*/
static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT* pReverbData);
#endif /* #ifndef _EAS_REVERBDATA_H */
|