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 /**
21  * SECTION: IpatchSF2VoiceCache_Gig
22  * @short_description: Voice cache converters for GigaSampler object types
23  * @see_also: #IpatchSF2VoiceCache
24  * @stability: Stable
25  */
26 #include <stdio.h>
27 #include <glib.h>
28 #include <glib-object.h>
29 
30 #include "IpatchSF2VoiceCache_Gig.h"
31 #include "IpatchSF2VoiceCache.h"
32 #include "IpatchConverter_priv.h"
33 #include "IpatchConverterSF2VoiceCache.h"
34 
35 #include "IpatchDLS2Inst.h"
36 #include "IpatchDLS2Region.h"
37 #include "IpatchDLS2Sample.h"
38 #include "IpatchSF2Mod.h"
39 #include "IpatchGig.h"
40 #include "IpatchGigInst.h"
41 #include "IpatchGigRegion.h"
42 #include "IpatchGigEffects.h"
43 #include "IpatchSample.h"
44 
45 // In IpatchSF2VoiceCache_DLS.c
46 gboolean _dls2_sample_to_sf2_voice_cache_convert(IpatchConverter *converter,
47         GError **err);
48 
49 /**
50  * _ipatch_sf2_voice_cache_init_gig: (skip)
51  */
52 void
_ipatch_sf2_voice_cache_init_gig(void)53 _ipatch_sf2_voice_cache_init_gig(void)
54 {
55     g_type_class_ref(IPATCH_TYPE_CONVERTER_GIG_INST_TO_SF2_VOICE_CACHE);
56     g_type_class_ref(IPATCH_TYPE_CONVERTER_GIG_SAMPLE_TO_SF2_VOICE_CACHE);
57 
58     ipatch_register_converter_map
59     (IPATCH_TYPE_CONVERTER_GIG_INST_TO_SF2_VOICE_CACHE, 0, 0,
60      IPATCH_TYPE_GIG_INST, 0, 1, IPATCH_TYPE_SF2_VOICE_CACHE, 0, 1);
61     ipatch_register_converter_map
62     (IPATCH_TYPE_CONVERTER_GIG_SAMPLE_TO_SF2_VOICE_CACHE, 0, 0,
63      IPATCH_TYPE_GIG_SAMPLE, 0, 1, IPATCH_TYPE_SF2_VOICE_CACHE, 0, 1);
64 }
65 
66 static gboolean
_gig_inst_to_sf2_voice_cache_convert(IpatchConverter * converter,GError ** err)67 _gig_inst_to_sf2_voice_cache_convert(IpatchConverter *converter, GError **err)
68 {
69     IpatchSF2VoiceCache *cache;
70     IpatchSF2Voice *voice;
71     IpatchDLS2Inst *inst;
72     IpatchGigRegion *region;
73     IpatchDLS2Region *dls_region;
74     IpatchGigDimension *dimension;
75     IpatchGigSubRegion *sub_region;
76     IpatchDLS2Sample *sample;
77     IpatchDLS2SampleInfo *sample_info;
78     IpatchSF2VoiceSelInfo sel_info[IPATCH_SF2_VOICE_CACHE_MAX_SEL_VALUES];
79     IpatchSF2VoiceSelInfo *infop;
80     GHashTable *sel_index_hash;	/* dimension type -> selection index */
81     int sel_count = 1;	/* 1 for note selection criteria */
82     int dim_type;
83     int index, sub_count;
84     int i, i2, v;
85     GSList *p;
86 
87     sel_index_hash = g_hash_table_new(NULL, NULL);
88 
89     cache = IPATCH_SF2_VOICE_CACHE(IPATCH_CONVERTER_OUTPUT(converter));
90 
91     inst = IPATCH_DLS2_INST(IPATCH_CONVERTER_INPUT(converter));
92     ipatch_sf2_voice_cache_declare_item(cache, (GObject *)inst);
93 
94     sel_info[0].type = IPATCH_SF2_VOICE_SEL_NOTE; /* always have note selection */
95     infop = &sel_info[1];
96 
97     IPATCH_ITEM_RLOCK(inst);	/* ++ LOCK instrument */
98 
99     /* determine all selection criteria types */
100     p = inst->regions;
101 
102     for(; p; p = p->next)	/* loop over DLS regions */
103     {
104         region = (IpatchGigRegion *)(p->data);
105         ipatch_sf2_voice_cache_declare_item(cache, (GObject *)region);
106 
107         /* NOTE: Dimensions and sub regions share the same mutex as region */
108         IPATCH_ITEM_RLOCK(region);  /* ++ LOCK region */
109 
110         for(i = 0; i < region->dimension_count; i++)   /* loop on dimensions */
111         {
112             ipatch_sf2_voice_cache_declare_item(cache,
113                                                 (GObject *)(region->dimensions[i]));
114             dim_type = region->dimensions[i]->type;
115 
116             /* channel region types don't entail selection criteria, but rather
117                channel audio routing */
118             if(dim_type == IPATCH_GIG_DIMENSION_CHANNEL)
119             {
120                 continue;
121             }
122 
123             /* already added this region selection type? */
124             if(g_hash_table_lookup(sel_index_hash, GINT_TO_POINTER(dim_type)))
125             {
126                 continue;
127             }
128 
129             infop->type = -1;
130 
131             switch(dim_type)
132             {
133             case IPATCH_GIG_DIMENSION_VELOCITY:
134                 infop->type = IPATCH_SF2_VOICE_SEL_VELOCITY;
135                 break;
136 
137             case IPATCH_GIG_DIMENSION_AFTER_TOUCH:
138                 infop->type = IPATCH_SF2_VOICE_SEL_AFTER_TOUCH;
139                 break;
140 
141             case IPATCH_GIG_DIMENSION_RELEASE_TRIG:
142                 break;
143 
144             case IPATCH_GIG_DIMENSION_KEYBOARD:
145                 break;
146 
147             case IPATCH_GIG_DIMENSION_ROUND_ROBIN:
148                 break;
149 
150             case IPATCH_GIG_DIMENSION_RANDOM:
151                 break;
152 
153             default:
154                 if(dim_type < 0x80)
155                 {
156                     infop->type = IPATCH_SF2_VOICE_SEL_MIDI_CC;
157                     infop->param1 = dim_type;	/* type is MIDI CC # */
158                 }
159 
160                 break;
161             }
162 
163             /* advance if selection criteria stored */
164             if(infop->type != -1)
165             {
166                 /* add to dim_type -> index hash + 1 (sel_count already + 1) */
167                 g_hash_table_insert(sel_index_hash, GINT_TO_POINTER(dim_type),
168                                     GINT_TO_POINTER(sel_count));
169                 infop++;
170                 sel_count++;
171             }
172             else
173             {
174                 g_warning("Unhandled Gig region type %d", dim_type);
175             }
176 
177             /* max number of selection types reached? */
178             if(infop == &sel_info[IPATCH_SF2_VOICE_CACHE_MAX_SEL_VALUES])
179             {
180                 g_warning("Max voice selection types reached!");
181                 break;
182             }
183         }  /* dimension loop */
184 
185         IPATCH_ITEM_RUNLOCK(region);  /* -- UNLOCK region */
186     }  /* region loop */
187 
188     p = inst->regions;
189 
190     for(; p; p = p->next)	/* loop over DLS regions */
191     {
192         region = (IpatchGigRegion *)(p->data);
193         dls_region = (IpatchDLS2Region *)region;
194 
195         IPATCH_ITEM_RLOCK(region);  /* ++ LOCK region */
196 
197         /* loop over all sub regions */
198         for(i = 0; i < region->sub_region_count; i++)
199         {
200             sub_region = region->sub_regions[i];
201             ipatch_sf2_voice_cache_declare_item(cache, (GObject *)sub_region);
202 
203             voice = ipatch_sf2_voice_cache_add_voice(cache);
204 
205             /* convert GigaSampler effects to SoundFont 2 generator array */
206             ipatch_gig_effects_to_gen_array(&sub_region->effects,
207                                             &voice->gen_array);
208             /* set note range */
209             ipatch_sf2_voice_cache_set_voice_range(cache, voice, 0,
210                                                    dls_region->note_range_low, dls_region->note_range_high);
211 
212             /* loop over dimension splits and set selection ranges */
213             for(i2 = 0; i2 < region->dimension_count; i2++)
214             {
215                 dimension = region->dimensions[i2];
216                 dim_type = dimension->type;
217 
218                 /* find selection info index for gig dimension type */
219                 index = GPOINTER_TO_INT(g_hash_table_lookup(sel_index_hash,
220                                         GINT_TO_POINTER(dim_type)));
221 
222                 if(!index)
223                 {
224                     continue;    /* not handled (FIXME) */
225                 }
226 
227                 /* split index for this dimension */
228                 v = (i & dimension->split_mask) >> dimension->split_shift;
229 
230                 /* dimension sub region count */
231                 sub_count = (1 << dimension->split_count);
232 
233                 /* set range based on dimension split index */
234                 ipatch_sf2_voice_cache_set_voice_range(cache, voice, index,
235                                                        128 * v / sub_count, 128 * (v + 1) / sub_count - 1);
236             }
237 
238             voice->mod_list = ipatch_sf2_mod_list_override(cache->default_mods,
239                               cache->override_mods, TRUE);
240 
241             sample = (IpatchDLS2Sample *)(sub_region->sample);
242             ipatch_sf2_voice_cache_declare_item(cache, (GObject *)sample);
243 
244             if(sub_region->sample_info)
245             {
246                 sample_info = sub_region->sample_info;
247             }
248             else
249             {
250                 sample_info = sample->sample_info;
251             }
252 
253             /* FIXME - what about stereo routing? */
254 
255             /* Assign sample */
256             ipatch_sf2_voice_set_sample_data(voice, sample->sample_data);
257 
258             /* copy sample parameters */
259             voice->rate = sample->rate;
260 
261             if(sample_info)
262             {
263                 voice->loop_start = sample_info->loop_start;
264                 voice->loop_end = sample_info->loop_end;
265                 voice->root_note = sample_info->root_note;
266                 voice->fine_tune = (guint8)sample_info->fine_tune;
267 
268                 switch(sample_info->options & IPATCH_DLS2_SAMPLE_LOOP_MASK)
269                 {
270                 case IPATCH_SAMPLE_LOOP_NONE:
271                     v = IPATCH_SF2_GEN_SAMPLE_MODE_NOLOOP;
272                     break;
273 
274                 case IPATCH_SAMPLE_LOOP_RELEASE:
275                     v = IPATCH_SF2_GEN_SAMPLE_MODE_LOOP_RELEASE;
276                     break;
277 
278                 default:	/* default to standard loop */
279                     v = IPATCH_SF2_GEN_SAMPLE_MODE_LOOP;
280                     break;
281                 }
282 
283                 /* set loop mode */
284                 voice->gen_array.values[IPATCH_SF2_GEN_SAMPLE_MODES].sword = v;
285                 IPATCH_SF2_GEN_ARRAY_SET_FLAG(&voice->gen_array,
286                                               IPATCH_SF2_GEN_SAMPLE_MODES);
287             }
288         }	// sub region loop
289 
290         IPATCH_ITEM_RUNLOCK(region);  /* -- UNLOCK region */
291     }	// region loop
292 
293     IPATCH_ITEM_RUNLOCK(inst);	/* -- UNLOCK instrument */
294 
295     g_hash_table_destroy(sel_index_hash);
296 
297     return (TRUE);
298 }
299 
300 /* use DLS sample converter function for Gig samples */
301 #define _gig_sample_to_sf2_voice_cache_convert \
302   _dls2_sample_to_sf2_voice_cache_convert
303 
304 CONVERTER_CLASS_INIT(gig_inst_to_sf2_voice_cache)
305 CONVERTER_CLASS_INIT(gig_sample_to_sf2_voice_cache)
306 
307 CONVERTER_SF2_VOICE_CACHE_GET_TYPE(gig_inst_to_sf2_voice_cache, GigInstToSF2VoiceCache)
308 CONVERTER_SF2_VOICE_CACHE_GET_TYPE(gig_sample_to_sf2_voice_cache, GigSampleToSF2VoiceCache)
309