1 /*
2 * libInstPatch
3 * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Moderal Public License
7 * as published by the Free Software Foundation; version 2.1
8 * of the License only.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Moderal Public License for more details.
14 *
15 * You should have received a copy of the GNU Moderal Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA or on the web at http://www.gnu.org.
19 */
20 /**
21 * SECTION: IpatchSF2ModList
22 * @short_description: SoundFont modulator lists
23 * @see_also:
24 * @stability: Stable
25 *
26 * SoundFont modulators are used to define real time MIDI effect controls.
27 */
28 #include <glib.h>
29 #include <glib-object.h>
30 #include "IpatchSF2ModList.h"
31 #include "IpatchSF2Gen.h"
32 #include "ipatch_priv.h"
33
34 /* default modulators */
35 static IpatchSF2Mod default_mods[] =
36 {
37 { 0x0502, IPATCH_SF2_GEN_ATTENUATION, 960, 0x0, 0 },
38 { 0x0102, IPATCH_SF2_GEN_FILTER_CUTOFF, -2400, 0xD02, 0 },
39 { 0x000D, IPATCH_SF2_GEN_VIB_LFO_TO_PITCH, 50, 0x0, 0 },
40 { 0x0081, IPATCH_SF2_GEN_VIB_LFO_TO_PITCH, 50, 0x0, 0 },
41 { 0x0587, IPATCH_SF2_GEN_ATTENUATION, 960, 0x0, 0 },
42 { 0x028A, IPATCH_SF2_GEN_PAN, 1000, 0x0, 0 },
43 { 0x058B, IPATCH_SF2_GEN_ATTENUATION, 960, 0x0, 0 },
44 { 0x00DB, IPATCH_SF2_GEN_REVERB, 200, 0x0, 0 },
45 { 0x00DD, IPATCH_SF2_GEN_CHORUS, 200, 0x0, 0 }
46 // { 0x020E, InitialPitch WTF?, 12700, 0x0010, 0 },
47 };
48
49 static GSList *list = NULL; /* list of default modulators */
50
51 /* ----- Initialization/deinitialization of list ----------------------------*/
52 /* Initialize list */
_ipatch_sf2_mod_list_init(void)53 void _ipatch_sf2_mod_list_init(void)
54 {
55 list = NULL;
56 }
57
58 /* Free list */
_ipatch_sf2_mod_list_deinit(void)59 void _ipatch_sf2_mod_list_deinit(void)
60 {
61 g_slist_free(list);
62 }
63
64 /*------ IpatchSF2ModList object functions ---------------------------------*/
65
66 GType
ipatch_sf2_mod_list_get_type(void)67 ipatch_sf2_mod_list_get_type(void)
68 {
69 static GType type = 0;
70
71 if(!type)
72 type = g_boxed_type_register_static("IpatchSF2ModList",
73 (GBoxedCopyFunc)ipatch_sf2_mod_list_duplicate,
74 (GBoxedFreeFunc)ipatch_sf2_mod_list_boxed_free);
75
76 return (type);
77 }
78
79 /**
80 * ipatch_sf2_mod_list_duplicate: (skip)
81 * @list: (element-type Ipatch.SF2Mod) (transfer none): Modulator list to duplicate
82 *
83 * Duplicates a modulator list (list and modulator data).
84 *
85 * Returns: (element-type Ipatch.SF2Mod) (transfer full): New duplicate modulator list which
86 * should be freed with ipatch_sf2_mod_list_free() with @free_mods set to
87 * %TRUE when finished with it.
88 */
89 GSList *
ipatch_sf2_mod_list_duplicate(const GSList * list)90 ipatch_sf2_mod_list_duplicate(const GSList *list)
91 {
92 GSList *newlist = NULL;
93
94 while(list)
95 {
96 newlist = g_slist_prepend(newlist, ipatch_sf2_mod_duplicate
97 ((IpatchSF2Mod *)(list->data)));
98 list = list->next;
99 }
100
101 newlist = g_slist_reverse(newlist);
102
103 return (newlist);
104 }
105
106 /**
107 * ipatch_sf2_mod_list_override: (skip)
108 * @alist: First modulator list
109 * @blist: Second modulator list
110 * @copy: If %TRUE then modulator data is duplicated
111 *
112 * Creates a new modulator list by combining @alist and @blist. Modulators
113 * in @blist override identical modulators in @alist. If @copy is set then
114 * the modulator data is also duplicated (a new IpatchSF2ModList is created).
115 *
116 * Returns: New IpatchSF2ModList of combined modulator lists.
117 * Should be freed with ipatch_sf2_mod_list_free() with the free_mods parameter
118 * set to the value of @copy.
119 */
120 GSList *
ipatch_sf2_mod_list_override(const GSList * alist,const GSList * blist,gboolean copy)121 ipatch_sf2_mod_list_override(const GSList *alist, const GSList *blist,
122 gboolean copy)
123 {
124 GSList *newlist, *bcopy, *p;
125 IpatchSF2Mod *amod, *bmod;
126
127 if(copy)
128 {
129 newlist = ipatch_sf2_mod_list_duplicate(blist);
130 }
131 else
132 {
133 newlist = g_slist_copy((GSList *)blist);
134 }
135
136 if(!newlist) /* optimize for empty blist */
137 {
138 if(copy)
139 {
140 return (ipatch_sf2_mod_list_duplicate(alist));
141 }
142 else
143 {
144 return (g_slist_copy((GSList *)alist));
145 }
146 }
147
148 bcopy = newlist;
149
150 while(alist) /* loop over alist */
151 {
152 amod = (IpatchSF2Mod *)(alist->data);
153 p = bcopy;
154
155 while(p)
156 {
157 bmod = (IpatchSF2Mod *)(p->data);
158
159 if(IPATCH_SF2_MOD_ARE_IDENTICAL(amod, bmod))
160 {
161 break;
162 }
163
164 p = p->next;
165 }
166
167 if(!p) /* no duplicate found? */
168 newlist = g_slist_prepend(newlist, copy ? ipatch_sf2_mod_duplicate
169 (amod) : amod);
170
171 alist = alist->next;
172 }
173
174 return (newlist);
175 }
176
177 /**
178 * ipatch_sf2_mod_list_override_copy: (rename-to ipatch_sf2_mod_list_override)
179 * @alist: (element-type Ipatch.SF2Mod) (transfer none) (nullable): First modulator list
180 * @blist: (element-type Ipatch.SF2Mod) (transfer none) (nullable): Second modulator list
181 *
182 * Creates a new modulator list by combining @alist and @blist. Modulators
183 * in @blist override identical modulators in @alist.
184 *
185 * Returns: (element-type Ipatch.SF2Mod) (transfer full) (nullable): New IpatchSF2ModList of
186 * combined modulator lists. Should be freed with ipatch_sf2_mod_list_free() with
187 * the free_mods parameter set to %TRUE.
188 *
189 * Since: 1.1.0
190 */
191 GSList *
ipatch_sf2_mod_list_override_copy(const GSList * alist,const GSList * blist)192 ipatch_sf2_mod_list_override_copy(const GSList *alist, const GSList *blist)
193 {
194 return (ipatch_sf2_mod_list_override(alist, blist, TRUE));
195 }
196
197 /**
198 * ipatch_sf2_mod_list_offset:
199 * @alist: (element-type Ipatch.SF2Mod) (transfer none) (nullable): First modulator list
200 * @blist: (element-type Ipatch.SF2Mod) (transfer none) (nullable): Second modulator list
201 *
202 * Creates a new modulator list by combining @list and @blist. Modulators
203 * in @blist offset (amounts are added) identical modulators in @alist.
204 * Operation is non-destructive as a new list is created and modulator data
205 * is duplicated.
206 *
207 * NOTE: Optimized for empty @blist.
208 *
209 * Returns: (element-type Ipatch.SF2Mod) (transfer full) (nullable): New IpatchSF2ModList
210 * of combined modulator lists. Should be freed with ipatch_sf2_mod_list_free()
211 * with @free_mods set to %TRUE when finished with it.
212 */
213 GSList *
ipatch_sf2_mod_list_offset(const GSList * alist,const GSList * blist)214 ipatch_sf2_mod_list_offset(const GSList *alist, const GSList *blist)
215 {
216 GSList *newlist, *acopy, *p;
217 IpatchSF2Mod *amod, *bmod;
218 int add;
219
220 newlist = ipatch_sf2_mod_list_duplicate(alist);
221
222 if(!blist)
223 {
224 return (newlist); /* optimize for empty blist */
225 }
226
227 acopy = newlist;
228
229 while(blist) /* loop over alist */
230 {
231 bmod = (IpatchSF2Mod *)(blist->data);
232 p = acopy;
233
234 while(p)
235 {
236 amod = (IpatchSF2Mod *)(p->data);
237
238 if(IPATCH_SF2_MOD_ARE_IDENTICAL(amod, bmod))
239 {
240 /* offset (add) the modulator amount */
241 add = amod->amount + bmod->amount;
242 add = CLAMP(add, -32768, 32767);
243 amod->amount = add;
244 break;
245 }
246
247 p = p->next;
248 }
249
250 /* no duplicate found? */
251 if(!p)
252 newlist = g_slist_prepend(newlist,
253 ipatch_sf2_mod_duplicate(bmod));
254
255 blist = blist->next;
256 }
257
258 return (newlist);
259 }
260
261 /**
262 * ipatch_sf2_mod_list_free: (skip)
263 * @list: Modulator list to free
264 * @free_mods: If %TRUE then the modulators themselves are freed, %FALSE
265 * makes this function act just like g_slist_free() (only the list is
266 * freed not the modulators).
267 *
268 * Free a list of modulators
269 */
270 void
ipatch_sf2_mod_list_free(GSList * list,gboolean free_mods)271 ipatch_sf2_mod_list_free(GSList *list, gboolean free_mods)
272 {
273 GSList *p;
274
275 if(free_mods)
276 {
277 p = list;
278
279 while(p)
280 {
281 ipatch_sf2_mod_free((IpatchSF2Mod *)(p->data));
282 p = g_slist_delete_link(p, p);
283 }
284 }
285 else
286 {
287 g_slist_free(list);
288 }
289 }
290
291 /**
292 * ipatch_sf2_mod_list_boxed_free: (skip)
293 * @list: Modulator list to free
294 *
295 * Like ipatch_sf2_mod_list_free() but used for boxed type declaration and so
296 * therefore frees all modulators in the list.
297 */
298 void
ipatch_sf2_mod_list_boxed_free(GSList * list)299 ipatch_sf2_mod_list_boxed_free(GSList *list)
300 {
301 ipatch_sf2_mod_list_free(list, TRUE);
302 }
303
304 /**
305 * ipatch_sf2_mod_list_insert: (skip)
306 * @mods: (element-type Ipatch.SF2Mod) (transfer none): Modulator list to insert into
307 * @modvals: (transfer none): Modulator values to insert (a new modulator is created
308 * and the values are copied to it)
309 * @pos: Index position in zone's modulator list to insert (0 = first, < 0 = last)
310 *
311 * Inserts a modulator into a modulator list. Does not check for
312 * duplicates! The modulator is not used directly, a new one is created and
313 * the values in @mod are copied to it.
314 *
315 * Returns: New start (root) of @mods list.
316 */
317 GSList *
ipatch_sf2_mod_list_insert(GSList * mods,const IpatchSF2Mod * modvals,int pos)318 ipatch_sf2_mod_list_insert(GSList *mods, const IpatchSF2Mod *modvals, int pos)
319 {
320 IpatchSF2Mod *newmod;
321
322 g_return_val_if_fail(modvals != NULL, mods);
323
324 newmod = ipatch_sf2_mod_duplicate(modvals);
325 return (g_slist_insert(mods, newmod, pos));
326 }
327
328 /**
329 * ipatch_sf2_mod_list_remove: (skip)
330 * @mods: (transfer full): Modulator list to remove from
331 * @modvals: Values of modulator to remove
332 * @changed: (out) (optional): Pointer to store bool of whether the list was changed
333 * (%NULL to ignore)
334 *
335 * Remove a modulator from a modulator list. The modulator values in @modvals
336 * are used to search the modulator list. The first modulator
337 * that matches all fields in @modvals is removed.
338 *
339 * Returns: New start (root) of @mods list.
340 */
341 GSList *
ipatch_sf2_mod_list_remove(GSList * mods,const IpatchSF2Mod * modvals,gboolean * changed)342 ipatch_sf2_mod_list_remove(GSList *mods, const IpatchSF2Mod *modvals,
343 gboolean *changed)
344 {
345 IpatchSF2Mod *mod;
346 GSList *p;
347
348 if(changed)
349 {
350 *changed = FALSE;
351 }
352
353 g_return_val_if_fail(modvals != NULL, mods);
354
355 for(p = mods; p; p = g_slist_next(p))
356 {
357 mod = (IpatchSF2Mod *)(p->data);
358
359 if(IPATCH_SF2_MOD_ARE_IDENTICAL_AMOUNT(mod, modvals))
360 {
361 ipatch_sf2_mod_free(mod);
362
363 if(changed)
364 {
365 *changed = TRUE;
366 }
367
368 return (g_slist_delete_link(mods, p));
369 }
370 }
371
372 return (mods);
373 }
374
375 /**
376 * ipatch_sf2_mod_list_change: (skip)
377 * @mods: Modulator list to change a modulator in
378 * @oldvals: Current values of modulator to set
379 * @newvals: New modulator values
380 *
381 * Sets the values of an existing modulator in a modulator list. The list
382 * is searched for a modulator that matches the values in @oldvals. If a
383 * modulator is found its values are set to those in @newvals. If it is not
384 * found, nothing is done.
385 *
386 * Returns: %TRUE if changed, %FALSE otherwise (no match)
387 */
388 gboolean
ipatch_sf2_mod_list_change(GSList * mods,const IpatchSF2Mod * oldvals,const IpatchSF2Mod * newvals)389 ipatch_sf2_mod_list_change(GSList *mods, const IpatchSF2Mod *oldvals,
390 const IpatchSF2Mod *newvals)
391 {
392 IpatchSF2Mod *mod;
393 GSList *p;
394
395 g_return_val_if_fail(oldvals != NULL, FALSE);
396 g_return_val_if_fail(newvals != NULL, FALSE);
397
398 for(p = mods; p; p = p->next)
399 {
400 mod = (IpatchSF2Mod *)(p->data);
401
402 if(IPATCH_SF2_MOD_ARE_IDENTICAL_AMOUNT(mod, oldvals))
403 {
404 *mod = *newvals; /* replace values in modulator */
405 return (TRUE);
406 }
407 }
408
409 return (FALSE);
410 }
411
412 /**
413 * ipatch_sf2_mod_list_get_default:
414 *
415 * Get the list of default instrument modulators.
416 *
417 * Returns: (element-type Ipatch.SF2Mod) (transfer none): The list of default
418 * modulators. The same modulator list is returned on subsequent calls and
419 * should not be modified or freed.
420 */
421 G_CONST_RETURN GSList *
ipatch_sf2_mod_list_get_default(void)422 ipatch_sf2_mod_list_get_default(void)
423 {
424 int i;
425
426 if(!list)
427 for(i = sizeof(default_mods) / sizeof(IpatchSF2Mod) - 1; i >= 0 ; i--)
428 {
429 list = g_slist_prepend(list, &default_mods[i]);
430 }
431
432 return (list);
433 }
434