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 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.
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 * Library General Public License for more details.
14 *
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
18 * 02110-1301, USA
19 */
20
21
22 #include "fluid_rvoice_handler.h"
23
24
new_fluid_rvoice_handler(void)25 fluid_rvoice_handler_t* new_fluid_rvoice_handler(void)
26 {
27 fluid_rvoice_handler_t* handler;
28
29 handler = FLUID_NEW(fluid_rvoice_handler_t);
30 if (handler == NULL) {
31 FLUID_LOG(FLUID_ERR, "Out of memory");
32 return NULL;
33 }
34 FLUID_MEMSET(handler, 0, sizeof(fluid_rvoice_handler_t));
35
36 return handler;
37 }
38
delete_fluid_rvoice_handler(fluid_rvoice_handler_t * handler)39 void delete_fluid_rvoice_handler(fluid_rvoice_handler_t* handler)
40 {
41 if (handler == NULL)
42 return;
43
44 #if 0
45 FLUID_FREE(handler->finished_voices);
46 #endif
47 FLUID_FREE(handler->voices);
48 FLUID_FREE(handler);
49 }
50
51
52 int
fluid_rvoice_handler_add_voice(fluid_rvoice_handler_t * handler,fluid_rvoice_t * voice)53 fluid_rvoice_handler_add_voice(fluid_rvoice_handler_t* handler, fluid_rvoice_t* voice)
54 {
55 if (handler->active_voices >= handler->polyphony) {
56 FLUID_LOG(FLUID_WARN, "Trying to exceed polyphony in fluid_rvoice_handler_add_voice");
57 return FLUID_FAILED;
58 }
59 handler->voices[handler->active_voices++] = voice;
60 return FLUID_OK;
61 }
62
63 /**
64 * Update polyphony - max number of voices (NOTE: not hard real-time capable)
65 * @return FLUID_OK or FLUID_FAILED
66 */
67 int
fluid_rvoice_handler_set_polyphony(fluid_rvoice_handler_t * handler,int value)68 fluid_rvoice_handler_set_polyphony(fluid_rvoice_handler_t* handler, int value)
69 {
70 void* newptr;
71 if (handler->active_voices > value)
72 return FLUID_FAILED;
73 #if 0
74 if (handler->finished_voice_count > value)
75 return FLUID_FAILED;
76 #endif
77
78 newptr = FLUID_REALLOC(handler->voices, value * sizeof(fluid_rvoice_t*));
79 if (newptr == NULL)
80 return FLUID_FAILED;
81 handler->voices = newptr;
82 #if 0
83 newptr = FLUID_REALLOC(handler->finished_voices, value * sizeof(fluid_rvoice_t*));
84 if (newptr == NULL)
85 return FLUID_FAILED;
86 handler->finished_voices = newptr;
87 #endif
88
89 handler->polyphony = value;
90 return FLUID_OK;
91 }
92
93 static void
fluid_rvoice_handler_remove_voice(fluid_rvoice_handler_t * handler,int index)94 fluid_rvoice_handler_remove_voice(fluid_rvoice_handler_t* handler, int index)
95 {
96 #if 0
97 if (handler->finished_voice_count < handler->polyphony)
98 handler->finished_voices[handler->finished_voice_count++] = handler->voices[index];
99 #endif
100
101 if (handler->remove_voice_callback != NULL)
102 handler->remove_voice_callback(handler->remove_voice_callback_userdata,
103 handler->voices[index]);
104
105 handler->active_voices--;
106 if (index < handler->active_voices) /* Move the last voice into the "hole" */
107 handler->voices[index] = handler->voices[handler->active_voices];
108 }
109
110 /**
111 * Synthesize one voice
112 * @return Number of samples written
113 */
114 #if 0
115 static inline int
116 fluid_rvoice_handler_write_one(fluid_rvoice_handler_t* handler, int index,
117 fluid_real_t* buf, int blockcount)
118 {
119 int i, result = 0;
120 fluid_rvoice_t* voice = handler->voices[index];
121 for (i=0; i < blockcount; i++) {
122 int s = fluid_rvoice_write(voice, buf);
123 if (s == -1) {
124 FLUID_MEMSET(buf, 0, FLUID_BUFSIZE*sizeof(fluid_real_t));
125 s = FLUID_BUFSIZE;
126 }
127 buf += s;
128 result += s;
129 }
130 return result;
131 }
132 #endif
133
134 /**
135 * Synthesize one voice and add to buffer.
136 * NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
137 * voice has been finished, removed and possibly replaced with another voice.
138 * @return Number of samples written
139 */
140 static inline int
fluid_rvoice_handler_mix_one(fluid_rvoice_handler_t * handler,int index,fluid_real_t ** bufs,unsigned int blockcount,unsigned int bufcount)141 fluid_rvoice_handler_mix_one(fluid_rvoice_handler_t* handler, int index,
142 fluid_real_t** bufs, unsigned int blockcount, unsigned int bufcount)
143 {
144 unsigned int i, j=0, result = 0;
145 fluid_rvoice_t* voice = handler->voices[index];
146
147 fluid_real_t local_buf[FLUID_BUFSIZE*blockcount];
148
149 for (i=0; i < blockcount; i++) {
150 int s = fluid_rvoice_write(voice, &local_buf[FLUID_BUFSIZE*i]);
151 if (s == -1) {
152 s = FLUID_BUFSIZE; /* Voice is quiet, TODO: optimize away memset/mix */
153 FLUID_MEMSET(&local_buf[FLUID_BUFSIZE*i], 0, FLUID_BUFSIZE*sizeof(fluid_real_t*));
154 }
155 result += s;
156 if (s < FLUID_BUFSIZE) {
157 j = 1;
158 break;
159 }
160 }
161 fluid_rvoice_buffers_mix(&voice->buffers, local_buf, result, bufs, bufcount);
162
163 if (j)
164 fluid_rvoice_handler_remove_voice(handler, index);
165
166 return result;
167 }
168
169 static inline void
fluid_resetbufs(int blockcount,int bufcount,fluid_real_t ** bufs)170 fluid_resetbufs(int blockcount, int bufcount, fluid_real_t** bufs)
171 {
172 int i;
173 for (i=0; i < bufcount; i++)
174 FLUID_MEMSET(bufs[i], 0, blockcount * FLUID_BUFSIZE * sizeof(fluid_real_t));
175 }
176
177 /**
178 * Single-threaded scenario, no worker threads
179 */
180 static inline void
fluid_rvoice_handler_render_loop_simple(fluid_rvoice_handler_t * handler,int blockcount,int bufcount,fluid_real_t ** bufs)181 fluid_rvoice_handler_render_loop_simple(fluid_rvoice_handler_t* handler,
182 int blockcount, int bufcount, fluid_real_t** bufs)
183 {
184 int i;
185 int scount = blockcount * FLUID_BUFSIZE;
186 for (i=0; i < handler->active_voices; i++) {
187 int s = fluid_rvoice_handler_mix_one(handler, i, bufs, blockcount, bufcount);
188 if (s < scount) i--; /* Need to render the moved voice as well */
189 }
190 }
191
192
193 /**
194 * @param blockcount number of samples to render is blockcount*FLUID_BUFSIZE
195 * @param bufcount number of buffers to render into
196 * @param bufs array of bufcount buffers, each containing blockcount*FLUID_BUFSIZE samples
197 */
198 void
fluid_rvoice_handler_render(fluid_rvoice_handler_t * handler,int blockcount,int bufcount,fluid_real_t ** bufs)199 fluid_rvoice_handler_render(fluid_rvoice_handler_t* handler,
200 int blockcount, int bufcount, fluid_real_t** bufs)
201 {
202 fluid_resetbufs(blockcount, bufcount, bufs);
203 fluid_rvoice_handler_render_loop_simple(handler, blockcount, bufcount, bufs);
204 }
205