1 /* FluidSynth - A Software Synthesizer
3 * Copyright (C) 2003 Peter Hanappe and others.
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.
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.
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
21 #include "fluid_rvoice.h"
22 #include "fluid_conv.h"
23 #include "fluid_sys.h"
26 static void fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks);
29 * @return -1 if voice has finished, 0 if it's currently quiet, 1 otherwise
31 static FLUID_INLINE int
32 fluid_rvoice_calc_amp(fluid_rvoice_t *voice)
34 fluid_real_t target_amp; /* target amplitude */
36 if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVDELAY)
38 return -1; /* The volume amplitude is in hold phase. No sound is produced. */
41 if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
43 /* the envelope is in the attack section: ramp linearly to max value.
44 * A positive modlfo_to_vol should increase volume (negative attenuation).
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);
52 fluid_real_t amplitude_that_reaches_noise_floor;
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);
59 /* We turn off a voice, if the volume has dropped low enough. */
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.
66 /* If the loop amplitude is known, we can use it if the voice loop is within
70 /* Is the playing pointer already in the loop? */
71 if(voice->dsp.has_looped)
73 amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_loop;
77 amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
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):
86 amp_max = fluid_cb2amp(voice->dsp.min_attenuation_cB) *
87 fluid_adsr_env_get_val(&voice->envlfo.volenv);
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)
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;
101 fluid_check_fpe("voice_write amplitude calculation");
103 /* no volume and not changing? - No need to process */
104 if((voice->dsp.amp == 0.0f) && (voice->dsp.amp_incr == 0.0f))
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
117 #define FLUID_SAMPLESANITY_CHECK (1 << 0)
118 #define FLUID_SAMPLESANITY_STARTUP (1 << 1)
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.
127 fluid_rvoice_check_sample_sanity(fluid_rvoice_t *voice)
129 int min_index_nonloop = (int) voice->dsp.sample->start;
130 int max_index_nonloop = (int) voice->dsp.sample->end;
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");
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);
144 /* Keep the start point within the sample data */
145 if(voice->dsp.start < min_index_nonloop)
147 voice->dsp.start = min_index_nonloop;
149 else if(voice->dsp.start > max_index_nonloop)
151 voice->dsp.start = max_index_nonloop;
154 /* Keep the end point within the sample data */
155 if(voice->dsp.end < min_index_nonloop)
157 voice->dsp.end = min_index_nonloop;
159 else if(voice->dsp.end > max_index_nonloop)
161 voice->dsp.end = max_index_nonloop;
164 /* Keep start and end point in the right order */
165 if(voice->dsp.start > voice->dsp.end)
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!"); */
174 if(voice->dsp.start == voice->dsp.end)
176 fluid_rvoice_voiceoff(voice, NULL);
180 if((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
181 || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE))
183 /* Keep the loop start point within the sample data */
184 if(voice->dsp.loopstart < min_index_loop)
186 voice->dsp.loopstart = min_index_loop;
188 else if(voice->dsp.loopstart > max_index_loop)
190 voice->dsp.loopstart = max_index_loop;
193 /* Keep the loop end point within the sample data */
194 if(voice->dsp.loopend < min_index_loop)
196 voice->dsp.loopend = min_index_loop;
198 else if(voice->dsp.loopend > max_index_loop)
200 voice->dsp.loopend = max_index_loop;
203 /* Keep loop start and end point in the right order */
204 if(voice->dsp.loopstart > voice->dsp.loopend)
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!"); */
212 /* Loop too short? Then don't loop. */
213 if(voice->dsp.loopend < voice->dsp.loopstart + FLUID_MIN_LOOP_SIZE)
215 voice->dsp.samplemode = FLUID_UNLOOPED;
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)
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)
226 voice->dsp.amplitude_that_reaches_noise_floor_loop = voice->dsp.sample->amplitude_that_reaches_noise_floor / voice->dsp.synth_gain;
231 voice->dsp.amplitude_that_reaches_noise_floor_loop = voice->dsp.amplitude_that_reaches_noise_floor_nonloop;
235 } /* if sample mode is looped */
237 /* Run startup specific code (only once, when the voice is started) */
238 if(voice->dsp.check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP)
240 if(max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE)
242 if((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE)
243 || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE))
245 voice->dsp.samplemode = FLUID_UNLOOPED;
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);
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))
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
271 int index_in_sample = fluid_phase_index(voice->dsp.phase);
273 if(index_in_sample >= voice->dsp.loopend)
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);
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); */
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;
286 printf("Sane? playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend);
288 fluid_check_fpe("voice_check_sample_sanity");
293 * Synthesize a voice to a buffer.
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.)
300 * Panning, reverb and chorus are processed separately. The dsp interpolation
301 * routine is in (fluid_rvoice_dsp.c).
304 fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
306 int ticks = voice->envlfo.ticks;
307 int count, is_looping;
309 /******************* sample sanity check **********/
311 if(!voice->dsp.sample)
316 if(voice->dsp.check_sample_sanity_flag)
318 fluid_rvoice_check_sample_sanity(voice);
321 /******************* noteoff check ****************/
323 if(voice->envlfo.noteoff_ticks != 0 &&
324 voice->envlfo.ticks >= voice->envlfo.noteoff_ticks)
326 fluid_rvoice_noteoff_LOCAL(voice, 0);
329 voice->envlfo.ticks += FLUID_BUFSIZE;
331 /******************* vol env **********************/
333 fluid_adsr_env_calc(&voice->envlfo.volenv, 1);
334 fluid_check_fpe("voice_write vol env");
336 if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVFINISHED)
341 /******************* mod env **********************/
343 fluid_adsr_env_calc(&voice->envlfo.modenv, 0);
344 fluid_check_fpe("voice_write mod env");
346 /******************* lfo **********************/
348 fluid_lfo_calc(&voice->envlfo.modlfo, ticks);
349 fluid_check_fpe("voice_write mod LFO");
350 fluid_lfo_calc(&voice->envlfo.viblfo, ticks);
351 fluid_check_fpe("voice_write vib LFO");
353 /******************* amplitude **********************/
355 count = fluid_rvoice_calc_amp(voice);
362 /******************* phase **********************/
364 /* Calculate the number of samples, that the DSP loop advances
365 * through the original waveform with each step in the output
366 * buffer. It is the ratio between the frequencies of original
367 * waveform and output waveform.*/
368 voice->dsp.phase_incr = fluid_ct2hz_real(voice->dsp.pitch +
369 voice->dsp.pitchoffset +
370 fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_pitch
371 + fluid_lfo_get_val(&voice->envlfo.viblfo) * voice->envlfo.viblfo_to_pitch
372 + fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_pitch)
373 / voice->dsp.root_pitch_hz;
375 /******************* portamento ****************/
376 /* pitchoffset is updated if enabled.
377 Pitchoffset will be added to dsp pitch at next phase calculation time */
379 /* In most cases portamento will be disabled. Thus first verify that portamento is
380 * enabled before updating pitchoffset and before disabling portamento when necessary,
381 * in order to keep the performance loss at minimum.
382 * If the algorithm would first update pitchoffset and then verify if portamento
383 * needs to be disabled, there would be a significant performance drop on a x87 FPU
385 if(voice->dsp.pitchinc > 0.0f)
387 /* portamento is enabled, so update pitchoffset */
388 voice->dsp.pitchoffset += voice->dsp.pitchinc;
390 /* when pitchoffset reaches 0.0f, portamento is disabled */
391 if(voice->dsp.pitchoffset > 0.0f)
393 voice->dsp.pitchoffset = voice->dsp.pitchinc = 0.0f;
396 else if(voice->dsp.pitchinc < 0.0f)
398 /* portamento is enabled, so update pitchoffset */
399 voice->dsp.pitchoffset += voice->dsp.pitchinc;
401 /* when pitchoffset reaches 0.0f, portamento is disabled */
402 if(voice->dsp.pitchoffset < 0.0f)
404 voice->dsp.pitchoffset = voice->dsp.pitchinc = 0.0f;
408 fluid_check_fpe("voice_write phase calculation");
410 /* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
411 if(voice->dsp.phase_incr == 0)
413 voice->dsp.phase_incr = 1;
416 /* voice is currently looping? */
417 is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE
418 || (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
419 && fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);
421 /*********************** run the dsp chain ************************
422 * The sample is mixed with the output buffer.
423 * The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
424 * Depending on the position in the loop and the loop size, this
425 * may require several runs. */
427 switch(voice->dsp.interp_method)
429 case FLUID_INTERP_NONE:
430 count = fluid_rvoice_dsp_interpolate_none(&voice->dsp, dsp_buf, is_looping);
433 case FLUID_INTERP_LINEAR:
434 count = fluid_rvoice_dsp_interpolate_linear(&voice->dsp, dsp_buf, is_looping);
437 case FLUID_INTERP_4THORDER:
439 count = fluid_rvoice_dsp_interpolate_4th_order(&voice->dsp, dsp_buf, is_looping);
442 case FLUID_INTERP_7THORDER:
443 count = fluid_rvoice_dsp_interpolate_7th_order(&voice->dsp, dsp_buf, is_looping);
447 fluid_check_fpe("voice_write interpolation");
454 /*************** resonant filter ******************/
456 fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
457 fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
458 fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_fc);
460 fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count);
462 /* additional custom filter - only uses the fixed modulator, no lfos... */
463 fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0);
464 fluid_iir_filter_apply(&voice->resonant_custom_filter, dsp_buf, count);
470 * Initialize buffers up to (and including) bufnum
473 fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t *buffers, unsigned int bufnum)
477 if(bufnum < buffers->count)
482 if(bufnum >= FLUID_RVOICE_MAX_BUFS)
487 for(i = buffers->count; i <= bufnum; i++)
489 buffers->bufs[i].amp = 0.0f;
492 buffers->count = bufnum + 1;
497 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp)
499 fluid_rvoice_buffers_t *buffers = obj;
500 unsigned int bufnum = param[0].i;
501 fluid_real_t value = param[1].real;
503 if(fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
508 buffers->bufs[bufnum].amp = value;
511 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping)
513 fluid_rvoice_buffers_t *buffers = obj;
514 unsigned int bufnum = param[0].i;
515 int mapping = param[1].i;
517 if(fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK)
522 buffers->bufs[bufnum].mapping = mapping;
526 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_reset)
528 fluid_rvoice_t *voice = obj;
530 voice->dsp.has_looped = 0;
531 voice->envlfo.ticks = 0;
532 voice->envlfo.noteoff_ticks = 0;
533 voice->dsp.amp = 0.0f; /* The last value of the volume envelope, used to
534 calculate the volume increment during
537 /* legato initialization */
538 voice->dsp.pitchoffset = 0.0; /* portamento initialization */
539 voice->dsp.pitchinc = 0.0;
541 /* mod env initialization*/
542 fluid_adsr_env_reset(&voice->envlfo.modenv);
544 /* vol env initialization */
545 fluid_adsr_env_reset(&voice->envlfo.volenv);
547 /* Fixme: Retrieve from any other existing
548 voice on this channel to keep LFOs in
550 fluid_lfo_reset(&voice->envlfo.viblfo);
551 fluid_lfo_reset(&voice->envlfo.modlfo);
553 /* Clear sample history in filter */
554 fluid_iir_filter_reset(&voice->resonant_filter);
555 fluid_iir_filter_reset(&voice->resonant_custom_filter);
557 /* Force setting of the phase at the first DSP loop run
558 * This cannot be done earlier, because it depends on modulators.
559 [DH] Is that comment really true? */
560 voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
563 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_noteoff)
565 fluid_rvoice_t *rvoice = obj;
566 unsigned int min_ticks = param[0].i;
568 fluid_rvoice_noteoff_LOCAL(rvoice, min_ticks);
572 fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks)
574 if(min_ticks > voice->envlfo.ticks)
577 voice->envlfo.noteoff_ticks = min_ticks;
581 voice->envlfo.noteoff_ticks = 0;
583 if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK)
585 /* A voice is turned off during the attack section of the volume
586 * envelope. The attack section ramps up linearly with
587 * amplitude. The other sections use logarithmic scaling. Calculate new
588 * volenv_val to achieve equievalent amplitude during the release phase
589 * for seamless volume transition.
591 if(fluid_adsr_env_get_val(&voice->envlfo.volenv) > 0)
593 fluid_real_t lfo = fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol;
594 fluid_real_t amp = fluid_adsr_env_get_val(&voice->envlfo.volenv) * fluid_cb2amp(lfo);
595 fluid_real_t env_value = - ((-200 * log(amp) / log(10.0) - lfo) / FLUID_PEAK_ATTENUATION - 1);
596 fluid_clip(env_value, 0.0, 1.0);
597 fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value);
601 fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVRELEASE);
602 fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVRELEASE);
606 * skips to Attack section
608 * Updates vol and attack data
609 * Correction on volume val to achieve equivalent amplitude at noteOn legato
611 * @param voice the synthesis voice to be updated
613 static FLUID_INLINE void fluid_rvoice_local_retrigger_attack(fluid_rvoice_t *voice)
615 /* skips to Attack section */
616 /* Once in Attack section, current count must be reset, to be sure
617 that the section will be not be prematurely finished. */
618 fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVATTACK);
620 /* Correction on volume val to achieve equivalent amplitude at noteOn legato */
621 fluid_env_data_t *env_data;
622 fluid_real_t peak = fluid_cb2amp(voice->dsp.attenuation);
623 fluid_real_t prev_peak = fluid_cb2amp(voice->dsp.prev_attenuation);
624 voice->envlfo.volenv.val = (voice->envlfo.volenv.val * prev_peak) / peak;
625 /* Correction on slope direction for Attack section */
626 env_data = &voice->envlfo.volenv.data[FLUID_VOICE_ENVATTACK];
628 if(voice->envlfo.volenv.val <= 1.0f)
630 /* slope attack for legato note needs to be positive from val up to 1 */
631 env_data->increment = 1.0f / env_data->count;
632 env_data->min = -1.0f;
633 env_data->max = 1.0f;
637 /* slope attack for legato note needs to be negative: from val down to 1 */
638 env_data->increment = -voice->envlfo.volenv.val / env_data->count;
639 env_data->min = 1.0f;
640 env_data->max = voice->envlfo.volenv.val;
646 * Used by legato Mode : multi_retrigger
647 * see fluid_synth_noteon_mono_legato_multi_retrigger()
648 * @param voice the synthesis voice to be updated
650 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack)
652 fluid_rvoice_t *voice = obj;
653 int section = fluid_adsr_env_get_section(&voice->envlfo.volenv);
655 /*-------------------------------------------------------------------------
656 Section skip for volume envelope
657 --------------------------------------------------------------------------*/
658 if(section >= FLUID_VOICE_ENVHOLD)
660 /* DECAY, SUSTAIN,RELEASE section use logarithmic scaling. Calculates new
661 volenv_val to achieve equivalent amplitude during the attack phase
662 for seamless volume transition. */
663 fluid_real_t amp_cb, env_value;
664 amp_cb = FLUID_PEAK_ATTENUATION *
665 (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv));
666 env_value = fluid_cb2amp(amp_cb); /* a bit of optimization */
667 fluid_clip(env_value, 0.0, 1.0);
668 fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value);
669 /* next, skips to Attack section */
672 /* skips to Attack section from any section */
673 /* Update vol and attack data */
674 fluid_rvoice_local_retrigger_attack(voice);
675 /*-------------------------------------------------------------------------
676 Section skip for modulation envelope
677 --------------------------------------------------------------------------*/
678 /* Skips from any section to ATTACK section */
679 fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVATTACK);
680 /* Actually (v 1.1.6) all sections are linear, so there is no need to
681 correct val value. However soundfont 2.01/2.4 spec. says that Attack should
682 be convex (see issue #153 from Christian Collins). In the case Attack
683 section would be changed to a non linear shape it will be necessary to do
684 a correction for seamless val transition. Here is the place to do this */
688 * sets the portamento dsp parameters: dsp.pitchoffset, dsp.pitchinc
689 * @param voice rvoice to set portamento.
690 * @param countinc increment count number.
691 * @param pitchoffset pitch offset to apply to voice dsp.pitch.
694 * 1) To get continuous portamento between consecutive noteOn (n1,n2,n3...),
695 * pitchoffset is accumulated in current dsp pitchoffset.
696 * 2) And to get constant portamento duration, dsp pitch increment is updated.
698 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_portamento)
700 fluid_rvoice_t *voice = obj;
701 unsigned int countinc = param[0].i;
702 fluid_real_t pitchoffset = param[1].real;
706 voice->dsp.pitchoffset += pitchoffset;
707 voice->dsp.pitchinc = - voice->dsp.pitchoffset / countinc;
710 /* Then during the voice processing (in fluid_rvoice_write()),
711 dsp.pitchoffset will be incremented by dsp pitchinc. */
715 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_output_rate)
717 fluid_rvoice_t *voice = obj;
718 fluid_real_t value = param[0].real;
720 voice->dsp.output_rate = value;
723 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_interp_method)
725 fluid_rvoice_t *voice = obj;
726 int value = param[0].i;
728 voice->dsp.interp_method = value;
731 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_root_pitch_hz)
733 fluid_rvoice_t *voice = obj;
734 fluid_real_t value = param[0].real;
736 voice->dsp.root_pitch_hz = value;
739 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_pitch)
741 fluid_rvoice_t *voice = obj;
742 fluid_real_t value = param[0].real;
744 voice->dsp.pitch = value;
748 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_attenuation)
750 fluid_rvoice_t *voice = obj;
751 fluid_real_t value = param[0].real;
753 voice->dsp.prev_attenuation = voice->dsp.attenuation;
754 voice->dsp.attenuation = value;
757 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_min_attenuation_cB)
759 fluid_rvoice_t *voice = obj;
760 fluid_real_t value = param[0].real;
762 voice->dsp.min_attenuation_cB = value;
765 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_viblfo_to_pitch)
767 fluid_rvoice_t *voice = obj;
768 fluid_real_t value = param[0].real;
770 voice->envlfo.viblfo_to_pitch = value;
773 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_pitch)
775 fluid_rvoice_t *voice = obj;
776 fluid_real_t value = param[0].real;
778 voice->envlfo.modlfo_to_pitch = value;
781 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_vol)
783 fluid_rvoice_t *voice = obj;
784 fluid_real_t value = param[0].real;
786 voice->envlfo.modlfo_to_vol = value;
789 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_fc)
791 fluid_rvoice_t *voice = obj;
792 fluid_real_t value = param[0].real;
794 voice->envlfo.modlfo_to_fc = value;
797 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_fc)
799 fluid_rvoice_t *voice = obj;
800 fluid_real_t value = param[0].real;
802 voice->envlfo.modenv_to_fc = value;
805 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_pitch)
807 fluid_rvoice_t *voice = obj;
808 fluid_real_t value = param[0].real;
810 voice->envlfo.modenv_to_pitch = value;
813 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_synth_gain)
815 fluid_rvoice_t *voice = obj;
816 fluid_real_t value = param[0].real;
818 voice->dsp.synth_gain = value;
820 /* For a looped sample, this value will be overwritten as soon as the
821 * loop parameters are initialized (they may depend on modulators).
822 * This value can be kept, it is a worst-case estimate.
824 voice->dsp.amplitude_that_reaches_noise_floor_nonloop = FLUID_NOISE_FLOOR / value;
825 voice->dsp.amplitude_that_reaches_noise_floor_loop = FLUID_NOISE_FLOOR / value;
826 voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
829 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_start)
831 fluid_rvoice_t *voice = obj;
832 int value = param[0].i;
834 voice->dsp.start = value;
835 voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
838 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_end)
840 fluid_rvoice_t *voice = obj;
841 int value = param[0].i;
843 voice->dsp.end = value;
844 voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
847 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopstart)
849 fluid_rvoice_t *voice = obj;
850 int value = param[0].i;
852 voice->dsp.loopstart = value;
853 voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
856 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopend)
858 fluid_rvoice_t *voice = obj;
859 int value = param[0].i;
861 voice->dsp.loopend = value;
862 voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
865 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_samplemode)
867 fluid_rvoice_t *voice = obj;
868 enum fluid_loop value = param[0].i;
870 voice->dsp.samplemode = value;
871 voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK;
875 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample)
877 fluid_rvoice_t *voice = obj;
878 fluid_sample_t *value = param[0].ptr;
880 voice->dsp.sample = value;
884 voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP;
888 DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_voiceoff)
890 fluid_rvoice_t *voice = obj;
892 fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVFINISHED);
893 fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVFINISHED);