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_mixer.c
4396 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_mixer.h"
22
#include "fluid_rvoice.h"
23
#include "fluid_sys.h"
24
#include "fluid_rev.h"
25
#include "fluid_chorus.h"
26
#include "fluid_ladspa.h"
27
#include "fluid_synth.h"
28
29
30
// If less than x voices, the thread overhead is larger than the gain,
31
// so don't activate the thread(s).
32
#define VOICES_PER_THREAD 8
33
34
typedef struct _fluid_mixer_buffers_t fluid_mixer_buffers_t;
35
36
struct _fluid_mixer_buffers_t
37
{
38
fluid_rvoice_mixer_t *mixer; /**< Owner of object */
39
#if ENABLE_MIXER_THREADS
40
fluid_thread_t *thread; /**< Thread object */
41
fluid_atomic_int_t ready; /**< Atomic: buffers are ready for mixing */
42
#endif
43
44
fluid_rvoice_t **finished_voices; /* List of voices who have finished */
45
int finished_voice_count;
46
47
fluid_real_t *local_buf;
48
49
int buf_count;
50
int fx_buf_count;
51
52
/** buffer to store the left part of a stereo channel to.
53
* Specifically a two dimensional array, containing \c buf_count sample buffers
54
* (i.e. for each synth.audio-groups), of which each contains
55
* FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT audio items (=samples)
56
* @note Each sample buffer is aligned to the FLUID_DEFAULT_ALIGNMENT
57
* boundary provided that this pointer points to an aligned buffer.
58
* So make sure to access the sample buffer by first aligning this
59
* pointer using fluid_align_ptr()
60
*/
61
fluid_real_t *left_buf;
62
63
/** dito, but for right part of a stereo channel */
64
fluid_real_t *right_buf;
65
66
/** buffer to store the left part of a stereo effects channel to.
67
* Specifically a two dimensional array, containing \c fx_buf_count buffers
68
* (i.e. for each synth.effects-channels), of which each buffer contains
69
* FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT audio items (=samples)
70
*/
71
fluid_real_t *fx_left_buf;
72
fluid_real_t *fx_right_buf;
73
};
74
75
typedef struct _fluid_mixer_fx_t fluid_mixer_fx_t;
76
77
struct _fluid_mixer_fx_t
78
{
79
fluid_revmodel_t *reverb; /**< Reverb unit */
80
/* reverb shadow parameters here will be returned if queried */
81
double reverb_param[FLUID_REVERB_PARAM_LAST];
82
int reverb_on; /* reverb on/off */
83
84
fluid_chorus_t *chorus; /**< Chorus unit */
85
/* chorus shadow parameters here will be returned if queried */
86
double chorus_param[FLUID_CHORUS_PARAM_LAST];
87
int chorus_on; /* chorus on/off */
88
};
89
90
struct _fluid_rvoice_mixer_t
91
{
92
fluid_mixer_fx_t *fx;
93
94
fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
95
fluid_rvoice_eventhandler_t *eventhandler;
96
97
fluid_rvoice_t **rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
98
int polyphony; /**< Read-only: Length of voices array */
99
int active_voices; /**< Read-only: Number of non-null voices */
100
int current_blockcount; /**< Read-only: how many blocks to process this time */
101
int fx_units;
102
int with_reverb; /**< Should the synth use the built-in reverb unit? */
103
int with_chorus; /**< Should the synth use the built-in chorus unit? */
104
int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */
105
106
#ifdef LADSPA
107
fluid_ladspa_fx_t *ladspa_fx; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
108
#endif
109
110
#if ENABLE_MIXER_THREADS
111
// int sleeping_threads; /**< Atomic: number of threads currently asleep */
112
// int active_threads; /**< Atomic: number of threads in the thread loop */
113
fluid_atomic_int_t threads_should_terminate; /**< Atomic: Set to TRUE when threads should terminate */
114
fluid_atomic_int_t current_rvoice; /**< Atomic: for the threads to know next voice to */
115
fluid_cond_t *wakeup_threads; /**< Signalled when the threads should wake up */
116
fluid_cond_mutex_t *wakeup_threads_m; /**< wakeup_threads mutex companion */
117
fluid_cond_t *thread_ready; /**< Signalled from thread, when the thread has a buffer ready for mixing */
118
fluid_cond_mutex_t *thread_ready_m; /**< thread_ready mutex companion */
119
120
int thread_count; /**< Number of extra mixer threads for multi-core rendering */
121
fluid_mixer_buffers_t *threads; /**< Array of mixer threads (thread_count in length) */
122
#endif
123
};
124
125
#if ENABLE_MIXER_THREADS
126
static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t *mixer);
127
static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t *mixer, int thread_count, int prio_level);
128
#endif
129
130
static FLUID_INLINE void
131
fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcount)
132
{
133
// Making those variables const causes gcc to fail with "variable is predetermined ‘shared’ for ‘shared’".
134
// Not explicitly marking them shared makes it fail for clang and MSVC...
135
/*const*/ int fx_channels_per_unit = mixer->buffers.fx_buf_count / mixer->fx_units;
136
/*const*/ int dry_count = mixer->buffers.buf_count; /* dry buffers count */
137
/*const*/ int mix_fx_to_out = mixer->mix_fx_to_out; /* get mix_fx_to_out mode */
138
139
void (*reverb_process_func)(fluid_revmodel_t *rev, const fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out);
140
void (*chorus_process_func)(fluid_chorus_t *chorus, const fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out);
141
142
fluid_real_t *out_rev_l, *out_rev_r, *out_ch_l, *out_ch_r;
143
144
// all dry unprocessed mono input is stored in the left channel
145
fluid_real_t *in_rev = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
146
fluid_real_t *in_ch = in_rev;
147
148
fluid_profile_ref_var(prof_ref);
149
150
#ifdef LADSPA
151
152
/* Run the signal through the LADSPA Fx unit. The buffers have already been
153
* set up in fluid_rvoice_mixer_set_ladspa. */
154
if(mixer->ladspa_fx)
155
{
156
fluid_ladspa_run(mixer->ladspa_fx, current_blockcount, FLUID_BUFSIZE);
157
fluid_check_fpe("LADSPA");
158
}
159
160
#endif
161
162
if(mix_fx_to_out)
163
{
164
// mix effects to first stereo channel
165
out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
166
out_ch_r = out_rev_r = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT);
167
168
reverb_process_func = fluid_revmodel_processmix;
169
chorus_process_func = fluid_chorus_processmix;
170
}
171
else
172
{
173
// replace effects into respective stereo effects channel
174
out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
175
out_ch_r = out_rev_r = fluid_align_ptr(mixer->buffers.fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
176
177
reverb_process_func = fluid_revmodel_processreplace;
178
chorus_process_func = fluid_chorus_processreplace;
179
}
180
181
if(mixer->with_reverb || mixer->with_chorus)
182
{
183
#if ENABLE_MIXER_THREADS && !defined(WITH_PROFILING)
184
int fx_mixer_threads = mixer->fx_units;
185
fluid_clip(fx_mixer_threads, 1, mixer->thread_count + 1);
186
#pragma omp parallel default(none) shared(mixer, reverb_process_func, chorus_process_func, dry_count, current_blockcount, mix_fx_to_out, fx_channels_per_unit) firstprivate(in_rev, in_ch, out_rev_l, out_rev_r, out_ch_l, out_ch_r) num_threads(fx_mixer_threads)
187
#endif
188
{
189
int i, f;
190
int buf_idx; /* buffer index */
191
int samp_idx; /* sample index in buffer */
192
int dry_idx = 0; /* dry buffer index */
193
int sample_count; /* sample count to process */
194
if(mixer->with_reverb)
195
{
196
#if ENABLE_MIXER_THREADS && !defined(WITH_PROFILING)
197
#pragma omp for schedule(static)
198
#endif
199
for(f = 0; f < mixer->fx_units; f++)
200
{
201
if(!mixer->fx[f].reverb_on)
202
{
203
continue; /* this reverb unit is disabled */
204
}
205
206
buf_idx = f * fx_channels_per_unit + SYNTH_REVERB_CHANNEL;
207
samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE;
208
sample_count = current_blockcount * FLUID_BUFSIZE;
209
210
/* in mix mode, map fx out_rev at index f to a dry buffer at index dry_idx */
211
if(mix_fx_to_out)
212
{
213
/* dry buffer mapping, should be done more flexible in the future */
214
dry_idx = (f % dry_count) * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE;
215
}
216
217
for(i = 0; i < sample_count; i += FLUID_BUFSIZE, samp_idx += FLUID_BUFSIZE)
218
{
219
reverb_process_func(mixer->fx[f].reverb,
220
&in_rev[samp_idx],
221
mix_fx_to_out ? &out_rev_l[dry_idx + i] : &out_rev_l[samp_idx],
222
mix_fx_to_out ? &out_rev_r[dry_idx + i] : &out_rev_r[samp_idx]);
223
}
224
} // implicit omp barrier - required, because out_rev_l aliases with out_ch_l
225
226
fluid_profile(FLUID_PROF_ONE_BLOCK_REVERB, prof_ref, 0,
227
current_blockcount * FLUID_BUFSIZE);
228
}
229
230
if(mixer->with_chorus)
231
{
232
#if ENABLE_MIXER_THREADS && !defined(WITH_PROFILING)
233
#pragma omp for schedule(static)
234
#endif
235
for(f = 0; f < mixer->fx_units; f++)
236
{
237
if(!mixer->fx[f].chorus_on)
238
{
239
continue; /* this chorus unit is disabled */
240
}
241
242
buf_idx = f * fx_channels_per_unit + SYNTH_CHORUS_CHANNEL;
243
samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE;
244
sample_count = current_blockcount * FLUID_BUFSIZE;
245
246
/* in mix mode, map fx out_ch at index f to a dry buffer at index dry_idx */
247
if(mix_fx_to_out)
248
{
249
/* dry buffer mapping, should be done more flexible in the future */
250
dry_idx = (f % dry_count) * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE;
251
}
252
253
for(i = 0; i < sample_count; i += FLUID_BUFSIZE, samp_idx += FLUID_BUFSIZE)
254
{
255
chorus_process_func(mixer->fx[f].chorus,
256
&in_ch [samp_idx],
257
mix_fx_to_out ? &out_ch_l[dry_idx + i] : &out_ch_l[samp_idx],
258
mix_fx_to_out ? &out_ch_r[dry_idx + i] : &out_ch_r[samp_idx]);
259
}
260
}
261
262
fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref, 0,
263
current_blockcount * FLUID_BUFSIZE);
264
}
265
}
266
}
267
}
268
269
/**
270
* Glue to get fluid_rvoice_buffers_mix what it wants
271
* Note: Make sure outbufs has 2 * (buf_count + fx_buf_count) elements before calling
272
*/
273
static FLUID_INLINE int
274
fluid_mixer_buffers_prepare(fluid_mixer_buffers_t *buffers, fluid_real_t **outbufs)
275
{
276
fluid_real_t *base_ptr;
277
int i;
278
const int fx_channels_per_unit = buffers->fx_buf_count / buffers->mixer->fx_units;
279
const int offset = buffers->buf_count * 2;
280
int with_reverb = buffers->mixer->with_reverb;
281
int with_chorus = buffers->mixer->with_chorus;
282
283
/* Set up the reverb and chorus buffers only when the effect is enabled or
284
* when LADSPA is active. Nonexisting buffers are detected in the DSP loop.
285
* Not sending the effect signals saves some time in that case. */
286
#ifdef LADSPA
287
int with_ladspa = (buffers->mixer->ladspa_fx != NULL);
288
with_reverb = (with_reverb | with_ladspa);
289
with_chorus = (with_chorus | with_ladspa);
290
#endif
291
292
// all the dry, non-processed mono audio for effects is to be stored in the left buffers
293
base_ptr = fluid_align_ptr(buffers->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
294
295
for(i = 0; i < buffers->mixer->fx_units; i++)
296
{
297
int fx_idx = i * fx_channels_per_unit;
298
299
outbufs[offset + fx_idx + SYNTH_REVERB_CHANNEL] =
300
(with_reverb)
301
? &base_ptr[(fx_idx + SYNTH_REVERB_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]
302
: NULL;
303
304
outbufs[offset + fx_idx + SYNTH_CHORUS_CHANNEL] =
305
(with_chorus)
306
? &base_ptr[(fx_idx + SYNTH_CHORUS_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]
307
: NULL;
308
}
309
310
/* The output associated with a MIDI channel is wrapped around
311
* using the number of audio groups as modulo divider. This is
312
* typically the number of output channels on the 'sound card',
313
* as long as the LADSPA Fx unit is not used. In case of LADSPA
314
* unit, think of it as subgroups on a mixer.
315
*
316
* For example: Assume that the number of groups is set to 2.
317
* Then MIDI channel 1, 3, 5, 7 etc. go to output 1, channels 2,
318
* 4, 6, 8 etc to output 2. Or assume 3 groups: Then MIDI
319
* channels 1, 4, 7, 10 etc go to output 1; 2, 5, 8, 11 etc to
320
* output 2, 3, 6, 9, 12 etc to output 3.
321
*/
322
base_ptr = fluid_align_ptr(buffers->left_buf, FLUID_DEFAULT_ALIGNMENT);
323
324
for(i = 0; i < buffers->buf_count; i++)
325
{
326
outbufs[i * 2] = &base_ptr[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
327
}
328
329
base_ptr = fluid_align_ptr(buffers->right_buf, FLUID_DEFAULT_ALIGNMENT);
330
331
for(i = 0; i < buffers->buf_count; i++)
332
{
333
outbufs[i * 2 + 1] = &base_ptr[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
334
}
335
336
return offset + buffers->fx_buf_count;
337
}
338
339
340
static FLUID_INLINE void
341
fluid_finish_rvoice(fluid_mixer_buffers_t *buffers, fluid_rvoice_t *rvoice)
342
{
343
if(buffers->finished_voice_count < buffers->mixer->polyphony)
344
{
345
buffers->finished_voices[buffers->finished_voice_count++] = rvoice;
346
}
347
else
348
{
349
FLUID_LOG(FLUID_ERR, "Exceeded finished voices array, try increasing polyphony");
350
}
351
}
352
353
static void
354
fluid_mixer_buffer_process_finished_voices(fluid_mixer_buffers_t *buffers)
355
{
356
int i, j;
357
358
for(i = 0; i < buffers->finished_voice_count; i++)
359
{
360
fluid_rvoice_t *v = buffers->finished_voices[i];
361
int av = buffers->mixer->active_voices;
362
363
for(j = 0; j < av; j++)
364
{
365
if(v == buffers->mixer->rvoices[j])
366
{
367
av--;
368
369
/* Pack the array */
370
if(j < av)
371
{
372
buffers->mixer->rvoices[j] = buffers->mixer->rvoices[av];
373
}
374
}
375
}
376
377
buffers->mixer->active_voices = av;
378
379
fluid_rvoice_eventhandler_finished_voice_callback(buffers->mixer->eventhandler, v);
380
}
381
382
buffers->finished_voice_count = 0;
383
}
384
385
static FLUID_INLINE void fluid_rvoice_mixer_process_finished_voices(fluid_rvoice_mixer_t *mixer)
386
{
387
#if ENABLE_MIXER_THREADS
388
int i;
389
390
for(i = 0; i < mixer->thread_count; i++)
391
{
392
fluid_mixer_buffer_process_finished_voices(&mixer->threads[i]);
393
}
394
395
#endif
396
fluid_mixer_buffer_process_finished_voices(&mixer->buffers);
397
}
398
399
400
static FLUID_INLINE fluid_real_t *
401
get_dest_buf(fluid_rvoice_buffers_t *buffers, int index,
402
fluid_real_t **dest_bufs, int dest_bufcount)
403
{
404
int j = buffers->bufs[index].mapping;
405
406
if(j >= dest_bufcount || j < 0)
407
{
408
return NULL;
409
}
410
411
return dest_bufs[j];
412
}
413
414
/**
415
* Mix samples down from internal dsp_buf to output buffers
416
*
417
* @param buffers Destination buffer(s)
418
* @param dsp_buf Mono sample source
419
* @param start_block starting sample in dsp_buf
420
* @param sample_count number of samples to mix following \c start_block
421
* @param dest_bufs Array of buffers to mixdown to
422
* @param dest_bufcount Length of dest_bufs (i.e count of buffers)
423
*/
424
static void
425
fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
426
const fluid_real_t *FLUID_RESTRICT dsp_buf,
427
int start_block, int sample_count,
428
fluid_real_t **dest_bufs, int dest_bufcount)
429
{
430
/* buffers count to mixdown to */
431
int bufcount = buffers->count;
432
int i, dsp_i;
433
434
/* if there is nothing to mix, return immediately */
435
if(sample_count <= 0 || dest_bufcount <= 0)
436
{
437
return;
438
}
439
440
FLUID_ASSERT((uintptr_t)dsp_buf % FLUID_DEFAULT_ALIGNMENT == 0);
441
FLUID_ASSERT((uintptr_t)(&dsp_buf[start_block * FLUID_BUFSIZE]) % FLUID_DEFAULT_ALIGNMENT == 0);
442
443
/* mixdown for each buffer */
444
for(i = 0; i < bufcount; i++)
445
{
446
fluid_real_t *FLUID_RESTRICT buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
447
fluid_real_t target_amp = buffers->bufs[i].target_amp;
448
fluid_real_t current_amp = buffers->bufs[i].current_amp;
449
fluid_real_t amp_incr;
450
451
if(buf == NULL || (current_amp == 0.0f && target_amp == 0.0f))
452
{
453
continue;
454
}
455
456
amp_incr = (target_amp - current_amp) / FLUID_BUFSIZE;
457
458
FLUID_ASSERT((uintptr_t)buf % FLUID_DEFAULT_ALIGNMENT == 0);
459
460
/* Mixdown sample_count samples in the current buffer buf
461
*
462
* For the first FLUID_BUFSIZE samples, we linearly interpolate the buffers amplitude to
463
* avoid clicks/pops when rapidly changing the channels panning (issue 768).
464
*
465
* We could have squashed this into one single loop by using an if clause within the loop body.
466
* But it seems like having two separate loops is easier for compilers to understand, and therefore
467
* auto-vectorizing the loops.
468
*/
469
if(sample_count < FLUID_BUFSIZE)
470
{
471
// scalar loop variant, the voice will have finished afterwards
472
for(dsp_i = 0; dsp_i < sample_count; dsp_i++)
473
{
474
buf[start_block * FLUID_BUFSIZE + dsp_i] += current_amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
475
current_amp += amp_incr;
476
}
477
}
478
else
479
{
480
// here goes the vectorizable loop
481
#pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT)
482
for(dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i++)
483
{
484
// We cannot simply increment current_amp by amp_incr during every iteration, as this would create a dependency and prevent vectorization.
485
buf[start_block * FLUID_BUFSIZE + dsp_i] += (current_amp + amp_incr * dsp_i) * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
486
}
487
488
// we have reached the target_amp
489
if(target_amp > 0)
490
{
491
/* Note, that this loop could be unrolled by FLUID_BUFSIZE elements */
492
#pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT)
493
for(dsp_i = FLUID_BUFSIZE; dsp_i < sample_count; dsp_i++)
494
{
495
// Index by blocks (not by samples) to let the compiler know that we always start accessing
496
// buf and dsp_buf at the FLUID_BUFSIZE*sizeof(fluid_real_t) byte boundary and never somewhere
497
// in between.
498
// A good compiler should understand: Aha, so I don't need to add a peel loop when vectorizing
499
// this loop. Great.
500
buf[start_block * FLUID_BUFSIZE + dsp_i] += target_amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
501
}
502
}
503
}
504
505
buffers->bufs[i].current_amp = target_amp;
506
}
507
}
508
509
/**
510
* Synthesize one voice and add to buffer.
511
* NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
512
* voice has been finished, removed and possibly replaced with another voice.
513
*/
514
static FLUID_INLINE void
515
fluid_mixer_buffers_render_one(fluid_mixer_buffers_t *buffers,
516
fluid_rvoice_t *rvoice, fluid_real_t **dest_bufs,
517
unsigned int dest_bufcount, fluid_real_t *src_buf, int blockcount)
518
{
519
int i, total_samples = 0, last_block_mixed = 0;
520
521
for(i = 0; i < blockcount; i++)
522
{
523
/* render one block in src_buf */
524
int s = fluid_rvoice_write(rvoice, &src_buf[FLUID_BUFSIZE * i]);
525
526
if(s == -1)
527
{
528
/* the voice is silent, mix back all the previously rendered sound */
529
fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed,
530
total_samples - (last_block_mixed * FLUID_BUFSIZE),
531
dest_bufs, dest_bufcount);
532
533
last_block_mixed = i + 1; /* future block start index to mix from */
534
total_samples += FLUID_BUFSIZE; /* accumulate samples count rendered */
535
}
536
else
537
{
538
/* the voice wasn't quiet. Some samples have been rendered [0..FLUID_BUFSIZE] */
539
total_samples += s;
540
541
if(s < FLUID_BUFSIZE)
542
{
543
/* voice has finished */
544
break;
545
}
546
}
547
}
548
549
/* Now mix the remaining blocks from last_block_mixed to total_sample */
550
fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed,
551
total_samples - (last_block_mixed * FLUID_BUFSIZE),
552
dest_bufs, dest_bufcount);
553
554
if(total_samples < blockcount * FLUID_BUFSIZE)
555
{
556
/* voice has finished */
557
fluid_finish_rvoice(buffers, rvoice);
558
}
559
}
560
561
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice)
562
{
563
int i;
564
fluid_rvoice_mixer_t *mixer = obj;
565
fluid_rvoice_t *voice = param[0].ptr;
566
567
if(mixer->active_voices < mixer->polyphony)
568
{
569
mixer->rvoices[mixer->active_voices++] = voice;
570
return; // success
571
}
572
573
/* See if any voices just finished, if so, take its place.
574
This can happen in voice overflow conditions. */
575
for(i = 0; i < mixer->active_voices; i++)
576
{
577
if(mixer->rvoices[i] == voice)
578
{
579
FLUID_LOG(FLUID_ERR, "Internal error: Trying to replace an existing rvoice in fluid_rvoice_mixer_add_voice?!");
580
return;
581
}
582
583
if(mixer->rvoices[i]->envlfo.volenv.section == FLUID_VOICE_ENVFINISHED)
584
{
585
fluid_finish_rvoice(&mixer->buffers, mixer->rvoices[i]);
586
mixer->rvoices[i] = voice;
587
return; // success
588
}
589
}
590
591
/* This should never happen */
592
FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
593
}
594
595
static int
596
fluid_mixer_buffers_update_polyphony(fluid_mixer_buffers_t *buffers, int value)
597
{
598
void *newptr;
599
600
if(buffers->finished_voice_count > value)
601
{
602
return FLUID_FAILED;
603
}
604
605
newptr = FLUID_REALLOC(buffers->finished_voices, value * sizeof(fluid_rvoice_t *));
606
607
if(newptr == NULL && value > 0)
608
{
609
return FLUID_FAILED;
610
}
611
612
buffers->finished_voices = newptr;
613
return FLUID_OK;
614
}
615
616
/**
617
* Update polyphony - max number of voices (NOTE: not hard real-time capable)
618
* @return FLUID_OK or FLUID_FAILED
619
*/
620
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_polyphony)
621
{
622
void *newptr;
623
fluid_rvoice_mixer_t *handler = obj;
624
int value = param[0].i;
625
626
if(handler->active_voices > value)
627
{
628
return /*FLUID_FAILED*/;
629
}
630
631
newptr = FLUID_REALLOC(handler->rvoices, value * sizeof(fluid_rvoice_t *));
632
633
if(newptr == NULL)
634
{
635
return /*FLUID_FAILED*/;
636
}
637
638
handler->rvoices = newptr;
639
640
if(fluid_mixer_buffers_update_polyphony(&handler->buffers, value)
641
== FLUID_FAILED)
642
{
643
return /*FLUID_FAILED*/;
644
}
645
646
#if ENABLE_MIXER_THREADS
647
{
648
int i;
649
650
for(i = 0; i < handler->thread_count; i++)
651
{
652
if(fluid_mixer_buffers_update_polyphony(&handler->threads[i], value)
653
== FLUID_FAILED)
654
{
655
return /*FLUID_FAILED*/;
656
}
657
}
658
}
659
#endif
660
661
handler->polyphony = value;
662
/*return FLUID_OK*/;
663
}
664
665
666
static void
667
fluid_render_loop_singlethread(fluid_rvoice_mixer_t *mixer, int blockcount)
668
{
669
int i;
670
FLUID_DECLARE_VLA(fluid_real_t *, bufs,
671
mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
672
int bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
673
674
fluid_real_t *local_buf = fluid_align_ptr(mixer->buffers.local_buf, FLUID_DEFAULT_ALIGNMENT);
675
676
fluid_profile_ref_var(prof_ref);
677
678
for(i = 0; i < mixer->active_voices; i++)
679
{
680
fluid_mixer_buffers_render_one(&mixer->buffers, mixer->rvoices[i], bufs,
681
bufcount, local_buf, blockcount);
682
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref, 1,
683
blockcount * FLUID_BUFSIZE);
684
}
685
}
686
687
static FLUID_INLINE void
688
fluid_mixer_buffers_zero(fluid_mixer_buffers_t *buffers, int current_blockcount)
689
{
690
int i, size = current_blockcount * FLUID_BUFSIZE * sizeof(fluid_real_t);
691
692
/* TODO: Optimize by only zero out the buffers we actually use later on. */
693
int buf_count = buffers->buf_count, fx_buf_count = buffers->fx_buf_count;
694
695
fluid_real_t *FLUID_RESTRICT buf_l = fluid_align_ptr(buffers->left_buf, FLUID_DEFAULT_ALIGNMENT);
696
fluid_real_t *FLUID_RESTRICT buf_r = fluid_align_ptr(buffers->right_buf, FLUID_DEFAULT_ALIGNMENT);
697
698
for(i = 0; i < buf_count; i++)
699
{
700
FLUID_MEMSET(&buf_l[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size);
701
FLUID_MEMSET(&buf_r[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size);
702
}
703
704
buf_l = fluid_align_ptr(buffers->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
705
buf_r = fluid_align_ptr(buffers->fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
706
707
for(i = 0; i < fx_buf_count; i++)
708
{
709
FLUID_MEMSET(&buf_l[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size);
710
FLUID_MEMSET(&buf_r[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size);
711
}
712
}
713
714
static int
715
fluid_mixer_buffers_init(fluid_mixer_buffers_t *buffers, fluid_rvoice_mixer_t *mixer)
716
{
717
static const int samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT;
718
719
buffers->mixer = mixer;
720
buffers->buf_count = mixer->buffers.buf_count;
721
buffers->fx_buf_count = mixer->buffers.fx_buf_count;
722
723
/* Local mono voice buf */
724
buffers->local_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, samplecount, FLUID_DEFAULT_ALIGNMENT);
725
726
/* Left and right audio buffers */
727
728
buffers->left_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT);
729
buffers->right_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT);
730
731
if((buffers->local_buf == NULL) || (buffers->left_buf == NULL) || (buffers->right_buf == NULL))
732
{
733
FLUID_LOG(FLUID_ERR, "Out of memory");
734
return 0;
735
}
736
737
/* Effects audio buffers */
738
739
buffers->fx_left_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->fx_buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT);
740
buffers->fx_right_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->fx_buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT);
741
742
if((buffers->fx_left_buf == NULL) || (buffers->fx_right_buf == NULL))
743
{
744
FLUID_LOG(FLUID_ERR, "Out of memory");
745
return 0;
746
}
747
748
buffers->finished_voices = NULL;
749
750
if(fluid_mixer_buffers_update_polyphony(buffers, mixer->polyphony)
751
== FLUID_FAILED)
752
{
753
FLUID_LOG(FLUID_ERR, "Out of memory");
754
return 0;
755
}
756
757
return 1;
758
}
759
760
/**
761
* Note: Not hard real-time capable (calls malloc)
762
*/
763
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
764
{
765
fluid_rvoice_mixer_t *mixer = obj;
766
fluid_real_t samplerate = param[1].real; // because fluid_synth_update_mixer() puts real into arg2
767
768
int i;
769
770
for(i = 0; i < mixer->fx_units; i++)
771
{
772
if(mixer->fx[i].chorus)
773
{
774
fluid_chorus_samplerate_change(mixer->fx[i].chorus, samplerate);
775
}
776
777
if(mixer->fx[i].reverb)
778
{
779
fluid_revmodel_samplerate_change(mixer->fx[i].reverb, samplerate);
780
781
/*
782
fluid_revmodel_samplerate_change() shouldn't fail if the reverb was created
783
with sample_rate_max set to the maximum sample rate indicated in the settings.
784
If this condition isn't respected, the reverb will continue to work but with
785
lost of quality.
786
*/
787
}
788
}
789
790
#if LADSPA
791
792
if(mixer->ladspa_fx != NULL)
793
{
794
fluid_ladspa_set_sample_rate(mixer->ladspa_fx, samplerate);
795
}
796
797
#endif
798
}
799
800
801
/**
802
* @param buf_count number of primary stereo buffers
803
* @param fx_buf_count number of stereo effect buffers
804
*/
805
fluid_rvoice_mixer_t *
806
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units,
807
fluid_real_t sample_rate_max,
808
fluid_real_t sample_rate,
809
fluid_rvoice_eventhandler_t *evthandler,
810
int extra_threads, int prio)
811
{
812
int i;
813
fluid_rvoice_mixer_t *mixer = FLUID_NEW(fluid_rvoice_mixer_t);
814
815
if(mixer == NULL)
816
{
817
FLUID_LOG(FLUID_ERR, "Out of memory");
818
return NULL;
819
}
820
821
FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
822
mixer->eventhandler = evthandler;
823
mixer->fx_units = fx_units;
824
mixer->buffers.buf_count = buf_count;
825
mixer->buffers.fx_buf_count = fx_buf_count * fx_units;
826
827
/* allocate the reverb module */
828
mixer->fx = FLUID_ARRAY(fluid_mixer_fx_t, fx_units);
829
830
if(mixer->fx == NULL)
831
{
832
FLUID_LOG(FLUID_ERR, "Out of memory");
833
goto error_recovery;
834
}
835
836
FLUID_MEMSET(mixer->fx, 0, fx_units * sizeof(*mixer->fx));
837
838
for(i = 0; i < fx_units; i++)
839
{
840
/* create reverb and chorus units */
841
mixer->fx[i].reverb = new_fluid_revmodel(sample_rate_max, sample_rate);
842
mixer->fx[i].chorus = new_fluid_chorus(sample_rate);
843
844
if(mixer->fx[i].reverb == NULL || mixer->fx[i].chorus == NULL)
845
{
846
FLUID_LOG(FLUID_ERR, "Out of memory");
847
goto error_recovery;
848
}
849
}
850
851
if(!fluid_mixer_buffers_init(&mixer->buffers, mixer))
852
{
853
goto error_recovery;
854
}
855
856
#if ENABLE_MIXER_THREADS
857
mixer->thread_ready = new_fluid_cond();
858
mixer->wakeup_threads = new_fluid_cond();
859
mixer->thread_ready_m = new_fluid_cond_mutex();
860
mixer->wakeup_threads_m = new_fluid_cond_mutex();
861
862
if(!mixer->thread_ready || !mixer->wakeup_threads ||
863
!mixer->thread_ready_m || !mixer->wakeup_threads_m)
864
{
865
goto error_recovery;
866
}
867
868
if(fluid_rvoice_mixer_set_threads(mixer, extra_threads, prio) != FLUID_OK)
869
{
870
goto error_recovery;
871
}
872
873
#endif
874
875
return mixer;
876
877
error_recovery:
878
delete_fluid_rvoice_mixer(mixer);
879
return NULL;
880
}
881
882
static void
883
fluid_mixer_buffers_free(fluid_mixer_buffers_t *buffers)
884
{
885
FLUID_FREE(buffers->finished_voices);
886
887
/* free all the sample buffers */
888
FLUID_FREE(buffers->local_buf);
889
FLUID_FREE(buffers->left_buf);
890
FLUID_FREE(buffers->right_buf);
891
FLUID_FREE(buffers->fx_left_buf);
892
FLUID_FREE(buffers->fx_right_buf);
893
}
894
895
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer)
896
{
897
int i;
898
899
fluid_return_if_fail(mixer != NULL);
900
901
#if ENABLE_MIXER_THREADS
902
delete_rvoice_mixer_threads(mixer);
903
904
if(mixer->thread_ready)
905
{
906
delete_fluid_cond(mixer->thread_ready);
907
}
908
909
if(mixer->wakeup_threads)
910
{
911
delete_fluid_cond(mixer->wakeup_threads);
912
}
913
914
if(mixer->thread_ready_m)
915
{
916
delete_fluid_cond_mutex(mixer->thread_ready_m);
917
}
918
919
if(mixer->wakeup_threads_m)
920
{
921
delete_fluid_cond_mutex(mixer->wakeup_threads_m);
922
}
923
924
#endif
925
fluid_mixer_buffers_free(&mixer->buffers);
926
927
928
for(i = 0; i < mixer->fx_units; i++)
929
{
930
if(mixer->fx[i].reverb)
931
{
932
delete_fluid_revmodel(mixer->fx[i].reverb);
933
}
934
935
if(mixer->fx[i].chorus)
936
{
937
delete_fluid_chorus(mixer->fx[i].chorus);
938
}
939
}
940
941
FLUID_FREE(mixer->fx);
942
FLUID_FREE(mixer->rvoices);
943
FLUID_FREE(mixer);
944
}
945
946
#ifdef LADSPA
947
/**
948
* Set a LADSPS fx instance to be used by the mixer and assign the mixer buffers
949
* as LADSPA host buffers with sensible names */
950
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t *mixer,
951
fluid_ladspa_fx_t *ladspa_fx, int audio_groups)
952
{
953
mixer->ladspa_fx = ladspa_fx;
954
955
if(ladspa_fx == NULL)
956
{
957
return;
958
}
959
else
960
{
961
fluid_real_t *main_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
962
fluid_real_t *main_r = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT);
963
964
fluid_real_t *rev = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
965
fluid_real_t *chor = rev;
966
967
rev = &rev[SYNTH_REVERB_CHANNEL * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
968
chor = &chor[SYNTH_CHORUS_CHANNEL * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT];
969
970
fluid_ladspa_add_host_ports(ladspa_fx, "Main:L", audio_groups,
971
main_l,
972
FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT);
973
974
fluid_ladspa_add_host_ports(ladspa_fx, "Main:R", audio_groups,
975
main_r,
976
FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT);
977
978
fluid_ladspa_add_host_ports(ladspa_fx, "Reverb:Send", 1,
979
rev,
980
FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT);
981
982
fluid_ladspa_add_host_ports(ladspa_fx, "Chorus:Send", 1,
983
chor,
984
FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT);
985
}
986
}
987
#endif
988
989
/**
990
* set one or more reverb shadow parameters for one fx group.
991
* These parameters will be returned if queried.
992
* (see fluid_rvoice_mixer_reverb_get_param())
993
*
994
* @param mixer that contains all fx units.
995
* @param fx_group index of the fx group to which parameters must be set.
996
* must be in the range [-1..mixer->fx_units[. If -1 the changes are applied to
997
* all fx units.
998
* @param set Flags indicating which parameters should be set (#fluid_revmodel_set_t)
999
* @param values table of parameters values.
1000
*/
1001
void
1002
fluid_rvoice_mixer_set_reverb_full(const fluid_rvoice_mixer_t *mixer,
1003
int fx_group, int set, const double values[])
1004
{
1005
fluid_mixer_fx_t *fx = mixer->fx;
1006
int nr_units = mixer->fx_units;
1007
1008
if(fx_group >= 0) /* apply parameters to this fx group only */
1009
{
1010
nr_units = fx_group + 1;
1011
}
1012
else /* apply parameters to all fx groups */
1013
{
1014
fx_group = 0;
1015
}
1016
1017
for(; fx_group < nr_units; fx_group++)
1018
{
1019
int param;
1020
1021
for(param = 0; param < FLUID_REVERB_PARAM_LAST; param++)
1022
{
1023
if(set & FLUID_REVPARAM_TO_SETFLAG(param))
1024
{
1025
fx[fx_group].reverb_param[param] = values[param];
1026
}
1027
}
1028
}
1029
}
1030
1031
/**
1032
* get one reverb shadow parameter for one fx group.
1033
* (see fluid_rvoice_mixer_set_reverb_full())
1034
*
1035
* @param mixer that contains all fx group units.
1036
* @param fx_group index of the fx group to get parameter from.
1037
* must be in the range [0..mixer->fx_units[.
1038
* @param enum indicating the parameter to get.
1039
* FLUID_REVERB_ROOMSIZE, reverb room size value.
1040
* FLUID_REVERB_DAMP, reverb damping value.
1041
* FLUID_REVERB_WIDTH, reverb width value.
1042
* FLUID_REVERB_LEVEL, reverb level value.
1043
* @return value.
1044
*/
1045
double
1046
fluid_rvoice_mixer_reverb_get_param(const fluid_rvoice_mixer_t *mixer,
1047
int fx_group, int param)
1048
{
1049
return mixer->fx[fx_group].reverb_param[param];
1050
}
1051
1052
/**
1053
* set one or more chorus shadow parameters for one fx group.
1054
* These parameters will be returned if queried.
1055
* (see fluid_rvoice_mixer_chorus_get_param())
1056
*
1057
* @param mixer that contains all fx units.
1058
* @param fx_group index of the fx group to which parameters must be set.
1059
* must be in the range [-1..mixer->fx_units[. If -1 the changes are applied
1060
* to all fx group.
1061
* Keep in mind, that the needed CPU time is proportional to 'nr'.
1062
* @param set Flags indicating which parameters to set (#fluid_chorus_set_t)
1063
* @param values table of pararameters.
1064
*/
1065
void
1066
fluid_rvoice_mixer_set_chorus_full(const fluid_rvoice_mixer_t *mixer,
1067
int fx_group, int set, const double values[])
1068
{
1069
fluid_mixer_fx_t *fx = mixer->fx;
1070
int nr_units = mixer->fx_units;
1071
1072
if(fx_group >= 0) /* apply parameters to this group fx only */
1073
{
1074
nr_units = fx_group + 1;
1075
}
1076
else /* apply parameters to all fx units*/
1077
{
1078
fx_group = 0;
1079
}
1080
1081
for(; fx_group < nr_units; fx_group++)
1082
{
1083
int param;
1084
1085
for(param = 0; param < FLUID_CHORUS_PARAM_LAST; param++)
1086
{
1087
if(set & FLUID_CHORPARAM_TO_SETFLAG(param))
1088
{
1089
fx[fx_group].chorus_param[param] = values[param];
1090
}
1091
}
1092
}
1093
}
1094
1095
/**
1096
* get one chorus shadow parameter for one fx group.
1097
* (see fluid_rvoice_mixer_set_chorus_full())
1098
*
1099
* @param mixer that contains all fx groups units.
1100
* @param fx_group index of the fx group to get parameter from.
1101
* must be in the range [0..mixer->fx_units[.
1102
* @param get Flags indicating which parameter to get (#fluid_chorus_set_t)
1103
* @return the parameter value (0.0 is returned if error)
1104
*/
1105
double
1106
fluid_rvoice_mixer_chorus_get_param(const fluid_rvoice_mixer_t *mixer,
1107
int fx_group, int param)
1108
{
1109
return mixer->fx[fx_group].chorus_param[param];
1110
}
1111
1112
/* @deprecated: use fluid_rvoice_mixer_reverb_enable instead */
1113
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled)
1114
{
1115
fluid_rvoice_mixer_t *mixer = obj;
1116
int on = param[0].i;
1117
1118
mixer->with_reverb = on;
1119
}
1120
1121
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reverb_enable)
1122
{
1123
fluid_rvoice_mixer_t *mixer = obj;
1124
int fx_group = param[0].i; /* reverb fx group index */
1125
int on = param[1].i; /* on/off */
1126
1127
int nr_units = mixer->fx_units;
1128
1129
/* does on/off must be applied only to fx group at index fx_group ? */
1130
if(fx_group >= 0)
1131
{
1132
mixer->fx[fx_group].reverb_on = on;
1133
}
1134
/* on/off must be applied to all fx groups */
1135
else
1136
{
1137
for(fx_group = 0; fx_group < nr_units; fx_group++)
1138
{
1139
mixer->fx[fx_group].reverb_on = on;
1140
}
1141
}
1142
1143
/* set with_reverb if at least one reverb unit is on */
1144
for(fx_group = 0; fx_group < nr_units; fx_group++)
1145
{
1146
on = mixer->fx[fx_group].reverb_on;
1147
1148
if(on)
1149
{
1150
break;
1151
}
1152
}
1153
1154
mixer->with_reverb = on;
1155
}
1156
1157
/* @deprecated: use fluid_rvoice_mixer_chorus_enable instead */
1158
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled)
1159
{
1160
fluid_rvoice_mixer_t *mixer = obj;
1161
int on = param[0].i;
1162
mixer->with_chorus = on;
1163
}
1164
1165
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_chorus_enable)
1166
{
1167
fluid_rvoice_mixer_t *mixer = obj;
1168
int fx_group = param[0].i; /* chorus fx group index */
1169
int on = param[1].i; /* on/off */
1170
1171
int nr_units = mixer->fx_units;
1172
1173
/* does on/off must be applied only to fx group at index fx_group ? */
1174
if(fx_group >= 0)
1175
{
1176
mixer->fx[fx_group].chorus_on = on;
1177
}
1178
/* on/off must be applied to all fx groups */
1179
else
1180
{
1181
for(fx_group = 0; fx_group < nr_units; fx_group++)
1182
{
1183
mixer->fx[fx_group].chorus_on = on;
1184
}
1185
}
1186
1187
/* set with_chorus if at least one chorus unit is on */
1188
for(fx_group = 0; fx_group < nr_units; fx_group++)
1189
{
1190
on = mixer->fx[fx_group].chorus_on;
1191
1192
if(on)
1193
{
1194
break;
1195
}
1196
}
1197
1198
mixer->with_chorus = on;
1199
}
1200
1201
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on)
1202
{
1203
mixer->mix_fx_to_out = on;
1204
}
1205
1206
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params)
1207
{
1208
fluid_rvoice_mixer_t *mixer = obj;
1209
int i = param[0].i;
1210
int set = param[1].i;
1211
int nr = param[2].i;
1212
fluid_real_t level = param[3].real;
1213
fluid_real_t speed = param[4].real;
1214
fluid_real_t depth_ms = param[5].real;
1215
int type = param[6].i;
1216
1217
int nr_units = mixer->fx_units;
1218
1219
/* does parameters must be applied only to fx group i ? */
1220
if(i >= 0)
1221
{
1222
nr_units = i + 1;
1223
}
1224
else
1225
{
1226
i = 0; /* parameters must be applied to all fx groups */
1227
}
1228
1229
while(i < nr_units)
1230
{
1231
fluid_chorus_set(mixer->fx[i++].chorus, set, nr, level, speed, depth_ms, type);
1232
}
1233
}
1234
1235
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params)
1236
{
1237
fluid_rvoice_mixer_t *mixer = obj;
1238
int i = param[0].i; /* fx group index */
1239
int set = param[1].i;
1240
fluid_real_t roomsize = param[2].real;
1241
fluid_real_t damping = param[3].real;
1242
fluid_real_t width = param[4].real;
1243
fluid_real_t level = param[5].real;
1244
1245
int nr_units = mixer->fx_units;
1246
1247
/* does parameters change should be applied only to fx group i ? */
1248
if(i >= 0)
1249
{
1250
nr_units = i + 1; /* parameters change must be applied to fx groups i */
1251
}
1252
else
1253
{
1254
i = 0; /* parameters change must be applied to all fx groups */
1255
}
1256
1257
while(i < nr_units)
1258
{
1259
fluid_revmodel_set(mixer->fx[i++].reverb, set, roomsize, damping, width, level);
1260
}
1261
}
1262
1263
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb)
1264
{
1265
fluid_rvoice_mixer_t *mixer = obj;
1266
int i;
1267
1268
for(i = 0; i < mixer->fx_units; i++)
1269
{
1270
fluid_revmodel_reset(mixer->fx[i].reverb);
1271
}
1272
}
1273
1274
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus)
1275
{
1276
fluid_rvoice_mixer_t *mixer = obj;
1277
int i;
1278
1279
for(i = 0; i < mixer->fx_units; i++)
1280
{
1281
fluid_chorus_reset(mixer->fx[i].chorus);
1282
}
1283
}
1284
1285
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t *mixer,
1286
fluid_real_t **left, fluid_real_t **right)
1287
{
1288
*left = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT);
1289
*right = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT);
1290
return mixer->buffers.buf_count;
1291
}
1292
1293
int fluid_rvoice_mixer_get_fx_bufs(fluid_rvoice_mixer_t *mixer,
1294
fluid_real_t **fx_left, fluid_real_t **fx_right)
1295
{
1296
*fx_left = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
1297
*fx_right = fluid_align_ptr(mixer->buffers.fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
1298
return mixer->buffers.fx_buf_count;
1299
}
1300
1301
int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer)
1302
{
1303
return FLUID_MIXER_MAX_BUFFERS_DEFAULT;
1304
}
1305
1306
#if WITH_PROFILING
1307
int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t *mixer)
1308
{
1309
return mixer->active_voices;
1310
}
1311
#endif
1312
1313
#if ENABLE_MIXER_THREADS
1314
1315
static FLUID_INLINE fluid_rvoice_t *
1316
fluid_mixer_get_mt_rvoice(fluid_rvoice_mixer_t *mixer)
1317
{
1318
int i = fluid_atomic_int_exchange_and_add(&mixer->current_rvoice, 1);
1319
1320
if(i >= mixer->active_voices)
1321
{
1322
return NULL;
1323
}
1324
1325
return mixer->rvoices[i];
1326
}
1327
1328
#define THREAD_BUF_PROCESSING 0
1329
#define THREAD_BUF_VALID 1
1330
#define THREAD_BUF_NODATA 2
1331
#define THREAD_BUF_TERMINATE 3
1332
1333
/* Core thread function (processes voices in parallel to primary synthesis thread) */
1334
static fluid_thread_return_t
1335
fluid_mixer_thread_func(void *data)
1336
{
1337
fluid_mixer_buffers_t *buffers = data;
1338
fluid_rvoice_mixer_t *mixer = buffers->mixer;
1339
int hasValidData = 0;
1340
FLUID_DECLARE_VLA(fluid_real_t *, bufs, buffers->buf_count * 2 + buffers->fx_buf_count * 2);
1341
int bufcount = 0;
1342
int current_blockcount = 0;
1343
fluid_real_t *local_buf = fluid_align_ptr(buffers->local_buf, FLUID_DEFAULT_ALIGNMENT);
1344
1345
while(!fluid_atomic_int_get(&mixer->threads_should_terminate))
1346
{
1347
fluid_rvoice_t *rvoice = fluid_mixer_get_mt_rvoice(mixer);
1348
1349
if(rvoice == NULL)
1350
{
1351
// if no voices: signal rendered buffers, sleep
1352
fluid_atomic_int_set(&buffers->ready, hasValidData ? THREAD_BUF_VALID : THREAD_BUF_NODATA);
1353
fluid_cond_mutex_lock(mixer->thread_ready_m);
1354
fluid_cond_signal(mixer->thread_ready);
1355
fluid_cond_mutex_unlock(mixer->thread_ready_m);
1356
1357
fluid_cond_mutex_lock(mixer->wakeup_threads_m);
1358
1359
while(1)
1360
{
1361
int j = fluid_atomic_int_get(&buffers->ready);
1362
1363
if(j == THREAD_BUF_PROCESSING || j == THREAD_BUF_TERMINATE)
1364
{
1365
break;
1366
}
1367
1368
fluid_cond_wait(mixer->wakeup_threads, mixer->wakeup_threads_m);
1369
}
1370
1371
fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
1372
1373
hasValidData = 0;
1374
}
1375
else
1376
{
1377
// else: if buffer is not zeroed, zero buffers
1378
if(!hasValidData)
1379
{
1380
// blockcount may have changed, since thread was put to sleep
1381
current_blockcount = mixer->current_blockcount;
1382
fluid_mixer_buffers_zero(buffers, current_blockcount);
1383
bufcount = fluid_mixer_buffers_prepare(buffers, bufs);
1384
hasValidData = 1;
1385
}
1386
1387
// then render voice to buffers
1388
fluid_mixer_buffers_render_one(buffers, rvoice, bufs, bufcount, local_buf, current_blockcount);
1389
}
1390
}
1391
1392
return FLUID_THREAD_RETURN_VALUE;
1393
}
1394
1395
static void
1396
fluid_mixer_buffers_mix(fluid_mixer_buffers_t *dst, fluid_mixer_buffers_t *src, int current_blockcount)
1397
{
1398
int i, j;
1399
int scount = current_blockcount * FLUID_BUFSIZE;
1400
int minbuf;
1401
fluid_real_t *FLUID_RESTRICT base_src;
1402
fluid_real_t *FLUID_RESTRICT base_dst;
1403
1404
minbuf = dst->buf_count;
1405
1406
if(minbuf > src->buf_count)
1407
{
1408
minbuf = src->buf_count;
1409
}
1410
1411
base_src = fluid_align_ptr(src->left_buf, FLUID_DEFAULT_ALIGNMENT);
1412
base_dst = fluid_align_ptr(dst->left_buf, FLUID_DEFAULT_ALIGNMENT);
1413
1414
for(i = 0; i < minbuf; i++)
1415
{
1416
#pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT)
1417
1418
for(j = 0; j < scount; j++)
1419
{
1420
int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
1421
base_dst[dsp_i] += base_src[dsp_i];
1422
}
1423
}
1424
1425
base_src = fluid_align_ptr(src->right_buf, FLUID_DEFAULT_ALIGNMENT);
1426
base_dst = fluid_align_ptr(dst->right_buf, FLUID_DEFAULT_ALIGNMENT);
1427
1428
for(i = 0; i < minbuf; i++)
1429
{
1430
#pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT)
1431
1432
for(j = 0; j < scount; j++)
1433
{
1434
int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
1435
base_dst[dsp_i] += base_src[dsp_i];
1436
}
1437
}
1438
1439
minbuf = dst->fx_buf_count;
1440
1441
if(minbuf > src->fx_buf_count)
1442
{
1443
minbuf = src->fx_buf_count;
1444
}
1445
1446
base_src = fluid_align_ptr(src->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
1447
base_dst = fluid_align_ptr(dst->fx_left_buf, FLUID_DEFAULT_ALIGNMENT);
1448
1449
for(i = 0; i < minbuf; i++)
1450
{
1451
#pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT)
1452
1453
for(j = 0; j < scount; j++)
1454
{
1455
int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
1456
base_dst[dsp_i] += base_src[dsp_i];
1457
}
1458
}
1459
1460
base_src = fluid_align_ptr(src->fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
1461
base_dst = fluid_align_ptr(dst->fx_right_buf, FLUID_DEFAULT_ALIGNMENT);
1462
1463
for(i = 0; i < minbuf; i++)
1464
{
1465
#pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT)
1466
1467
for(j = 0; j < scount; j++)
1468
{
1469
int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
1470
base_dst[dsp_i] += base_src[dsp_i];
1471
}
1472
}
1473
}
1474
1475
1476
/**
1477
* Go through all threads and see if someone is finished for mixing
1478
*/
1479
static int
1480
fluid_mixer_mix_in(fluid_rvoice_mixer_t *mixer, int extra_threads, int current_blockcount)
1481
{
1482
int i, result, hasmixed;
1483
1484
do
1485
{
1486
hasmixed = 0;
1487
result = 0;
1488
1489
for(i = 0; i < extra_threads; i++)
1490
{
1491
int j = fluid_atomic_int_get(&mixer->threads[i].ready);
1492
1493
switch(j)
1494
{
1495
case THREAD_BUF_PROCESSING:
1496
result = 1;
1497
break;
1498
1499
case THREAD_BUF_VALID:
1500
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_NODATA);
1501
fluid_mixer_buffers_mix(&mixer->buffers, &mixer->threads[i], current_blockcount);
1502
hasmixed = 1;
1503
break;
1504
}
1505
}
1506
}
1507
while(hasmixed);
1508
1509
return result;
1510
}
1511
1512
static void
1513
fluid_render_loop_multithread(fluid_rvoice_mixer_t *mixer, int current_blockcount)
1514
{
1515
int i, bufcount;
1516
fluid_real_t *local_buf = fluid_align_ptr(mixer->buffers.local_buf, FLUID_DEFAULT_ALIGNMENT);
1517
1518
FLUID_DECLARE_VLA(fluid_real_t *, bufs,
1519
mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
1520
// How many threads should we start this time?
1521
int extra_threads = mixer->active_voices / VOICES_PER_THREAD;
1522
1523
if(extra_threads > mixer->thread_count)
1524
{
1525
extra_threads = mixer->thread_count;
1526
}
1527
1528
if(extra_threads == 0)
1529
{
1530
// No extra threads? No thread overhead!
1531
fluid_render_loop_singlethread(mixer, current_blockcount);
1532
return;
1533
}
1534
1535
bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
1536
1537
// Prepare voice list
1538
fluid_cond_mutex_lock(mixer->wakeup_threads_m);
1539
fluid_atomic_int_set(&mixer->current_rvoice, 0);
1540
1541
for(i = 0; i < extra_threads; i++)
1542
{
1543
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_PROCESSING);
1544
}
1545
1546
// Signal threads to wake up
1547
fluid_cond_broadcast(mixer->wakeup_threads);
1548
fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
1549
1550
// If thread is finished, mix it in
1551
while(fluid_mixer_mix_in(mixer, extra_threads, current_blockcount))
1552
{
1553
// Otherwise get a voice and render it
1554
fluid_rvoice_t *rvoice = fluid_mixer_get_mt_rvoice(mixer);
1555
1556
if(rvoice != NULL)
1557
{
1558
fluid_profile_ref_var(prof_ref);
1559
fluid_mixer_buffers_render_one(&mixer->buffers, rvoice, bufs, bufcount, local_buf, current_blockcount);
1560
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref, 1,
1561
current_blockcount * FLUID_BUFSIZE);
1562
//test++;
1563
}
1564
else
1565
{
1566
// If no voices, wait for mixes. Make sure one is still processing to avoid deadlock
1567
int is_processing = 0;
1568
//waits++;
1569
fluid_cond_mutex_lock(mixer->thread_ready_m);
1570
1571
for(i = 0; i < extra_threads; i++)
1572
{
1573
if(fluid_atomic_int_get(&mixer->threads[i].ready) ==
1574
THREAD_BUF_PROCESSING)
1575
{
1576
is_processing = 1;
1577
}
1578
}
1579
1580
if(is_processing)
1581
{
1582
fluid_cond_wait(mixer->thread_ready, mixer->thread_ready_m);
1583
}
1584
1585
fluid_cond_mutex_unlock(mixer->thread_ready_m);
1586
}
1587
}
1588
1589
//FLUID_LOG(FLUID_DBG, "Blockcount: %d, mixed %d of %d voices myself, waits = %d",
1590
// current_blockcount, test, mixer->active_voices, waits);
1591
}
1592
1593
static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t *mixer)
1594
{
1595
int i;
1596
1597
// if no threads have been created yet (e.g. because a previous error prevented creation of threads
1598
// mutexes and condition variables), skip terminating threads
1599
if(mixer->thread_count != 0)
1600
{
1601
fluid_atomic_int_set(&mixer->threads_should_terminate, 1);
1602
// Signal threads to wake up
1603
fluid_cond_mutex_lock(mixer->wakeup_threads_m);
1604
1605
for(i = 0; i < mixer->thread_count; i++)
1606
{
1607
fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_TERMINATE);
1608
}
1609
1610
fluid_cond_broadcast(mixer->wakeup_threads);
1611
fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
1612
1613
for(i = 0; i < mixer->thread_count; i++)
1614
{
1615
if(mixer->threads[i].thread)
1616
{
1617
fluid_thread_join(mixer->threads[i].thread);
1618
delete_fluid_thread(mixer->threads[i].thread);
1619
}
1620
1621
fluid_mixer_buffers_free(&mixer->threads[i]);
1622
}
1623
}
1624
1625
FLUID_FREE(mixer->threads);
1626
mixer->thread_count = 0;
1627
mixer->threads = NULL;
1628
}
1629
1630
/**
1631
* Update amount of extra mixer threads.
1632
* @param thread_count Number of extra mixer threads for multi-core rendering
1633
* @param prio_level real-time prio level for the extra mixer threads
1634
*/
1635
static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t *mixer, int thread_count, int prio_level)
1636
{
1637
char name[16];
1638
int i;
1639
1640
// Kill all existing threads first
1641
if(mixer->thread_count)
1642
{
1643
delete_rvoice_mixer_threads(mixer);
1644
}
1645
1646
if(thread_count == 0)
1647
{
1648
return FLUID_OK;
1649
}
1650
1651
// Now prepare the new threads
1652
fluid_atomic_int_set(&mixer->threads_should_terminate, 0);
1653
mixer->threads = FLUID_ARRAY(fluid_mixer_buffers_t, thread_count);
1654
1655
if(mixer->threads == NULL)
1656
{
1657
FLUID_LOG(FLUID_ERR, "Out of memory");
1658
return FLUID_FAILED;
1659
}
1660
1661
FLUID_MEMSET(mixer->threads, 0, thread_count * sizeof(fluid_mixer_buffers_t));
1662
mixer->thread_count = thread_count;
1663
1664
for(i = 0; i < thread_count; i++)
1665
{
1666
fluid_mixer_buffers_t *b = &mixer->threads[i];
1667
1668
if(!fluid_mixer_buffers_init(b, mixer))
1669
{
1670
return FLUID_FAILED;
1671
}
1672
1673
fluid_atomic_int_set(&b->ready, THREAD_BUF_NODATA);
1674
FLUID_SNPRINTF(name, sizeof(name), "mixer%d", i);
1675
b->thread = new_fluid_thread(name, fluid_mixer_thread_func, b, prio_level, 0);
1676
1677
if(!b->thread)
1678
{
1679
return FLUID_FAILED;
1680
}
1681
}
1682
1683
return FLUID_OK;
1684
}
1685
#endif
1686
1687
/**
1688
* Synthesize audio into buffers
1689
* @param blockcount number of blocks to render, each having FLUID_BUFSIZE samples
1690
* @return number of blocks rendered
1691
*/
1692
int
1693
fluid_rvoice_mixer_render(fluid_rvoice_mixer_t *mixer, int blockcount)
1694
{
1695
fluid_profile_ref_var(prof_ref);
1696
1697
mixer->current_blockcount = blockcount;
1698
1699
// Zero buffers
1700
fluid_mixer_buffers_zero(&mixer->buffers, blockcount);
1701
fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref, mixer->active_voices,
1702
blockcount * FLUID_BUFSIZE);
1703
1704
#if ENABLE_MIXER_THREADS
1705
1706
if(mixer->thread_count > 0)
1707
{
1708
fluid_render_loop_multithread(mixer, blockcount);
1709
}
1710
else
1711
#endif
1712
{
1713
fluid_render_loop_singlethread(mixer, blockcount);
1714
}
1715
1716
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref, mixer->active_voices,
1717
blockcount * FLUID_BUFSIZE);
1718
1719
1720
// Process reverb & chorus
1721
fluid_rvoice_mixer_process_fx(mixer, blockcount);
1722
1723
// Call the callback and pack active voice array
1724
fluid_rvoice_mixer_process_finished_voices(mixer);
1725
1726
return blockcount;
1727
}
1728
1729