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