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 Lesser General 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 Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General 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 #include <stdio.h>
21 #include <string.h>
22 #include <glib.h>
23 #include <glib-object.h>
24 
25 #include "IpatchSF2VoiceCache_SF2.h"
26 #include "IpatchConverter.h"
27 #include "IpatchConverterSF2VoiceCache.h"
28 #include "IpatchConverter_priv.h"
29 
30 #include "IpatchSF2Inst.h"
31 #include "IpatchSF2IZone.h"
32 #include "IpatchSF2Preset.h"
33 #include "IpatchSF2PZone.h"
34 #include "IpatchSF2Sample.h"
35 #include "IpatchSF2VoiceCache.h"
36 #include "IpatchSF2Zone.h"
37 #include "IpatchSF2GenItem.h"
38 
39 /**
40  * _ipatch_sf2_voice_cache_init_SF2: (skip)
41  */
42 void
_ipatch_sf2_voice_cache_init_SF2(void)43 _ipatch_sf2_voice_cache_init_SF2(void)
44 {
45     g_type_class_ref(IPATCH_TYPE_CONVERTER_SF2_PRESET_TO_SF2_VOICE_CACHE);
46     g_type_class_ref(IPATCH_TYPE_CONVERTER_SF2_PZONE_TO_SF2_VOICE_CACHE);
47     g_type_class_ref(IPATCH_TYPE_CONVERTER_SF2_INST_TO_SF2_VOICE_CACHE);
48     g_type_class_ref(IPATCH_TYPE_CONVERTER_SF2_IZONE_TO_SF2_VOICE_CACHE);
49     g_type_class_ref(IPATCH_TYPE_CONVERTER_SF2_SAMPLE_TO_SF2_VOICE_CACHE);
50 
51     ipatch_register_converter_map
52     (IPATCH_TYPE_CONVERTER_SF2_PRESET_TO_SF2_VOICE_CACHE, 0, 0,
53      IPATCH_TYPE_SF2_PRESET, 0, 1, IPATCH_TYPE_SF2_VOICE_CACHE, 0, 1);
54     ipatch_register_converter_map
55     (IPATCH_TYPE_CONVERTER_SF2_PZONE_TO_SF2_VOICE_CACHE, 0, 0,
56      IPATCH_TYPE_SF2_PZONE, 0, 1, IPATCH_TYPE_SF2_VOICE_CACHE, 0, 1);
57     ipatch_register_converter_map
58     (IPATCH_TYPE_CONVERTER_SF2_INST_TO_SF2_VOICE_CACHE, 0, 0,
59      IPATCH_TYPE_SF2_INST, 0, 1, IPATCH_TYPE_SF2_VOICE_CACHE, 0, 1);
60     ipatch_register_converter_map
61     (IPATCH_TYPE_CONVERTER_SF2_IZONE_TO_SF2_VOICE_CACHE, 0, 0,
62      IPATCH_TYPE_SF2_IZONE, 0, 1, IPATCH_TYPE_SF2_VOICE_CACHE, 0, 1);
63     ipatch_register_converter_map
64     (IPATCH_TYPE_CONVERTER_SF2_SAMPLE_TO_SF2_VOICE_CACHE, 0, 0,
65      IPATCH_TYPE_SF2_SAMPLE, 0, 1, IPATCH_TYPE_SF2_VOICE_CACHE, 0, 1);
66 }
67 
68 static gboolean
_sf2_preset_to_sf2_voice_cache_convert(IpatchConverter * converter,GError ** err)69 _sf2_preset_to_sf2_voice_cache_convert(IpatchConverter *converter,
70                                        GError **err)
71 {
72     IpatchSF2Preset *preset;
73     IpatchSF2Inst *inst;
74     IpatchSF2VoiceCache *cache;
75     IpatchSF2Voice *voice;
76     IpatchSF2GenArray *gpz;
77     IpatchSF2GenArray pz;
78     IpatchSF2GenArray *giz;
79     IpatchSF2Zone *pzone, *izone;
80     IpatchSF2Sample *sample;
81     IpatchSF2GenAmount *amt;
82     IpatchItem *solo_item;
83     GObject *obj;
84     GSList *gpmods = NULL, *pmods; /* global and preset modulator lists */
85     GSList *gimods;	/* global and instrument modulator lists */
86     GSList *imods;	/* local instrument modulators */
87     const GSList *defmods;	/* default modulator list */
88     GSList *tmpmods;
89     GSList *p, *p2;
90 
91     obj = IPATCH_CONVERTER_INPUT(converter);
92     cache = IPATCH_SF2_VOICE_CACHE(IPATCH_CONVERTER_OUTPUT(converter));
93     solo_item = ((IpatchConverterSF2VoiceCache *)converter)->solo_item;
94 
95     /* check if its a preset zone or a preset */
96     if(IPATCH_IS_SF2_PZONE(obj))	/* ++ ref parent preset */
97     {
98         preset = IPATCH_SF2_PRESET(ipatch_item_get_parent(IPATCH_ITEM(obj)));
99     }
100     else
101     {
102         preset = IPATCH_SF2_PRESET(obj);
103     }
104 
105     /* declare the preset as a dependent item */
106     ipatch_sf2_voice_cache_declare_item(cache, (GObject *)preset);
107 
108     defmods = cache->default_mods;	/* get default mod list */
109 
110     IPATCH_ITEM_RLOCK(preset);	/* ++ LOCK preset */
111 
112     /* global generators and modulators (can access as long as preset is locked) */
113     gpz = &preset->genarray;
114     gpmods = preset->mods;
115 
116     for(p = preset->zones; p; p = p->next)	/* loop over preset zones */
117     {
118         pzone = (IpatchSF2Zone *)(p->data);
119 
120         /* If a zone is currently solo, skip other zones */
121         if(solo_item && (IpatchItem *)pzone != solo_item)
122         {
123             continue;
124         }
125 
126         ipatch_sf2_voice_cache_declare_item(cache, (GObject *)pzone);
127 
128         /* copy def/global gen values */
129         memcpy(&pz, gpz, sizeof(IpatchSF2GenArray));
130 
131         IPATCH_ITEM_RLOCK(pzone);  /* ++ LOCK preset zone */
132 
133         inst = (IpatchSF2Inst *)(pzone->item);
134 
135         if(!inst)	/* skip any zones without instrument ref */
136         {
137             IPATCH_ITEM_RUNLOCK(pzone);
138             continue;
139         }
140 
141         ipatch_sf2_gen_item_copy_set((IpatchSF2GenItem *)pzone, &pz);  /* process pzone */
142 
143         if(pzone->mods)
144         {
145             pmods = ipatch_sf2_mod_list_override(gpmods, pzone->mods, FALSE);
146         }
147         else
148         {
149             pmods = gpmods;
150         }
151 
152         IPATCH_ITEM_RLOCK(inst);  /* ++ LOCK inst */
153 
154         /* process global generators and modulators */
155         giz = &inst->genarray;
156 
157         if(inst->mods)	/* can use modulators while inst is locked (no copy) */
158         {
159             gimods = ipatch_sf2_mod_list_override(defmods, inst->mods, FALSE);    /* ++ alloc new mod list */
160         }
161         else
162         {
163             gimods = (GSList *)defmods;
164         }
165 
166         p2 = inst->zones;
167 
168         for(; p2; p2 = p2->next)		/* loop over instrument zones */
169         {
170             izone = (IpatchSF2Zone *)(p2->data);
171             ipatch_sf2_voice_cache_declare_item(cache, (GObject *)izone);
172 
173             IPATCH_ITEM_RLOCK(izone);  /* ++ LOCK izone */
174 
175             sample = (IpatchSF2Sample *)(izone->item);
176 
177             /* skip zones without sample or which don't note/velocity intersect */
178             if(!sample || !ipatch_sf2_gen_item_intersect_test((IpatchSF2GenItem *)izone, &pz))
179             {
180                 IPATCH_ITEM_RUNLOCK(izone);
181                 continue;
182             }
183 
184             voice = ipatch_sf2_voice_cache_add_voice(cache);
185 
186             /* copy global inst gen values */
187             memcpy(&voice->gen_array, giz, sizeof(IpatchSF2GenArray));
188 
189             /* zone overrides */
190             ipatch_sf2_gen_item_copy_set((IpatchSF2GenItem *)izone,
191                                          &voice->gen_array);
192 
193             if(izone->mods)   /* ++ override global/def mods with zone (no copy) */
194             {
195                 imods = ipatch_sf2_mod_list_override(gimods, izone->mods, FALSE);
196             }
197             else
198             {
199                 imods = gimods;
200             }
201 
202             /* igens += pgens */
203             ipatch_sf2_gen_array_offset(&voice->gen_array, &pz);
204 
205             /* ++ new modulator list of imods + pmods */
206             voice->mod_list = ipatch_sf2_mod_list_offset(imods, pmods);
207 
208             if(cache->override_mods)
209             {
210                 tmpmods = voice->mod_list;
211                 voice->mod_list = ipatch_sf2_mod_list_override(tmpmods, cache->override_mods, TRUE);
212 
213                 if(tmpmods)
214                 {
215                     ipatch_sf2_mod_list_free(tmpmods, TRUE);
216                 }
217             }
218 
219             /* set MIDI note and velocity ranges */
220             amt = &voice->gen_array.values[IPATCH_SF2_GEN_NOTE_RANGE];
221             ipatch_sf2_voice_cache_set_voice_range(cache, voice, 0,
222                                                    amt->range.low, amt->range.high);
223 
224             amt = &voice->gen_array.values[IPATCH_SF2_GEN_VELOCITY_RANGE];
225             ipatch_sf2_voice_cache_set_voice_range(cache, voice, 1,
226                                                    amt->range.low, amt->range.high);
227 
228             /* copy sample parameters */
229             ipatch_sf2_voice_cache_declare_item(cache, (GObject *)sample);
230 
231             ipatch_sf2_voice_set_sample_data(voice, sample->sample_data);
232 
233             voice->loop_start = sample->loop_start;
234             voice->loop_end = sample->loop_end;
235             voice->rate = sample->rate;
236             voice->root_note = sample->root_note;
237             voice->fine_tune = sample->fine_tune;
238 
239             IPATCH_ITEM_RUNLOCK(izone);  /* -- UNLOCK izone */
240 
241             /* free imods if not == gimods (only list, since mod data not copied) */
242             if(imods != gimods)
243             {
244                 ipatch_sf2_mod_list_free(imods, FALSE);
245             }
246         }
247 
248         IPATCH_ITEM_RUNLOCK(inst);	/* -- UNLOCK inst */
249         IPATCH_ITEM_RUNLOCK(pzone);	/* -- UNLOCK preset zone */
250 
251         /* free gimods if not defmods (mod data was not copied) */
252         if(gimods != defmods)
253         {
254             ipatch_sf2_mod_list_free(gimods, FALSE);
255         }
256 
257         /* free pmods list if not gpmods (mod data was not copied) */
258         if(pmods != gpmods)
259         {
260             ipatch_sf2_mod_list_free(pmods, FALSE);
261         }
262     }
263 
264     IPATCH_ITEM_RUNLOCK(preset);  /* -- UNLOCK preset */
265 
266     /* if convert object was preset zone, unref parent preset */
267     if((void *)obj != (void *)preset)
268     {
269         g_object_unref(preset);    /* -- unref parent preset */
270     }
271 
272     return (TRUE);
273 }
274 
275 /* use preset to voice cache converter function */
276 #define _sf2_pzone_to_sf2_voice_cache_convert \
277   _sf2_preset_to_sf2_voice_cache_convert
278 
279 static gboolean
_sf2_inst_to_sf2_voice_cache_convert(IpatchConverter * converter,GError ** err)280 _sf2_inst_to_sf2_voice_cache_convert(IpatchConverter *converter, GError **err)
281 {
282     IpatchSF2Inst *inst;
283     IpatchSF2VoiceCache *cache;
284     IpatchSF2Voice *voice;
285     IpatchSF2GenArray *giz;
286     IpatchSF2Zone *izone;
287     IpatchSF2Sample *sample;
288     IpatchSF2GenAmount *amt;
289     GObject *obj;
290     GSList *gimods = NULL;
291     const GSList *defmods;
292     GSList *tmpmods;
293     IpatchItem *solo_item;
294     GSList *p;
295 
296     obj = IPATCH_CONVERTER_INPUT(converter);
297     cache = IPATCH_SF2_VOICE_CACHE(IPATCH_CONVERTER_OUTPUT(converter));
298     solo_item = ((IpatchConverterSF2VoiceCache *)converter)->solo_item;
299 
300     /* check if its a instrument zone or a instrument */
301     if(IPATCH_IS_SF2_IZONE(obj))	/* ++ ref parent instrument */
302     {
303         inst = IPATCH_SF2_INST(ipatch_item_get_parent(IPATCH_ITEM(obj)));
304     }
305     else
306     {
307         inst = IPATCH_SF2_INST(obj);
308     }
309 
310     /* declare the instrument as a dependent item */
311     ipatch_sf2_voice_cache_declare_item(cache, (GObject *)inst);
312 
313     defmods = cache->default_mods;
314 
315     IPATCH_ITEM_RLOCK(inst);	/* ++ LOCK instrument */
316 
317     /* global generators and modulators (can access as long as inst is locked) */
318     giz = &inst->genarray;
319 
320     if(inst->mods)	/* don't need to copy mods, under LOCK */
321     {
322         gimods = ipatch_sf2_mod_list_override(defmods, inst->mods, FALSE);
323     }
324     else
325     {
326         gimods = (GSList *)defmods;
327     }
328 
329     p = inst->zones;
330 
331     for(; p; p = p->next)
332     {
333         izone = (IpatchSF2Zone *)(p->data);
334 
335         /* If a zone is currently solo, skip other zones */
336         if(solo_item && (IpatchItem *)izone != solo_item)
337         {
338             continue;
339         }
340 
341         ipatch_sf2_voice_cache_declare_item(cache, (GObject *)izone);
342 
343         IPATCH_ITEM_RLOCK(izone);  /* ++ LOCK izone */
344 
345         sample = (IpatchSF2Sample *)(izone->item);
346 
347         if(!sample)		/* skip zones without sample ref */
348         {
349             IPATCH_ITEM_RUNLOCK(izone);	/* -- unlock izone */
350             continue;
351         }
352 
353         voice = ipatch_sf2_voice_cache_add_voice(cache);
354 
355         /* copy global gen values */
356         memcpy(&voice->gen_array, giz, sizeof(IpatchSF2GenArray));
357 
358         /* zone overrides global */
359         ipatch_sf2_gen_item_copy_set((IpatchSF2GenItem *)izone, &voice->gen_array);
360 
361 
362         if(cache->override_mods)
363         {
364             /* Override global/default mods with zone (no copy) and then with cache override mods (copy) */
365             tmpmods = ipatch_sf2_mod_list_override(gimods, izone->mods, FALSE);
366             voice->mod_list = ipatch_sf2_mod_list_override(tmpmods, cache->override_mods, TRUE);
367             ipatch_sf2_mod_list_free(tmpmods, FALSE);
368         } /* override global/default mods with zone (copy) */
369         else
370         {
371             voice->mod_list = ipatch_sf2_mod_list_override(gimods, izone->mods, TRUE);
372         }
373 
374         /* set MIDI note and velocity ranges */
375         amt = &voice->gen_array.values[IPATCH_SF2_GEN_NOTE_RANGE];
376         ipatch_sf2_voice_cache_set_voice_range(cache, voice, 0,
377                                                amt->range.low, amt->range.high);
378         amt = &voice->gen_array.values[IPATCH_SF2_GEN_VELOCITY_RANGE];
379         ipatch_sf2_voice_cache_set_voice_range(cache, voice, 1,
380                                                amt->range.low, amt->range.high);
381 
382         ipatch_sf2_voice_cache_declare_item(cache, (GObject *)sample);
383         ipatch_sf2_voice_set_sample_data(voice, sample->sample_data);
384 
385         voice->loop_start = sample->loop_start;
386         voice->loop_end = sample->loop_end;
387         voice->rate = sample->rate;
388         voice->root_note = sample->root_note;
389         voice->fine_tune = sample->fine_tune;
390 
391         IPATCH_ITEM_RUNLOCK(izone);  /* -- UNLOCK izone */
392     }
393 
394     IPATCH_ITEM_RUNLOCK(inst);  /* -- UNLOCK instrument */
395 
396     /* free gimods (mod data was not copied) */
397     if(gimods != defmods)
398     {
399         ipatch_sf2_mod_list_free(gimods, FALSE);
400     }
401 
402     /* if convert object was instrument zone, unref parent instrument */
403     if((void *)obj != (void *)inst)
404     {
405         g_object_unref(inst);    /* -- unref parent instrument */
406     }
407 
408     return (TRUE);
409 }
410 
411 /* use instrument to voice cache converter function */
412 #define _sf2_izone_to_sf2_voice_cache_convert \
413   _sf2_inst_to_sf2_voice_cache_convert
414 
415 static gboolean
_sf2_sample_to_sf2_voice_cache_convert(IpatchConverter * converter,GError ** err)416 _sf2_sample_to_sf2_voice_cache_convert(IpatchConverter *converter,
417                                        GError **err)
418 {
419     IpatchSF2Sample *sample;
420     IpatchSF2VoiceCache *cache;
421     IpatchSF2Voice *voice;
422     IpatchSF2GenAmount *amt;
423 
424     sample = IPATCH_SF2_SAMPLE(IPATCH_CONVERTER_INPUT(converter));
425     cache = IPATCH_SF2_VOICE_CACHE(IPATCH_CONVERTER_OUTPUT(converter));
426 
427     ipatch_sf2_voice_cache_declare_item(cache, (GObject *)sample);
428 
429     voice = ipatch_sf2_voice_cache_add_voice(cache);
430 
431     voice->mod_list = ipatch_sf2_mod_list_override(cache->default_mods,
432                       cache->override_mods, TRUE);
433 
434     /* set MIDI note and velocity ranges */
435     amt = &voice->gen_array.values[IPATCH_SF2_GEN_NOTE_RANGE];
436     ipatch_sf2_voice_cache_set_voice_range(cache, voice, 0,
437                                            amt->range.low, amt->range.high);
438     amt = &voice->gen_array.values[IPATCH_SF2_GEN_VELOCITY_RANGE];
439     ipatch_sf2_voice_cache_set_voice_range(cache, voice, 1,
440                                            amt->range.low, amt->range.high);
441 
442     /* use the default loop type for the IpatchSF2VoiceCache */
443     voice->gen_array.values[IPATCH_SF2_GEN_SAMPLE_MODES].sword
444         = cache->default_loop_type;
445     IPATCH_SF2_GEN_ARRAY_SET_FLAG(&voice->gen_array, IPATCH_SF2_GEN_SAMPLE_MODES);
446 
447     ipatch_sf2_voice_set_sample_data(voice, sample->sample_data);
448 
449     voice->loop_start = sample->loop_start;
450     voice->loop_end = sample->loop_end;
451     voice->rate = sample->rate;
452     voice->root_note = sample->root_note;
453     voice->fine_tune = sample->fine_tune;
454 
455     return (TRUE);
456 }
457 
458 CONVERTER_CLASS_INIT(sf2_preset_to_sf2_voice_cache)
459 CONVERTER_CLASS_INIT(sf2_pzone_to_sf2_voice_cache)
460 CONVERTER_CLASS_INIT(sf2_inst_to_sf2_voice_cache)
461 CONVERTER_CLASS_INIT(sf2_izone_to_sf2_voice_cache)
462 CONVERTER_CLASS_INIT(sf2_sample_to_sf2_voice_cache)
463 
464 CONVERTER_SF2_VOICE_CACHE_GET_TYPE(sf2_preset_to_sf2_voice_cache, SF2PresetToSF2VoiceCache)
465 CONVERTER_SF2_VOICE_CACHE_GET_TYPE(sf2_pzone_to_sf2_voice_cache, SF2PZoneToSF2VoiceCache)
466 CONVERTER_SF2_VOICE_CACHE_GET_TYPE(sf2_inst_to_sf2_voice_cache, SF2InstToSF2VoiceCache)
467 CONVERTER_SF2_VOICE_CACHE_GET_TYPE(sf2_izone_to_sf2_voice_cache, SF2IZoneToSF2VoiceCache)
468 CONVERTER_SF2_VOICE_CACHE_GET_TYPE(sf2_sample_to_sf2_voice_cache, SF2SampleToSF2VoiceCache)
469