Update Fluidsynth to 2.0.1
[ardour.git] / libs / fluidsynth / src / fluid_rvoice_event.c
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_event.h"
22 #include "fluid_rvoice.h"
23 #include "fluid_rvoice_mixer.h"
24 #include "fluid_iir_filter.h"
25 #include "fluid_lfo.h"
26 #include "fluid_adsr_env.h"
27
28 static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event);
29
30 static FLUID_INLINE void
31 fluid_rvoice_event_dispatch(fluid_rvoice_event_t *event)
32 {
33     event->method(event->object, event->param);
34 }
35
36
37 /**
38  * In order to be able to push more than one event atomically,
39  * use push for all events, then use flush to commit them to the
40  * queue. If threadsafe is false, all events are processed immediately. */
41 int
42 fluid_rvoice_eventhandler_push_int_real(fluid_rvoice_eventhandler_t *handler,
43                                         fluid_rvoice_function_t method, void *object, int intparam,
44                                         fluid_real_t realparam)
45 {
46     fluid_rvoice_event_t local_event;
47
48     local_event.method = method;
49     local_event.object = object;
50     local_event.param[0].i = intparam;
51     local_event.param[1].real = realparam;
52
53     return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
54 }
55
56 int
57 fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t *handler, fluid_rvoice_function_t method, void *object, fluid_rvoice_param_t param[MAX_EVENT_PARAMS])
58 {
59     fluid_rvoice_event_t local_event;
60
61     local_event.method = method;
62     local_event.object = object;
63     FLUID_MEMCPY(&local_event.param, param, sizeof(*param) * MAX_EVENT_PARAMS);
64
65     return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
66 }
67
68 int
69 fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t *handler,
70                                    fluid_rvoice_function_t method, void *object, void *ptr)
71 {
72     fluid_rvoice_event_t local_event;
73
74     local_event.method = method;
75     local_event.object = object;
76     local_event.param[0].ptr = ptr;
77
78     return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
79 }
80
81 static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event)
82 {
83     fluid_rvoice_event_t *event;
84     int old_queue_stored = fluid_atomic_int_add(&handler->queue_stored, 1);
85
86     event = fluid_ringbuffer_get_inptr(handler->queue, old_queue_stored);
87
88     if(event == NULL)
89     {
90         fluid_atomic_int_add(&handler->queue_stored, -1);
91         FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
92         return FLUID_FAILED; // Buffer full...
93     }
94
95     FLUID_MEMCPY(event, src_event, sizeof(*event));
96
97     return FLUID_OK;
98 }
99
100
101 void
102 fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler, fluid_rvoice_t *rvoice)
103 {
104     fluid_rvoice_t **vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
105
106     if(vptr == NULL)
107     {
108         return;    // Buffer full
109     }
110
111     *vptr = rvoice;
112     fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1);
113 }
114
115 fluid_rvoice_eventhandler_t *
116 new_fluid_rvoice_eventhandler(int queuesize,
117                               int finished_voices_size, int bufs, int fx_bufs, int fx_units, fluid_real_t sample_rate, int extra_threads, int prio)
118 {
119     fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
120
121     if(eventhandler == NULL)
122     {
123         FLUID_LOG(FLUID_ERR, "Out of memory");
124         return NULL;
125     }
126
127     eventhandler->mixer = NULL;
128     eventhandler->queue = NULL;
129     eventhandler->finished_voices = NULL;
130
131     fluid_atomic_int_set(&eventhandler->queue_stored, 0);
132
133     eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size,
134                                     sizeof(fluid_rvoice_t *));
135
136     if(eventhandler->finished_voices == NULL)
137     {
138         goto error_recovery;
139     }
140
141     eventhandler->queue = new_fluid_ringbuffer(queuesize, sizeof(fluid_rvoice_event_t));
142
143     if(eventhandler->queue == NULL)
144     {
145         goto error_recovery;
146     }
147
148     eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units, sample_rate, eventhandler, extra_threads, prio);
149
150     if(eventhandler->mixer == NULL)
151     {
152         goto error_recovery;
153     }
154
155     return eventhandler;
156
157 error_recovery:
158     delete_fluid_rvoice_eventhandler(eventhandler);
159     return NULL;
160 }
161
162 int
163 fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t *handler)
164 {
165     return fluid_ringbuffer_get_count(handler->queue);
166 }
167
168
169 /**
170  * Call fluid_rvoice_event_dispatch for all events in queue
171  * @return number of events dispatched
172  */
173 int
174 fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t *handler)
175 {
176     fluid_rvoice_event_t *event;
177     int result = 0;
178
179     while(NULL != (event = fluid_ringbuffer_get_outptr(handler->queue)))
180     {
181         fluid_rvoice_event_dispatch(event);
182         result++;
183         fluid_ringbuffer_next_outptr(handler->queue);
184     }
185
186     return result;
187 }
188
189
190 void
191 delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *handler)
192 {
193     fluid_return_if_fail(handler != NULL);
194
195     delete_fluid_rvoice_mixer(handler->mixer);
196     delete_fluid_ringbuffer(handler->queue);
197     delete_fluid_ringbuffer(handler->finished_voices);
198     FLUID_FREE(handler);
199 }