Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/fluidsynth/src/rvoice/fluid_rvoice.c
8848 views
1
/* FluidSynth - A Software Synthesizer
2
*
3
* Copyright (C) 2003 Peter Hanappe and others.
4
*
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public License
7
* as published by the Free Software Foundation; either version 2.1 of
8
* the License, or (at your option) any later version.
9
*
10
* This library is distributed in the hope that it will be useful, but
11
* WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
14
*
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free
17
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
* 02110-1301, USA
19
*/
20
21
#include "fluid_rvoice.h"
22
#include "fluid_conv.h"
23
#include "fluid_sys.h"
24
25
26
static void fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks);
27
28
/**
29
* @return -1 if voice is quiet, 0 if voice has finished, 1 otherwise
30
*/
31
static FLUID_INLINE int
32
fluid_rvoice_calc_amp(fluid_rvoice_t *voice)
33
{
34
fluid_real_t target_amp; /* target amplitude */
35
36
if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVDELAY)
37
{
38
return -1; /* The volume amplitude is in hold phase. No sound is produced. */
39
}
40
41
if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
42
{
43
/* the envelope is in the attack section: ramp linearly to max value.
44
* A positive modlfo_to_vol should increase volume (negative attenuation).
45
*/
46
target_amp = fluid_cb2amp(voice->dsp.attenuation)
47
* fluid_cb2amp(fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol)
48
* fluid_adsr_env_get_val(&voice->envlfo.volenv);
49
}
50
else
51
{
52
fluid_real_t amplitude_that_reaches_noise_floor;
53
fluid_real_t amp_max;
54
55
target_amp = fluid_cb2amp(voice->dsp.attenuation)
56
* fluid_cb2amp(FLUID_PEAK_ATTENUATION * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv))
57
+ fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol);
58
59
/* We turn off a voice, if the volume has dropped low enough. */
60
61
/* A voice can be turned off, when an estimate for the volume
62
* (upper bound) falls below that volume, that will drop the
63
* sample below the noise floor.
64
*/
65
66
/* If the loop amplitude is known, we can use it if the voice loop is within
67
* the sample loop
68
*/
69
70
/* Is the playing pointer already in the loop? */
71
if(voice->dsp.has_looped)
72
{
73
amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_loop;
74
}
75
else
76
{
77
amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
78
}
79
80
/* voice->attenuation_min is a lower boundary for the attenuation
81
* now and in the future (possibly 0 in the worst case). Now the
82
* amplitude of sample and volenv cannot exceed amp_max (since
83
* volenv_val can only drop):
84
*/
85
86
amp_max = fluid_cb2amp(voice->dsp.min_attenuation_cB) *
87
fluid_adsr_env_get_val(&voice->envlfo.volenv);
88
89
/* And if amp_max is already smaller than the known amplitude,
90
* which will attenuate the sample below the noise floor, then we
91
* can safely turn off the voice. Duh. */
92
if(amp_max < amplitude_that_reaches_noise_floor)
93
{
94
return 0;
95
}
96
}
97
98
/* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */
99
voice->dsp.amp_incr = (target_amp - voice->dsp.amp) / FLUID_BUFSIZE;
100
101
fluid_check_fpe("voice_write amplitude calculation");
102
103
/* no volume and not changing? - No need to process */
104
if((voice->dsp.amp == 0.0f) && (voice->dsp.amp_incr == 0.0f))
105
{
106
return -1;
107
}
108
109
return 1;
110
}
111
112
113
/* these should be the absolute minimum that FluidSynth can deal with */
114
#define FLUID_MIN_LOOP_SIZE 2
115
#define FLUID_MIN_LOOP_PAD 0
116
117
#define FLUID_SAMPLESANITY_CHECK (1 << 0)
118
#define FLUID_SAMPLESANITY_STARTUP (1 << 1)
119
120
/* Purpose:
121
*
122
* Make sure, that sample start / end point and loop points are in
123
* proper order. When starting up, calculate the initial phase.
124
* TODO: Investigate whether this can be moved from rvoice to voice.
125
*/
126
static void
127
fluid_rvoice_check_sample_sanity(fluid_rvoice_t *voice)
128
{
129
int min_index_nonloop = (int) voice->dsp.sample->start;
130
int max_index_nonloop = (int) voice->dsp.sample->end;
131
132
/* make sure we have enough samples surrounding the loop */
133
int min_index_loop = (int) voice->dsp.sample->start + FLUID_MIN_LOOP_PAD;
134
int max_index_loop = (int) voice->dsp.sample->end - FLUID_MIN_LOOP_PAD + 1; /* 'end' is last valid sample, loopend can be + 1 */
135
fluid_check_fpe("voice_check_sample_sanity start");
136
137
#if 0
138
printf("Sample from %i to %i\n", voice->dsp.sample->start, voice->dsp.sample->end);
139
printf("Sample loop from %i %i\n", voice->dsp.sample->loopstart, voice->dsp.sample->loopend);
140
printf("Playback from %i to %i\n", voice->dsp.start, voice->dsp.end);
141
printf("Playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend);
142
#endif
143
144
/* Keep the start point within the sample data */
145
if(voice->dsp.start < min_index_nonloop)
146
{
147
voice->dsp.start = min_index_nonloop;
148
}
149
else if(voice->dsp.start > max_index_nonloop)
150
{
151
voice->dsp.start = max_index_nonloop;
152
}
153
154
/* Keep the end point within the sample data */
155
if(voice->dsp.end < min_index_nonloop)
156
{
157
voice->dsp.end = min_index_nonloop;
158
}
159
else if(voice->dsp.end > max_index_nonloop)
160
{
161
voice->dsp.end = max_index_nonloop;
162
}
163
164
/* Keep start and end point in the right order */
165
if(voice->dsp.start > voice->dsp.end)
166
{
167
int temp = voice->dsp.start;
168
voice->dsp.start = voice->dsp.end;
169
voice->dsp.end = temp;
170
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
171
}
172
173
/* Zero length? */
174
if(voice->dsp.start == voice->dsp.end)
175
{
176
fluid_rvoice_voiceoff(voice, NULL);
177
return;
178
}
179
180
if((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
181
|| (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE))
182
{
183
/* Keep the loop start point within the sample data */
184
if(voice->dsp.loopstart < min_index_loop)
185
{
186
voice->dsp.loopstart = min_index_loop;
187
}
188
else if(voice->dsp.loopstart > max_index_loop)
189
{
190
voice->dsp.loopstart = max_index_loop;
191
}
192
193
/* Keep the loop end point within the sample data */
194
if(voice->dsp.loopend < min_index_loop)
195
{
196
voice->dsp.loopend = min_index_loop;
197
}
198
else if(voice->dsp.loopend > max_index_loop)
199
{
200
voice->dsp.loopend = max_index_loop;
201
}
202
203
/* Keep loop start and end point in the right order */
204
if(voice->dsp.loopstart > voice->dsp.loopend)
205
{
206
int temp = voice->dsp.loopstart;
207
voice->dsp.loopstart = voice->dsp.loopend;
208
voice->dsp.loopend = temp;
209
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
210
}
211
212
/* Loop too short? Then don't loop. */
213
if(voice->dsp.loopend < voice->dsp.loopstart + FLUID_MIN_LOOP_SIZE)
214
{
215
voice->dsp.samplemode = FLUID_UNLOOPED;
216
}
217
218
/* The loop points may have changed. Obtain a new estimate for the loop volume. */
219
/* Is the voice loop within the sample loop? */
220
if((int)voice->dsp.loopstart >= (int)voice->dsp.sample->loopstart
221
&& (int)voice->dsp.loopend <= (int)voice->dsp.sample->loopend)
222
{
223
/* Is there a valid peak amplitude available for the loop, and can we use it? */
224
if(voice->dsp.sample->amplitude_that_reaches_noise_floor_is_valid && voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)
225
{
226
voice->dsp.amplitude_that_reaches_noise_floor_loop = voice->dsp.sample->amplitude_that_reaches_noise_floor / voice->dsp.synth_gain;
227
}
228
else
229
{
230
/* Worst case */
231
voice->dsp.amplitude_that_reaches_noise_floor_loop = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
232
};
233
};
234
235
} /* if sample mode is looped */
236
237
/* Run startup specific code (only once, when the voice is started) */
238
if(voice->dsp.check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP)
239
{
240
if(max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE)
241
{
242
if((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
243
|| (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE))
244
{
245
voice->dsp.samplemode = FLUID_UNLOOPED;
246
}
247
}
248
249
/* Set the initial phase of the voice (using the result from the
250
start offset modulators). */
251
fluid_phase_set_int(voice->dsp.phase, voice->dsp.start);
252
} /* if startup */
253
254
/* Is this voice run in loop mode, or does it run straight to the
255
end of the waveform data? */
256
if(((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE) &&
257
(fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE))
258
|| (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE))
259
{
260
/* Yes, it will loop as soon as it reaches the loop point. In
261
* this case we must prevent, that the playback pointer (phase)
262
* happens to end up beyond the 2nd loop point, because the
263
* point has moved. The DSP algorithm is unable to cope with
264
* that situation. So if the phase is beyond the 2nd loop
265
* point, set it to the start of the loop. No way to avoid some
266
* noise here. Note: If the sample pointer ends up -before the
267
* first loop point- instead, then the DSP loop will just play
268
* the sample, enter the loop and proceed as expected => no
269
* actions required.
270
*/
271
int index_in_sample = fluid_phase_index(voice->dsp.phase);
272
273
if(index_in_sample >= voice->dsp.loopend)
274
{
275
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
276
fluid_phase_set_int(voice->dsp.phase, voice->dsp.loopstart);
277
}
278
}
279
280
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->dsp.start, voice->dsp.end, voice->dsp.loopstart, voice->dsp.loopend); */
281
282
/* Sample sanity has been assured. Don't check again, until some
283
sample parameter is changed by modulation. */
284
voice->dsp.check_sample_sanity_flag = 0;
285
#if 0
286
printf("Sane? playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend);
287
#endif
288
fluid_check_fpe("voice_check_sample_sanity");
289
}
290
291
292
/**
293
* Synthesize a voice to a buffer.
294
*
295
* @param voice rvoice to synthesize
296
* @param dsp_buf Audio buffer to synthesize to (#FLUID_BUFSIZE in length)
297
* @return Count of samples written to dsp_buf. (-1 means voice is currently
298
* quiet, 0 .. #FLUID_BUFSIZE-1 means voice finished.)
299
*
300
* Panning, reverb and chorus are processed separately. The dsp interpolation
301
* routine is in (fluid_rvoice_dsp.c).
302
*/
303
int
304
fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
305
{
306
int ticks = voice->envlfo.ticks;
307
int count, is_looping;
308
fluid_real_t modenv_val;
309
310
/******************* sample sanity check **********/
311
312
if(!voice->dsp.sample)
313
{
314
return 0;
315
}
316
317
if(voice->dsp.check_sample_sanity_flag)
318
{
319
fluid_rvoice_check_sample_sanity(voice);
320
}
321
322
/******************* noteoff check ****************/
323
324
if(voice->envlfo.noteoff_ticks != 0 &&
325
voice->envlfo.ticks >= voice->envlfo.noteoff_ticks)
326
{
327
fluid_rvoice_noteoff_LOCAL(voice, 0);
328
}
329
330
voice->envlfo.ticks += FLUID_BUFSIZE;
331
332
/******************* vol env **********************/
333
334
fluid_adsr_env_calc(&voice->envlfo.volenv);
335
fluid_check_fpe("voice_write vol env");
336
337
if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVFINISHED)
338
{
339
return 0;
340
}
341
342
/******************* mod env **********************/
343
344
fluid_adsr_env_calc(&voice->envlfo.modenv);
345
fluid_check_fpe("voice_write mod env");
346
347
/******************* lfo **********************/
348
349
fluid_lfo_calc(&voice->envlfo.modlfo, ticks);
350
fluid_check_fpe("voice_write mod LFO");
351
fluid_lfo_calc(&voice->envlfo.viblfo, ticks);
352
fluid_check_fpe("voice_write vib LFO");
353
354
/******************* amplitude **********************/
355
356
count = fluid_rvoice_calc_amp(voice);
357
if(count == 0)
358
{
359
// Voice has finished, remove from dsp loop
360
return 0;
361
}
362
// else if count is negative, still process the voice
363
364
365
/******************* phase **********************/
366
367
/* SF2.04 section 8.1.2 #26:
368
* attack of modEnv is convex ?!?
369
*/
370
modenv_val = (fluid_adsr_env_get_section(&voice->envlfo.modenv) == FLUID_VOICE_ENVATTACK)
371
? fluid_convex(127 * fluid_adsr_env_get_val(&voice->envlfo.modenv))
372
: fluid_adsr_env_get_val(&voice->envlfo.modenv);
373
/* Calculate the number of samples, that the DSP loop advances
374
* through the original waveform with each step in the output
375
* buffer. It is the ratio between the frequencies of original
376
* waveform and output waveform.*/
377
voice->dsp.phase_incr = fluid_ct2hz_real(voice->dsp.pitch +
378
voice->dsp.pitchoffset +
379
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_pitch
380
+ fluid_lfo_get_val(&voice->envlfo.viblfo) * voice->envlfo.viblfo_to_pitch
381
+ modenv_val * voice->envlfo.modenv_to_pitch)
382
/ voice->dsp.root_pitch_hz;
383
384
/******************* portamento ****************/
385
/* pitchoffset is updated if enabled.
386
Pitchoffset will be added to dsp pitch at next phase calculation time */
387
388
/* In most cases portamento will be disabled. Thus first verify that portamento is
389
* enabled before updating pitchoffset and before disabling portamento when necessary,
390
* in order to keep the performance loss at minimum.
391
* If the algorithm would first update pitchoffset and then verify if portamento
392
* needs to be disabled, there would be a significant performance drop on a x87 FPU
393
*/
394
if(voice->dsp.pitchinc > 0.0f)
395
{
396
/* portamento is enabled, so update pitchoffset */
397
voice->dsp.pitchoffset += voice->dsp.pitchinc;
398
399
/* when pitchoffset reaches 0.0f, portamento is disabled */
400
if(voice->dsp.pitchoffset > 0.0f)
401
{
402
voice->dsp.pitchoffset = voice->dsp.pitchinc = 0.0f;
403
}
404
}
405
else if(voice->dsp.pitchinc < 0.0f)
406
{
407
/* portamento is enabled, so update pitchoffset */
408
voice->dsp.pitchoffset += voice->dsp.pitchinc;
409
410
/* when pitchoffset reaches 0.0f, portamento is disabled */
411
if(voice->dsp.pitchoffset < 0.0f)
412
{
413
voice->dsp.pitchoffset = voice->dsp.pitchinc = 0.0f;
414
}
415
}
416
417
fluid_check_fpe("voice_write phase calculation");
418
419
/* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
420
if(voice->dsp.phase_incr == 0)
421
{
422
voice->dsp.phase_incr = 1;
423
}
424
425
/* loop mode release? if not in release, the voice is silent
426
* note: this intentionally processes the volenv before returning silence,
427
* since that's what polyphone does (PR #1400) */
428
if(voice->dsp.samplemode == FLUID_START_ON_RELEASE && fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE)
429
{
430
return -1;
431
}
432
433
/* voice is currently looping? */
434
is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE
435
|| (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
436
&& fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);
437
438
/*************** resonant filter ******************/
439
// Only "prepare" the filter here, the filter itself will be applied in the dsp_interpolation routines below.
440
// This is to satisfy SF2 Section 9.1.8, particularly, the filtered output must be gain-adjusted by the volEnv.
441
// Applying the filter after applying the gain from the volEnv might cause audible clicks for when turning off
442
// voices that are filtered by a high Q, see https://github.com/FluidSynth/fluidsynth/issues/1427
443
//
444
// Note that at this point we are using voice->dsp.output_rate which is set to the synth's output rate, because
445
// the filter will receive the interpolated waveform.
446
447
fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
448
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
449
modenv_val * voice->envlfo.modenv_to_fc);
450
451
/* additional custom filter - only uses the fixed modulator, no lfos... */
452
fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0);
453
454
/*********************** run the dsp chain ************************
455
* The sample is mixed with the output buffer.
456
* The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
457
* Depending on the position in the loop and the loop size, this
458
* may require several runs. */
459
460
if(count < 0)
461
{
462
// The voice is quite, i.e. either in delay phase or zero volume.
463
// We need to update the rvoice's dsp phase, as the delay phase shall not "postpone" the sound, rather
464
// it should be played silently, see https://github.com/FluidSynth/fluidsynth/issues/1312
465
//
466
// Currently, this does access the sample buffers, which is redundant and could be optimized away.
467
// On the other hand, entering this if-clause is not supposed to happen often.
468
return fluid_rvoice_dsp_interpolate_none(voice, dsp_buf, is_looping);
469
}
470
471
switch(voice->dsp.interp_method)
472
{
473
case FLUID_INTERP_NONE:
474
count = fluid_rvoice_dsp_interpolate_none(voice, dsp_buf, is_looping);
475
break;
476
477
case FLUID_INTERP_LINEAR:
478
count = fluid_rvoice_dsp_interpolate_linear(voice, dsp_buf, is_looping);
479
break;
480
481
case FLUID_INTERP_4THORDER:
482
default:
483
count = fluid_rvoice_dsp_interpolate_4th_order(voice, dsp_buf, is_looping);
484
break;
485
486
case FLUID_INTERP_7THORDER:
487
count = fluid_rvoice_dsp_interpolate_7th_order(voice, dsp_buf, is_looping);
488
break;
489
}
490
491
fluid_check_fpe("voice_write interpolation");
492
493
if(count == 0)
494
{
495
// voice has finished
496
return count;
497
}
498
499
return count;
500
}
501
502
/**
503
* Initialize buffers up to (and including) bufnum
504
*/
505
static int
506
fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t *buffers, unsigned int bufnum)
507
{
508
unsigned int i;
509
510
if(bufnum < buffers->count)
511
{
512
return FLUID_OK;
513
}
514
515
if(bufnum >= FLUID_RVOICE_MAX_BUFS)
516
{
517
return FLUID_FAILED;
518
}
519
520
for(i = buffers->count; i <= bufnum; i++)
521
{
522
buffers->bufs[i].target_amp = 0.0f;
523
buffers->bufs[i].current_amp = 0.0f;
524
}
525
526
buffers->count = bufnum + 1;
527
return FLUID_OK;
528
}
529
530
531
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp)
532
{
533
fluid_rvoice_buffers_t *buffers = obj;
534
unsigned int bufnum = param[0].i;
535
fluid_real_t value = param[1].real;
536
537
if(fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
538
{
539
return;
540
}
541
542
buffers->bufs[bufnum].target_amp = value;
543
}
544
545
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping)
546
{
547
fluid_rvoice_buffers_t *buffers = obj;
548
unsigned int bufnum = param[0].i;
549
int mapping = param[1].i;
550
551
if(fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
552
{
553
return;
554
}
555
556
buffers->bufs[bufnum].mapping = mapping;
557
}
558
559
560
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_reset)
561
{
562
fluid_rvoice_t *voice = obj;
563
564
voice->dsp.has_looped = 0;
565
voice->envlfo.ticks = 0;
566
voice->envlfo.noteoff_ticks = 0;
567
voice->dsp.amp = 0.0f; /* The last value of the volume envelope, used to
568
calculate the volume increment during
569
processing */
570
571
/* legato initialization */
572
voice->dsp.pitchoffset = 0.0; /* portamento initialization */
573
voice->dsp.pitchinc = 0.0;
574
575
/* mod env initialization*/
576
fluid_adsr_env_reset(&voice->envlfo.modenv);
577
578
/* vol env initialization */
579
fluid_adsr_env_reset(&voice->envlfo.volenv);
580
581
/* Fixme: Retrieve from any other existing
582
voice on this channel to keep LFOs in
583
unison? */
584
fluid_lfo_reset(&voice->envlfo.viblfo);
585
fluid_lfo_reset(&voice->envlfo.modlfo);
586
587
/* Clear sample history in filter */
588
fluid_iir_filter_reset(&voice->resonant_filter);
589
fluid_iir_filter_reset(&voice->resonant_custom_filter);
590
591
/* Force setting of the phase at the first DSP loop run
592
* This cannot be done earlier, because it depends on modulators.
593
[DH] Is that comment really true? */
594
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
595
}
596
597
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_noteoff)
598
{
599
fluid_rvoice_t *rvoice = obj;
600
unsigned int min_ticks = param[0].i;
601
602
fluid_rvoice_noteoff_LOCAL(rvoice, min_ticks);
603
}
604
605
static void
606
fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks)
607
{
608
if(min_ticks > voice->envlfo.ticks)
609
{
610
/* Delay noteoff */
611
voice->envlfo.noteoff_ticks = min_ticks;
612
return;
613
}
614
615
voice->envlfo.noteoff_ticks = 0;
616
617
if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
618
{
619
/* A voice is turned off during the attack section of the volume
620
* envelope. The attack section ramps up linearly with
621
* amplitude. The other sections use logarithmic scaling. Calculate new
622
* volenv_val to achieve equivalent amplitude during the release phase
623
* for seamless volume transition.
624
*/
625
if(fluid_adsr_env_get_val(&voice->envlfo.volenv) > 0)
626
{
627
fluid_real_t lfo = fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol;
628
fluid_real_t amp = fluid_adsr_env_get_val(&voice->envlfo.volenv) * fluid_cb2amp(lfo);
629
fluid_real_t env_value = - (((-200.f / FLUID_M_LN10) * FLUID_LOGF(amp) - lfo) / FLUID_PEAK_ATTENUATION - 1);
630
fluid_clip(env_value, 0.0f, 1.0f);
631
fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value);
632
}
633
}
634
635
if(fluid_adsr_env_get_section(&voice->envlfo.modenv) == FLUID_VOICE_ENVATTACK)
636
{
637
/* A voice is turned off during the attack section of the modulation
638
* envelope. The attack section use convex scaling with pitch and filter
639
* frequency cutoff (see fluid_rvoice_write(): modenv_val = fluid_convex(127 * modenv.val)
640
* The other sections use linear scaling: modenv_val = modenv.val
641
*
642
* Calculate new modenv.val to achieve equivalent modenv_val during the release phase
643
* for seamless pitch and filter frequency cutoff transition.
644
*/
645
if(fluid_adsr_env_get_val(&voice->envlfo.modenv) > 0)
646
{
647
fluid_real_t env_value = fluid_convex(127 * fluid_adsr_env_get_val(&voice->envlfo.modenv));
648
fluid_clip(env_value, 0.0, 1.0);
649
fluid_adsr_env_set_val(&voice->envlfo.modenv, env_value);
650
}
651
}
652
653
fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVRELEASE);
654
fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVRELEASE);
655
}
656
657
/**
658
* skips to Attack section
659
*
660
* Updates vol and attack data
661
* Correction on volume val to achieve equivalent amplitude at noteOn legato
662
*
663
* @param voice the synthesis voice to be updated
664
*/
665
static FLUID_INLINE void fluid_rvoice_local_retrigger_attack(fluid_rvoice_t *voice)
666
{
667
/* skips to Attack section */
668
/* Once in Attack section, current count must be reset, to be sure
669
that the section will be not be prematurely finished. */
670
fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVATTACK);
671
{
672
/* Correction on volume val to achieve equivalent amplitude at noteOn legato */
673
fluid_env_data_t *env_data;
674
fluid_real_t peak = fluid_cb2amp(voice->dsp.attenuation);
675
fluid_real_t prev_peak = fluid_cb2amp(voice->dsp.prev_attenuation);
676
voice->envlfo.volenv.val = (voice->envlfo.volenv.val * prev_peak) / peak;
677
/* Correction on slope direction for Attack section */
678
env_data = &voice->envlfo.volenv.data[FLUID_VOICE_ENVATTACK];
679
680
if(voice->envlfo.volenv.val <= 1.0f)
681
{
682
/* slope attack for legato note needs to be positive from val up to 1 */
683
env_data->increment = 1.0f / env_data->count;
684
env_data->min = -1.0f;
685
env_data->max = 1.0f;
686
}
687
else
688
{
689
/* slope attack for legato note needs to be negative: from val down to 1 */
690
env_data->increment = -voice->envlfo.volenv.val / env_data->count;
691
env_data->min = 1.0f;
692
env_data->max = voice->envlfo.volenv.val;
693
}
694
}
695
}
696
697
/**
698
* Used by legato Mode : multi_retrigger
699
* see fluid_synth_noteon_mono_legato_multi_retrigger()
700
* @param voice the synthesis voice to be updated
701
*/
702
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack)
703
{
704
fluid_rvoice_t *voice = obj;
705
int section; /* volume or modulation section */
706
707
/*-------------------------------------------------------------------------
708
Section skip for volume envelope
709
--------------------------------------------------------------------------*/
710
section = fluid_adsr_env_get_section(&voice->envlfo.volenv);
711
if(section >= FLUID_VOICE_ENVHOLD)
712
{
713
/* DECAY, SUSTAIN,RELEASE section use logarithmic scaling. Calculates new
714
volenv_val to achieve equivalent amplitude during the attack phase
715
for seamless volume transition. */
716
fluid_real_t amp_cb, env_value;
717
amp_cb = FLUID_PEAK_ATTENUATION *
718
(1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv));
719
env_value = fluid_cb2amp(amp_cb); /* a bit of optimization */
720
fluid_clip(env_value, 0.0, 1.0);
721
fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value);
722
/* next, skips to Attack section */
723
}
724
725
/* skips to Attack section from any section */
726
/* Update vol and attack data */
727
fluid_rvoice_local_retrigger_attack(voice);
728
729
/*-------------------------------------------------------------------------
730
Section skip for modulation envelope
731
--------------------------------------------------------------------------*/
732
section = fluid_adsr_env_get_section(&voice->envlfo.modenv);
733
if(section >= FLUID_VOICE_ENVHOLD)
734
{
735
/* DECAY, SUSTAIN,RELEASE section use linear scaling.
736
Since v 2.1 , as recommended by soundfont 2.01/2.4 spec, ATTACK section
737
uses convex shape (see fluid_rvoice_write() - fluid_convex()).
738
Calculate new modenv value (new_value) for seamless attack transition.
739
Here we need the inverse of fluid_convex() function defined as:
740
new_value = pow(10, (1 - current_val) . FLUID_PEAK_ATTENUATION / -200 . 2.0)
741
For performance reason we use fluid_cb2amp(Val) = pow(10, val/-200) with
742
val = (1 - current_val) . FLUID_PEAK_ATTENUATION / 2.0
743
*/
744
fluid_real_t new_value; /* new modenv value */
745
new_value = fluid_cb2amp((1.0f - fluid_adsr_env_get_val(&voice->envlfo.modenv))
746
* FLUID_PEAK_ATTENUATION / 2.0);
747
fluid_clip(new_value, 0.0, 1.0);
748
fluid_adsr_env_set_val(&voice->envlfo.modenv, new_value);
749
}
750
/* Skips from any section to ATTACK section */
751
fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVATTACK);
752
}
753
754
/**
755
* sets the portamento dsp parameters: dsp.pitchoffset, dsp.pitchinc
756
* @param voice rvoice to set portamento.
757
* @param countinc increment count number.
758
* @param pitchoffset pitch offset to apply to voice dsp.pitch.
759
*
760
* Notes:
761
* 1) To get continuous portamento between consecutive noteOn (n1,n2,n3...),
762
* pitchoffset is accumulated in current dsp pitchoffset.
763
* 2) And to get constant portamento duration, dsp pitch increment is updated.
764
*/
765
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_portamento)
766
{
767
fluid_rvoice_t *voice = obj;
768
unsigned int countinc = param[0].i;
769
fluid_real_t pitchoffset = param[1].real;
770
771
if(countinc)
772
{
773
voice->dsp.pitchoffset += pitchoffset;
774
voice->dsp.pitchinc = - voice->dsp.pitchoffset / countinc;
775
}
776
777
/* Then during the voice processing (in fluid_rvoice_write()),
778
dsp.pitchoffset will be incremented by dsp pitchinc. */
779
}
780
781
782
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_output_rate)
783
{
784
fluid_rvoice_t *voice = obj;
785
fluid_real_t value = param[0].real;
786
787
voice->dsp.output_rate = value;
788
}
789
790
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_interp_method)
791
{
792
fluid_rvoice_t *voice = obj;
793
int value = param[0].i;
794
795
voice->dsp.interp_method = value;
796
}
797
798
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_root_pitch_hz)
799
{
800
fluid_rvoice_t *voice = obj;
801
fluid_real_t value = param[0].real;
802
803
voice->dsp.root_pitch_hz = value;
804
}
805
806
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_pitch)
807
{
808
fluid_rvoice_t *voice = obj;
809
fluid_real_t value = param[0].real;
810
811
voice->dsp.pitch = value;
812
}
813
814
815
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_attenuation)
816
{
817
fluid_rvoice_t *voice = obj;
818
fluid_real_t value = param[0].real;
819
820
voice->dsp.prev_attenuation = voice->dsp.attenuation;
821
voice->dsp.attenuation = value;
822
}
823
824
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_min_attenuation_cB)
825
{
826
fluid_rvoice_t *voice = obj;
827
fluid_real_t value = param[0].real;
828
829
voice->dsp.min_attenuation_cB = value;
830
}
831
832
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_viblfo_to_pitch)
833
{
834
fluid_rvoice_t *voice = obj;
835
fluid_real_t value = param[0].real;
836
837
voice->envlfo.viblfo_to_pitch = value;
838
}
839
840
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_pitch)
841
{
842
fluid_rvoice_t *voice = obj;
843
fluid_real_t value = param[0].real;
844
845
voice->envlfo.modlfo_to_pitch = value;
846
}
847
848
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_vol)
849
{
850
fluid_rvoice_t *voice = obj;
851
fluid_real_t value = param[0].real;
852
853
voice->envlfo.modlfo_to_vol = value;
854
}
855
856
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_fc)
857
{
858
fluid_rvoice_t *voice = obj;
859
fluid_real_t value = param[0].real;
860
861
voice->envlfo.modlfo_to_fc = value;
862
}
863
864
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_fc)
865
{
866
fluid_rvoice_t *voice = obj;
867
fluid_real_t value = param[0].real;
868
869
voice->envlfo.modenv_to_fc = value;
870
}
871
872
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_pitch)
873
{
874
fluid_rvoice_t *voice = obj;
875
fluid_real_t value = param[0].real;
876
877
voice->envlfo.modenv_to_pitch = value;
878
}
879
880
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_synth_gain)
881
{
882
fluid_rvoice_t *voice = obj;
883
fluid_real_t value = param[0].real;
884
885
voice->dsp.synth_gain = value;
886
887
/* For a looped sample, this value will be overwritten as soon as the
888
* loop parameters are initialized (they may depend on modulators).
889
* This value can be kept, it is a worst-case estimate.
890
*/
891
voice->dsp.amplitude_that_reaches_noise_floor_nonloop = FLUID_NOISE_FLOOR / value;
892
voice->dsp.amplitude_that_reaches_noise_floor_loop = FLUID_NOISE_FLOOR / value;
893
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
894
}
895
896
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_start)
897
{
898
fluid_rvoice_t *voice = obj;
899
int value = param[0].i;
900
901
voice->dsp.start = value;
902
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
903
}
904
905
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_end)
906
{
907
fluid_rvoice_t *voice = obj;
908
int value = param[0].i;
909
910
voice->dsp.end = value;
911
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
912
}
913
914
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopstart)
915
{
916
fluid_rvoice_t *voice = obj;
917
int value = param[0].i;
918
919
voice->dsp.loopstart = value;
920
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
921
}
922
923
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopend)
924
{
925
fluid_rvoice_t *voice = obj;
926
int value = param[0].i;
927
928
voice->dsp.loopend = value;
929
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
930
}
931
932
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_samplemode)
933
{
934
fluid_rvoice_t *voice = obj;
935
enum fluid_loop value = param[0].i;
936
937
voice->dsp.samplemode = value;
938
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
939
}
940
941
942
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample)
943
{
944
fluid_rvoice_t *voice = obj;
945
fluid_sample_t *value = param[0].ptr;
946
947
voice->dsp.sample = value;
948
949
if(value)
950
{
951
voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
952
}
953
}
954
955
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_voiceoff)
956
{
957
fluid_rvoice_t *voice = obj;
958
959
fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVFINISHED);
960
fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVFINISHED);
961
}
962
963