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 Library General Public License
7 * as published by the Free Software Foundation; either version 2 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 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library 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_mixer.h"
22 #include "fluid_rvoice.h"
23 #include "fluid_sys.h"
24 #include "fluid_rev.h"
25 #include "fluid_chorus.h"
26 #include "fluidsynth_priv.h"
27 //#include "fluid_ladspa.h"
29 #define SYNTH_REVERB_CHANNEL 0
30 #define SYNTH_CHORUS_CHANNEL 1
32 #undef ENABLE_MIXER_THREADS // Ardour does the multithreading -- synth.cpu-cores defaults to 1
34 // If less than x voices, the thread overhead is larger than the gain,
35 // so don't activate the thread(s).
36 #define VOICES_PER_THREAD 8
38 typedef struct _fluid_mixer_buffers_t fluid_mixer_buffers_t;
40 struct _fluid_mixer_buffers_t {
41 fluid_rvoice_mixer_t* mixer; /**< Owner of object */
42 #ifdef ENABLE_MIXER_THREADS
43 fluid_thread_t* thread; /**< Thread object */
46 fluid_rvoice_t** finished_voices; /* List of voices who have finished */
47 int finished_voice_count;
49 int ready; /**< Atomic: buffers are ready for mixing */
51 int buf_blocks; /**< Number of blocks allocated in the buffers */
54 fluid_real_t** left_buf;
55 fluid_real_t** right_buf;
58 fluid_real_t** fx_left_buf;
59 fluid_real_t** fx_right_buf;
62 typedef struct _fluid_mixer_fx_t fluid_mixer_fx_t;
64 struct _fluid_mixer_fx_t {
65 fluid_revmodel_t* reverb; /**< Reverb unit */
66 fluid_chorus_t* chorus; /**< Chorus unit */
67 int with_reverb; /**< Should the synth use the built-in reverb unit? */
68 int with_chorus; /**< Should the synth use the built-in chorus unit? */
69 int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */
72 struct _fluid_rvoice_mixer_t {
75 fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
76 void (*remove_voice_callback)(void*, fluid_rvoice_t*); /**< Used by mixer only: Receive this callback every time a voice is removed */
77 void* remove_voice_callback_userdata;
79 fluid_rvoice_t** rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
80 int polyphony; /**< Read-only: Length of voices array */
81 int active_voices; /**< Read-only: Number of non-null voices */
82 int current_blockcount; /**< Read-only: how many blocks to process this time */
85 fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */
88 #ifdef ENABLE_MIXER_THREADS
89 // int sleeping_threads; /**< Atomic: number of threads currently asleep */
90 // int active_threads; /**< Atomic: number of threads in the thread loop */
91 int threads_should_terminate; /**< Atomic: Set to TRUE when threads should terminate */
92 int current_rvoice; /**< Atomic: for the threads to know next voice to */
93 fluid_cond_t* wakeup_threads; /**< Signalled when the threads should wake up */
94 fluid_cond_mutex_t* wakeup_threads_m; /**< wakeup_threads mutex companion */
95 fluid_cond_t* thread_ready; /**< Signalled from thread, when the thread has a buffer ready for mixing */
96 fluid_cond_mutex_t* thread_ready_m; /**< thread_ready mutex companion */
98 int thread_count; /**< Number of extra mixer threads for multi-core rendering */
99 fluid_mixer_buffers_t* threads; /**< Array of mixer threads (thread_count in length) */
103 static FLUID_INLINE void
104 fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
107 fluid_profile_ref_var(prof_ref);
108 if (mixer->fx.with_reverb) {
109 if (mixer->fx.mix_fx_to_out) {
110 for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
111 fluid_revmodel_processmix(mixer->fx.reverb,
112 &mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
113 &mixer->buffers.left_buf[0][i],
114 &mixer->buffers.right_buf[0][i]);
117 for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
118 fluid_revmodel_processreplace(mixer->fx.reverb,
119 &mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
120 &mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL][i],
121 &mixer->buffers.fx_right_buf[SYNTH_REVERB_CHANNEL][i]);
123 fluid_profile(FLUID_PROF_ONE_BLOCK_REVERB, prof_ref);
126 if (mixer->fx.with_chorus) {
127 if (mixer->fx.mix_fx_to_out) {
128 for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
129 fluid_chorus_processmix(mixer->fx.chorus,
130 &mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
131 &mixer->buffers.left_buf[0][i],
132 &mixer->buffers.right_buf[0][i]);
135 for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE)
136 fluid_chorus_processreplace(mixer->fx.chorus,
137 &mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
138 &mixer->buffers.fx_left_buf[SYNTH_CHORUS_CHANNEL][i],
139 &mixer->buffers.fx_right_buf[SYNTH_CHORUS_CHANNEL][i]);
141 fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref);
145 /* Run the signal through the LADSPA Fx unit */
146 if (mixer->LADSPA_FxUnit) {
148 FLUID_DECLARE_VLA(fluid_real_t*, left_buf, mixer->buffers.buf_count);
149 FLUID_DECLARE_VLA(fluid_real_t*, right_buf, mixer->buffers.buf_count);
150 FLUID_DECLARE_VLA(fluid_real_t*, fx_left_buf, mixer->buffers.fx_buf_count);
151 FLUID_DECLARE_VLA(fluid_real_t*, fx_right_buf, mixer->buffers.fx_buf_count);
152 for (j=0; j < mixer->buffers.buf_count; j++) {
153 left_buf[j] = mixer->buffers.left_buf[j];
154 right_buf[j] = mixer->buffers.right_buf[j];
156 for (j=0; j < mixer->buffers.fx_buf_count; j++) {
157 fx_left_buf[j] = mixer->buffers.fx_left_buf[j];
158 fx_right_buf[j] = mixer->buffers.fx_right_buf[j];
160 for (i=0; i < mixer->current_blockcount * FLUID_BUFSIZE; i += FLUID_BUFSIZE) {
161 fluid_LADSPA_run(mixer->LADSPA_FxUnit, left_buf, right_buf, fx_left_buf,
163 for (j=0; j < mixer->buffers.buf_count; j++) {
164 left_buf[j] += FLUID_BUFSIZE;
165 right_buf[j] += FLUID_BUFSIZE;
167 for (j=0; j < mixer->buffers.fx_buf_count; j++) {
168 fx_left_buf[j] += FLUID_BUFSIZE;
169 fx_right_buf[j] += FLUID_BUFSIZE;
172 fluid_check_fpe("LADSPA");
178 * During rendering, rvoices might be finished. Set this callback
179 * for getting a callback any time the rvoice is finished.
181 void fluid_rvoice_mixer_set_finished_voices_callback(
182 fluid_rvoice_mixer_t* mixer,
183 void (*func)(void*, fluid_rvoice_t*),
186 mixer->remove_voice_callback_userdata = userdata;
187 mixer->remove_voice_callback = func;
193 * Synthesize one voice and add to buffer.
194 * NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
195 * voice has been finished, removed and possibly replaced with another voice.
196 * @return Number of samples written
199 fluid_mix_one(fluid_rvoice_t* rvoice, fluid_real_t** bufs, unsigned int bufcount, int blockcount)
203 FLUID_DECLARE_VLA(fluid_real_t, local_buf, FLUID_BUFSIZE*blockcount);
205 for (i=0; i < blockcount; i++) {
206 int s = fluid_rvoice_write(rvoice, &local_buf[FLUID_BUFSIZE*i]);
208 s = FLUID_BUFSIZE; /* Voice is quiet, TODO: optimize away memset/mix */
209 FLUID_MEMSET(&local_buf[FLUID_BUFSIZE*i], 0, FLUID_BUFSIZE*sizeof(fluid_real_t));
212 if (s < FLUID_BUFSIZE) {
216 fluid_rvoice_buffers_mix(&rvoice->buffers, local_buf, result, bufs, bufcount);
222 * Glue to get fluid_rvoice_buffers_mix what it wants
223 * Note: Make sure outbufs has 2 * (buf_count + fx_buf_count) elements before calling
225 static FLUID_INLINE int
226 fluid_mixer_buffers_prepare(fluid_mixer_buffers_t* buffers, fluid_real_t** outbufs)
228 fluid_real_t* reverb_buf, *chorus_buf;
231 /* Set up the reverb / chorus buffers only, when the effect is
232 * enabled on synth level. Nonexisting buffers are detected in the
233 * DSP loop. Not sending the reverb / chorus signal saves some time
235 reverb_buf = buffers->mixer->fx.with_reverb ? buffers->fx_left_buf[SYNTH_REVERB_CHANNEL] : NULL;
236 chorus_buf = buffers->mixer->fx.with_chorus ? buffers->fx_left_buf[SYNTH_CHORUS_CHANNEL] : NULL;
237 outbufs[buffers->buf_count*2 + SYNTH_REVERB_CHANNEL] = reverb_buf;
238 outbufs[buffers->buf_count*2 + SYNTH_CHORUS_CHANNEL] = chorus_buf;
240 /* The output associated with a MIDI channel is wrapped around
241 * using the number of audio groups as modulo divider. This is
242 * typically the number of output channels on the 'sound card',
243 * as long as the LADSPA Fx unit is not used. In case of LADSPA
244 * unit, think of it as subgroups on a mixer.
246 * For example: Assume that the number of groups is set to 2.
247 * Then MIDI channel 1, 3, 5, 7 etc. go to output 1, channels 2,
248 * 4, 6, 8 etc to output 2. Or assume 3 groups: Then MIDI
249 * channels 1, 4, 7, 10 etc go to output 1; 2, 5, 8, 11 etc to
250 * output 2, 3, 6, 9, 12 etc to output 3.
253 for (i = 0; i < buffers->buf_count; i++) {
254 outbufs[i*2] = buffers->left_buf[i];
255 outbufs[i*2+1] = buffers->right_buf[i];
257 return buffers->buf_count*2 + 2;
261 static FLUID_INLINE void
262 fluid_finish_rvoice(fluid_mixer_buffers_t* buffers, fluid_rvoice_t* rvoice)
264 if (buffers->finished_voice_count < buffers->mixer->polyphony)
265 buffers->finished_voices[buffers->finished_voice_count++] = rvoice;
267 FLUID_LOG(FLUID_ERR, "Exceeded finished voices array, try increasing polyphony");
271 fluid_mixer_buffer_process_finished_voices(fluid_mixer_buffers_t* buffers)
274 for (i=0; i < buffers->finished_voice_count; i++) {
275 fluid_rvoice_t* v = buffers->finished_voices[i];
276 int* av = &buffers->mixer->active_voices;
277 for (j=0; j < *av; j++) {
278 if (v == buffers->mixer->rvoices[j]) {
282 buffers->mixer->rvoices[j] = buffers->mixer->rvoices[*av];
285 if (buffers->mixer->remove_voice_callback)
286 buffers->mixer->remove_voice_callback(
287 buffers->mixer->remove_voice_callback_userdata, v);
289 buffers->finished_voice_count = 0;
292 static FLUID_INLINE void fluid_rvoice_mixer_process_finished_voices(fluid_rvoice_mixer_t* mixer)
294 #ifdef ENABLE_MIXER_THREADS
296 for (i=0; i < mixer->thread_count; i++)
297 fluid_mixer_buffer_process_finished_voices(&mixer->threads[i]);
299 fluid_mixer_buffer_process_finished_voices(&mixer->buffers);
302 static FLUID_INLINE void
303 fluid_mixer_buffers_render_one(fluid_mixer_buffers_t* buffers,
304 fluid_rvoice_t* voice, fluid_real_t** bufs,
305 unsigned int bufcount)
307 int s = fluid_mix_one(voice, bufs, bufcount, buffers->mixer->current_blockcount);
308 if (s < buffers->mixer->current_blockcount * FLUID_BUFSIZE) {
309 fluid_finish_rvoice(buffers, voice);
313 static int fluid_mixer_buffers_replace_voice(fluid_mixer_buffers_t* buffers,
314 fluid_rvoice_t* voice)
317 int fvc = buffers->finished_voice_count;
318 for (i=0; i < fvc; i++)
319 if (buffers->finished_voices[i] == voice) {
322 buffers->finished_voices[i] = buffers->finished_voices[fvc];
325 fvc = buffers->finished_voice_count;
331 fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice)
335 if (mixer->active_voices < mixer->polyphony) {
336 mixer->rvoices[mixer->active_voices++] = voice;
340 /* See if any voices just finished, if so, take its place.
341 This can happen in voice overflow conditions. */
342 for (i=0; i < mixer->active_voices; i++) {
343 if (mixer->rvoices[i] == voice) {
344 FLUID_LOG(FLUID_ERR, "Internal error: Trying to replace an existing rvoice in fluid_rvoice_mixer_add_voice?!");
347 if (mixer->rvoices[i]->envlfo.volenv.section == FLUID_VOICE_ENVFINISHED) {
348 fluid_finish_rvoice(&mixer->buffers, mixer->rvoices[i]);
349 mixer->rvoices[i] = voice;
354 /* This should never happen */
355 FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice");
360 fluid_mixer_buffers_update_polyphony(fluid_mixer_buffers_t* buffers, int value)
364 if (buffers->finished_voice_count > value)
367 newptr = FLUID_REALLOC(buffers->finished_voices, value * sizeof(fluid_rvoice_t*));
368 if (newptr == NULL && value > 0)
370 buffers->finished_voices = newptr;
375 * Update polyphony - max number of voices (NOTE: not hard real-time capable)
376 * @return FLUID_OK or FLUID_FAILED
379 fluid_rvoice_mixer_set_polyphony(fluid_rvoice_mixer_t* handler, int value)
382 if (handler->active_voices > value)
385 newptr = FLUID_REALLOC(handler->rvoices, value * sizeof(fluid_rvoice_t*));
388 handler->rvoices = newptr;
390 if (fluid_mixer_buffers_update_polyphony(&handler->buffers, value)
394 #ifdef ENABLE_MIXER_THREADS
397 for (i=0; i < handler->thread_count; i++)
398 if (fluid_mixer_buffers_update_polyphony(&handler->threads[i], value)
404 handler->polyphony = value;
410 fluid_render_loop_singlethread(fluid_rvoice_mixer_t* mixer)
413 FLUID_DECLARE_VLA(fluid_real_t*, bufs,
414 mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
415 int bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
416 fluid_profile_ref_var(prof_ref);
417 for (i=0; i < mixer->active_voices; i++) {
418 fluid_mixer_buffers_render_one(&mixer->buffers, mixer->rvoices[i], bufs,
420 fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref);
425 static FLUID_INLINE void
426 fluid_mixer_buffers_zero(fluid_mixer_buffers_t* buffers)
429 int size = buffers->mixer->current_blockcount * FLUID_BUFSIZE * sizeof(fluid_real_t);
430 /* TODO: Optimize by only zero out the buffers we actually use later on. */
431 for (i=0; i < buffers->buf_count; i++) {
432 FLUID_MEMSET(buffers->left_buf[i], 0, size);
433 FLUID_MEMSET(buffers->right_buf[i], 0, size);
435 for (i=0; i < buffers->fx_buf_count; i++) {
436 FLUID_MEMSET(buffers->fx_left_buf[i], 0, size);
437 FLUID_MEMSET(buffers->fx_right_buf[i], 0, size);
444 fluid_mixer_buffers_init(fluid_mixer_buffers_t* buffers, fluid_rvoice_mixer_t* mixer)
448 buffers->mixer = mixer;
449 buffers->buf_count = buffers->mixer->buffers.buf_count;
450 buffers->fx_buf_count = buffers->mixer->buffers.fx_buf_count;
451 buffers->buf_blocks = buffers->mixer->buffers.buf_blocks;
452 samplecount = FLUID_BUFSIZE * buffers->buf_blocks;
455 /* Left and right audio buffers */
457 buffers->left_buf = FLUID_ARRAY(fluid_real_t*, buffers->buf_count);
458 buffers->right_buf = FLUID_ARRAY(fluid_real_t*, buffers->buf_count);
460 if ((buffers->left_buf == NULL) || (buffers->right_buf == NULL)) {
461 FLUID_LOG(FLUID_ERR, "Out of memory");
465 FLUID_MEMSET(buffers->left_buf, 0, buffers->buf_count * sizeof(fluid_real_t*));
466 FLUID_MEMSET(buffers->right_buf, 0, buffers->buf_count * sizeof(fluid_real_t*));
468 for (i = 0; i < buffers->buf_count; i++) {
470 buffers->left_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
471 buffers->right_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
473 if ((buffers->left_buf[i] == NULL) || (buffers->right_buf[i] == NULL)) {
474 FLUID_LOG(FLUID_ERR, "Out of memory");
479 /* Effects audio buffers */
481 buffers->fx_left_buf = FLUID_ARRAY(fluid_real_t*, buffers->fx_buf_count);
482 buffers->fx_right_buf = FLUID_ARRAY(fluid_real_t*, buffers->fx_buf_count);
484 if ((buffers->fx_left_buf == NULL) || (buffers->fx_right_buf == NULL)) {
485 FLUID_LOG(FLUID_ERR, "Out of memory");
489 FLUID_MEMSET(buffers->fx_left_buf, 0, buffers->fx_buf_count * sizeof(fluid_real_t*));
490 FLUID_MEMSET(buffers->fx_right_buf, 0, buffers->fx_buf_count * sizeof(fluid_real_t*));
492 for (i = 0; i < buffers->fx_buf_count; i++) {
493 buffers->fx_left_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
494 buffers->fx_right_buf[i] = FLUID_ARRAY(fluid_real_t, samplecount);
496 if ((buffers->fx_left_buf[i] == NULL) || (buffers->fx_right_buf[i] == NULL)) {
497 FLUID_LOG(FLUID_ERR, "Out of memory");
502 buffers->finished_voices = NULL;
503 if (fluid_mixer_buffers_update_polyphony(buffers, mixer->polyphony)
505 FLUID_LOG(FLUID_ERR, "Out of memory");
513 * Note: Not hard real-time capable (calls malloc)
516 fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samplerate)
519 if (mixer->fx.chorus)
520 delete_fluid_chorus(mixer->fx.chorus);
521 mixer->fx.chorus = new_fluid_chorus(samplerate);
522 if (mixer->fx.reverb)
523 fluid_revmodel_samplerate_change(mixer->fx.reverb, samplerate);
524 for (i=0; i < mixer->active_voices; i++)
525 fluid_rvoice_set_output_rate(mixer->rvoices[i], samplerate);
530 * @param buf_count number of primary stereo buffers
531 * @param fx_buf_count number of stereo effect buffers
533 fluid_rvoice_mixer_t*
534 new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate)
536 fluid_rvoice_mixer_t* mixer = FLUID_NEW(fluid_rvoice_mixer_t);
538 FLUID_LOG(FLUID_ERR, "Out of memory");
541 FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
542 mixer->buffers.buf_count = buf_count;
543 mixer->buffers.fx_buf_count = fx_buf_count;
544 mixer->buffers.buf_blocks = FLUID_MIXER_MAX_BUFFERS_DEFAULT;
546 /* allocate the reverb module */
547 mixer->fx.reverb = new_fluid_revmodel(sample_rate);
548 mixer->fx.chorus = new_fluid_chorus(sample_rate);
549 if (mixer->fx.reverb == NULL) {
550 FLUID_LOG(FLUID_ERR, "Out of memory");
551 delete_fluid_rvoice_mixer(mixer);
555 if (!fluid_mixer_buffers_init(&mixer->buffers, mixer)) {
556 delete_fluid_rvoice_mixer(mixer);
560 #ifdef ENABLE_MIXER_THREADS
561 mixer->thread_ready = new_fluid_cond();
562 mixer->wakeup_threads = new_fluid_cond();
563 mixer->thread_ready_m = new_fluid_cond_mutex();
564 mixer->wakeup_threads_m = new_fluid_cond_mutex();
565 if (!mixer->thread_ready || !mixer->wakeup_threads ||
566 !mixer->thread_ready_m || !mixer->wakeup_threads_m) {
567 delete_fluid_rvoice_mixer(mixer);
576 fluid_mixer_buffers_free(fluid_mixer_buffers_t* buffers)
580 FLUID_FREE(buffers->finished_voices);
582 /* free all the sample buffers */
583 if (buffers->left_buf != NULL) {
584 for (i = 0; i < buffers->buf_count; i++) {
585 if (buffers->left_buf[i] != NULL) {
586 FLUID_FREE(buffers->left_buf[i]);
589 FLUID_FREE(buffers->left_buf);
592 if (buffers->right_buf != NULL) {
593 for (i = 0; i < buffers->buf_count; i++) {
594 if (buffers->right_buf[i] != NULL) {
595 FLUID_FREE(buffers->right_buf[i]);
598 FLUID_FREE(buffers->right_buf);
601 if (buffers->fx_left_buf != NULL) {
602 for (i = 0; i < buffers->fx_buf_count; i++) {
603 if (buffers->fx_left_buf[i] != NULL) {
604 FLUID_FREE(buffers->fx_left_buf[i]);
607 FLUID_FREE(buffers->fx_left_buf);
610 if (buffers->fx_right_buf != NULL) {
611 for (i = 0; i < buffers->fx_buf_count; i++) {
612 if (buffers->fx_right_buf[i] != NULL) {
613 FLUID_FREE(buffers->fx_right_buf[i]);
616 FLUID_FREE(buffers->fx_right_buf);
620 void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t* mixer)
624 fluid_rvoice_mixer_set_threads(mixer, 0, 0);
625 #ifdef ENABLE_MIXER_THREADS
626 if (mixer->thread_ready)
627 delete_fluid_cond(mixer->thread_ready);
628 if (mixer->wakeup_threads)
629 delete_fluid_cond(mixer->wakeup_threads);
630 if (mixer->thread_ready_m)
631 delete_fluid_cond_mutex(mixer->thread_ready_m);
632 if (mixer->wakeup_threads_m)
633 delete_fluid_cond_mutex(mixer->wakeup_threads_m);
635 fluid_mixer_buffers_free(&mixer->buffers);
636 if (mixer->fx.reverb)
637 delete_fluid_revmodel(mixer->fx.reverb);
638 if (mixer->fx.chorus)
639 delete_fluid_chorus(mixer->fx.chorus);
640 FLUID_FREE(mixer->rvoices);
646 void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
647 fluid_LADSPA_FxUnit_t* ladspa)
649 mixer->LADSPA_FxUnit = ladspa;
653 void fluid_rvoice_mixer_set_reverb_enabled(fluid_rvoice_mixer_t* mixer, int on)
655 mixer->fx.with_reverb = on;
658 void fluid_rvoice_mixer_set_chorus_enabled(fluid_rvoice_mixer_t* mixer, int on)
660 mixer->fx.with_chorus = on;
663 void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on)
665 mixer->fx.mix_fx_to_out = on;
668 void fluid_rvoice_mixer_set_chorus_params(fluid_rvoice_mixer_t* mixer, int set,
669 int nr, double level, double speed,
670 double depth_ms, int type)
672 fluid_chorus_set(mixer->fx.chorus, set, nr, level, speed, depth_ms, type);
674 void fluid_rvoice_mixer_set_reverb_params(fluid_rvoice_mixer_t* mixer, int set,
675 double roomsize, double damping,
676 double width, double level)
678 fluid_revmodel_set(mixer->fx.reverb, set, roomsize, damping, width, level);
681 void fluid_rvoice_mixer_reset_fx(fluid_rvoice_mixer_t* mixer)
683 fluid_revmodel_reset(mixer->fx.reverb);
684 fluid_chorus_reset(mixer->fx.chorus);
687 void fluid_rvoice_mixer_reset_reverb(fluid_rvoice_mixer_t* mixer)
689 fluid_revmodel_reset(mixer->fx.reverb);
692 void fluid_rvoice_mixer_reset_chorus(fluid_rvoice_mixer_t* mixer)
694 fluid_chorus_reset(mixer->fx.chorus);
697 int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
698 fluid_real_t*** left, fluid_real_t*** right)
700 *left = mixer->buffers.left_buf;
701 *right = mixer->buffers.right_buf;
702 return mixer->buffers.buf_count;
706 #ifdef ENABLE_MIXER_THREADS
708 static FLUID_INLINE fluid_rvoice_t*
709 fluid_mixer_get_mt_rvoice(fluid_rvoice_mixer_t* mixer)
711 int i = fluid_atomic_int_exchange_and_add(&mixer->current_rvoice, 1);
712 if (i >= mixer->active_voices)
714 return mixer->rvoices[i];
717 #define THREAD_BUF_PROCESSING 0
718 #define THREAD_BUF_VALID 1
719 #define THREAD_BUF_NODATA 2
720 #define THREAD_BUF_TERMINATE 3
722 /* Core thread function (processes voices in parallel to primary synthesis thread) */
724 fluid_mixer_thread_func (void* data)
726 fluid_mixer_buffers_t* buffers = data;
727 fluid_rvoice_mixer_t* mixer = buffers->mixer;
728 int hasValidData = 0;
729 FLUID_DECLARE_VLA(fluid_real_t*, bufs, buffers->buf_count*2 + buffers->fx_buf_count*2);
732 while (!fluid_atomic_int_get(&mixer->threads_should_terminate)) {
733 fluid_rvoice_t* rvoice = fluid_mixer_get_mt_rvoice(mixer);
734 if (rvoice == NULL) {
735 // if no voices: signal rendered buffers, sleep
736 fluid_atomic_int_set(&buffers->ready, hasValidData ? THREAD_BUF_VALID : THREAD_BUF_NODATA);
737 fluid_cond_mutex_lock(mixer->thread_ready_m);
738 fluid_cond_signal(mixer->thread_ready);
739 fluid_cond_mutex_unlock(mixer->thread_ready_m);
741 fluid_cond_mutex_lock(mixer->wakeup_threads_m);
743 int j = fluid_atomic_int_get(&buffers->ready);
744 if (j == THREAD_BUF_PROCESSING || j == THREAD_BUF_TERMINATE)
746 fluid_cond_wait(mixer->wakeup_threads, mixer->wakeup_threads_m);
748 fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
753 // else: if buffer is not zeroed, zero buffers
755 fluid_mixer_buffers_zero(buffers);
756 bufcount = fluid_mixer_buffers_prepare(buffers, bufs);
759 // then render voice to buffers
760 fluid_mixer_buffers_render_one(buffers, rvoice, bufs, bufcount);
767 fluid_mixer_buffers_mix(fluid_mixer_buffers_t* dest, fluid_mixer_buffers_t* src)
770 int scount = dest->mixer->current_blockcount * FLUID_BUFSIZE;
773 minbuf = dest->buf_count;
774 if (minbuf > src->buf_count)
775 minbuf = src->buf_count;
776 for (i=0; i < minbuf; i++) {
777 for (j=0; j < scount; j++) {
778 dest->left_buf[i][j] += src->left_buf[i][j];
779 dest->right_buf[i][j] += src->right_buf[i][j];
783 minbuf = dest->fx_buf_count;
784 if (minbuf > src->fx_buf_count)
785 minbuf = src->fx_buf_count;
786 for (i=0; i < minbuf; i++) {
787 for (j=0; j < scount; j++) {
788 dest->fx_left_buf[i][j] += src->fx_left_buf[i][j];
789 dest->fx_right_buf[i][j] += src->fx_right_buf[i][j];
796 * Go through all threads and see if someone is finished for mixing
798 static FLUID_INLINE int
799 fluid_mixer_mix_in(fluid_rvoice_mixer_t* mixer, int extra_threads)
801 int i, result, hasmixed;
805 for (i=0; i < extra_threads; i++) {
806 int j = fluid_atomic_int_get(&mixer->threads[i].ready);
808 case THREAD_BUF_PROCESSING:
811 case THREAD_BUF_VALID:
812 fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_NODATA);
813 fluid_mixer_buffers_mix(&mixer->buffers, &mixer->threads[i]);
823 fluid_render_loop_multithread(fluid_rvoice_mixer_t* mixer)
826 //int scount = mixer->current_blockcount * FLUID_BUFSIZE;
827 FLUID_DECLARE_VLA(fluid_real_t*, bufs,
828 mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2);
829 // How many threads should we start this time?
830 int extra_threads = mixer->active_voices / VOICES_PER_THREAD;
831 if (extra_threads > mixer->thread_count)
832 extra_threads = mixer->thread_count;
833 if (extra_threads == 0) {
834 // No extra threads? No thread overhead!
835 fluid_render_loop_singlethread(mixer);
839 bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs);
841 // Prepare voice list
842 fluid_cond_mutex_lock(mixer->wakeup_threads_m);
843 fluid_atomic_int_set(&mixer->current_rvoice, 0);
844 for (i=0; i < extra_threads; i++)
845 fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_PROCESSING);
846 // Signal threads to wake up
847 fluid_cond_broadcast(mixer->wakeup_threads);
848 fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
850 // If thread is finished, mix it in
851 while (fluid_mixer_mix_in(mixer, extra_threads)) {
852 // Otherwise get a voice and render it
853 fluid_rvoice_t* rvoice = fluid_mixer_get_mt_rvoice(mixer);
854 if (rvoice != NULL) {
855 fluid_profile_ref_var(prof_ref);
856 fluid_mixer_buffers_render_one(&mixer->buffers, rvoice, bufs, bufcount);
857 fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref);
861 // If no voices, wait for mixes. Make sure one is still processing to avoid deadlock
862 int is_processing = 0;
864 fluid_cond_mutex_lock(mixer->thread_ready_m);
865 for (i=0; i < extra_threads; i++)
866 if (fluid_atomic_int_get(&mixer->threads[i].ready) ==
867 THREAD_BUF_PROCESSING)
870 fluid_cond_wait(mixer->thread_ready, mixer->thread_ready_m);
871 fluid_cond_mutex_unlock(mixer->thread_ready_m);
874 //FLUID_LOG(FLUID_DBG, "Blockcount: %d, mixed %d of %d voices myself, waits = %d",
875 // mixer->current_blockcount, test, mixer->active_voices, waits);
881 * Update amount of extra mixer threads.
882 * @param thread_count Number of extra mixer threads for multi-core rendering
883 * @param prio_level real-time prio level for the extra mixer threads
886 fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_count,
889 #ifdef ENABLE_MIXER_THREADS
893 // Kill all existing threads first
894 if (mixer->thread_count) {
895 fluid_atomic_int_set(&mixer->threads_should_terminate, 1);
896 // Signal threads to wake up
897 fluid_cond_mutex_lock(mixer->wakeup_threads_m);
898 for (i=0; i < mixer->thread_count; i++)
899 fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_TERMINATE);
900 fluid_cond_broadcast(mixer->wakeup_threads);
901 fluid_cond_mutex_unlock(mixer->wakeup_threads_m);
903 for (i=0; i < mixer->thread_count; i++) {
904 if (mixer->threads[i].thread) {
905 fluid_thread_join(mixer->threads[i].thread);
906 delete_fluid_thread(mixer->threads[i].thread);
908 fluid_mixer_buffers_free(&mixer->threads[i]);
910 FLUID_FREE(mixer->threads);
911 mixer->thread_count = 0;
912 mixer->threads = NULL;
915 if (thread_count == 0)
918 // Now prepare the new threads
919 fluid_atomic_int_set(&mixer->threads_should_terminate, 0);
920 mixer->threads = FLUID_ARRAY(fluid_mixer_buffers_t, thread_count);
921 if (mixer->threads == NULL) {
922 FLUID_LOG(FLUID_ERR, "Out of memory");
925 FLUID_MEMSET(mixer->threads, 0, thread_count*sizeof(fluid_mixer_buffers_t));
926 mixer->thread_count = thread_count;
927 for (i=0; i < thread_count; i++) {
928 fluid_mixer_buffers_t* b = &mixer->threads[i];
929 if (!fluid_mixer_buffers_init(b, mixer))
931 fluid_atomic_int_set(&b->ready, THREAD_BUF_NODATA);
932 g_snprintf (name, sizeof (name), "mixer%d", i);
933 b->thread = new_fluid_thread(name, fluid_mixer_thread_func, b, prio_level, 0);
942 * Synthesize audio into buffers
943 * @param blockcount number of blocks to render, each having FLUID_BUFSIZE samples
944 * @return number of blocks rendered
947 fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount)
949 fluid_profile_ref_var(prof_ref);
951 mixer->current_blockcount = blockcount > mixer->buffers.buf_blocks ?
952 mixer->buffers.buf_blocks : blockcount;
955 fluid_mixer_buffers_zero(&mixer->buffers);
956 fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref);
958 #ifdef ENABLE_MIXER_THREADS
959 if (mixer->thread_count > 0)
960 fluid_render_loop_multithread(mixer);
963 fluid_render_loop_singlethread(mixer);
964 fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref);
967 // Process reverb & chorus
968 fluid_rvoice_mixer_process_fx(mixer);
970 // Call the callback and pack active voice array
971 fluid_rvoice_mixer_process_finished_voices(mixer);
973 return mixer->current_blockcount;