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: IpatchDLS2Sample
22 * @short_description: DLS audio sample object
23 * @see_also: #IpatchDLS, #IpatchDLSRegion
24 * @stability: Stable
25 *
26 * Object which defines a DLS audio sample. These objects are contained in
27 * #IpatchDLS objects and linked (referenced) from #IpatchDLSRegion objects.
28 */
29 #include <stdarg.h>
30 #include <string.h>
31 #include <glib.h>
32 #include <glib-object.h>
33 #include "IpatchDLS2Sample.h"
34 #include "IpatchDLS2.h"
35 #include "IpatchDLSFile.h"
36 #include "IpatchDLSFile_priv.h"
37 #include "IpatchSample.h"
38 #include "IpatchSampleStoreRam.h"
39 #include "IpatchTypeProp.h"
40 #include "ipatch_priv.h"
41 #include "builtin_enums.h"
42
43 /* properties */
44 enum
45 {
46 PROP_0,
47 PROP_SAMPLE_SIZE, /* read only convenience property */
48 PROP_SAMPLE_FORMAT,
49 PROP_SAMPLE_RATE,
50 PROP_SAMPLE_DATA
51 };
52
53
54 /* sample info property enums, used by regions as well, so we define these
55 in a non-conflicting range
56 !! Keep order synchronized with IPATCH_DLS2_SAMPLE_INFO_PROPERTY_COUNT */
57 enum
58 {
59 PROP_FLAGS = IPATCH_DLS2_SAMPLE_INFO_FIRST_PROPERTY_ID,
60 PROP_LOOP_TYPE,
61 PROP_ROOT_NOTE,
62 PROP_FINE_TUNE,
63 PROP_GAIN,
64 PROP_LOOP_START,
65 PROP_LOOP_END
66 };
67
68 /* for caching sample info GParamSpec objects for an object class */
69 typedef struct
70 {
71 GObjectClass *klass; /* object class owning these properties */
72 GParamSpec *pspecs[IPATCH_DLS2_SAMPLE_INFO_PROPERTY_COUNT];
73 } ClassPropBag;
74
75 static void ipatch_dls2_sample_iface_init(IpatchSampleIface *sample_iface);
76 static gboolean
77 ipatch_dls2_sample_iface_open(IpatchSampleHandle *handle, GError **err);
78
79 static void ipatch_dls2_sample_finalize(GObject *gobject);
80 static void ipatch_dls2_sample_set_property(GObject *object,
81 guint property_id,
82 const GValue *value,
83 GParamSpec *pspec);
84 static void ipatch_dls2_sample_get_property(GObject *object,
85 guint property_id,
86 GValue *value,
87 GParamSpec *pspec);
88 static void ipatch_dls2_sample_item_copy(IpatchItem *dest, IpatchItem *src,
89 IpatchItemCopyLinkFunc link_func,
90 gpointer user_data);
91 static void ipatch_dls2_sample_item_remove_full(IpatchItem *item, gboolean full);
92 static gboolean ipatch_dls2_sample_real_set_data(IpatchDLS2Sample *sample,
93 IpatchSampleData *sampledata);
94
95
96 /* list of ClassPropBag to speed up info property notifies */
97 static GSList *info_pspec_list = NULL;
98
99
G_DEFINE_TYPE_WITH_CODE(IpatchDLS2Sample,ipatch_dls2_sample,IPATCH_TYPE_ITEM,G_IMPLEMENT_INTERFACE (IPATCH_TYPE_SAMPLE,ipatch_dls2_sample_iface_init))100 G_DEFINE_TYPE_WITH_CODE(IpatchDLS2Sample, ipatch_dls2_sample,
101 IPATCH_TYPE_ITEM,
102 G_IMPLEMENT_INTERFACE(IPATCH_TYPE_SAMPLE,
103 ipatch_dls2_sample_iface_init))
104
105 /* ----- Initialization/deinitialization of ClassPropBag list ---------------*/
106 void _ipatch_DLS2_sample_init(void)
107 {
108 info_pspec_list = NULL;
109 }
110
_ipatch_DLS2_sample_deinit()111 void _ipatch_DLS2_sample_deinit()
112 {
113 g_slist_free_full(info_pspec_list, g_free);
114 }
115
116 /* ----- IpatchDSL2SAmple object functions ---------------------------------*/
117
118 /* sample interface initialization */
119 static void
ipatch_dls2_sample_iface_init(IpatchSampleIface * sample_iface)120 ipatch_dls2_sample_iface_init(IpatchSampleIface *sample_iface)
121 {
122 sample_iface->open = ipatch_dls2_sample_iface_open;
123 sample_iface->loop_types = ipatch_sample_loop_types_standard_release;
124 }
125
126 static gboolean
ipatch_dls2_sample_iface_open(IpatchSampleHandle * handle,GError ** err)127 ipatch_dls2_sample_iface_open(IpatchSampleHandle *handle, GError **err)
128 {
129 IpatchDLS2Sample *sample = IPATCH_DLS2_SAMPLE(handle->sample);
130 g_return_val_if_fail(sample->sample_data != NULL, FALSE);
131 return (ipatch_sample_handle_cascade_open
132 (handle, (IpatchSample *)(sample->sample_data), err));
133 }
134
135 static void
ipatch_dls2_sample_class_init(IpatchDLS2SampleClass * klass)136 ipatch_dls2_sample_class_init(IpatchDLS2SampleClass *klass)
137 {
138 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
139 IpatchItemClass *item_class = IPATCH_ITEM_CLASS(klass);
140
141 obj_class->finalize = ipatch_dls2_sample_finalize;
142 obj_class->get_property = ipatch_dls2_sample_get_property;
143
144 /* we use the IpatchItem item_set_property method */
145 item_class->item_set_property = ipatch_dls2_sample_set_property;
146 item_class->copy = ipatch_dls2_sample_item_copy;
147 item_class->remove_full = ipatch_dls2_sample_item_remove_full;
148
149 g_object_class_override_property(obj_class, IPATCH_DLS2_NAME, "title");
150
151 ipatch_sample_install_property_readonly(obj_class, PROP_SAMPLE_SIZE, "sample-size");
152 ipatch_sample_install_property_readonly(obj_class, PROP_SAMPLE_FORMAT, "sample-format");
153 ipatch_sample_install_property(obj_class, PROP_SAMPLE_RATE, "sample-rate");
154 ipatch_sample_install_property(obj_class, PROP_SAMPLE_DATA, "sample-data");
155
156 ipatch_dls2_sample_info_install_class_properties(obj_class);
157 ipatch_dls2_info_install_class_properties(obj_class);
158 }
159
160 static void
ipatch_dls2_sample_init(IpatchDLS2Sample * sample)161 ipatch_dls2_sample_init(IpatchDLS2Sample *sample)
162 {
163 ipatch_dls2_sample_set_blank(sample);
164 sample->rate = IPATCH_SAMPLE_RATE_DEFAULT;
165 }
166
167 static void
ipatch_dls2_sample_finalize(GObject * gobject)168 ipatch_dls2_sample_finalize(GObject *gobject)
169 {
170 IpatchDLS2Sample *sample = IPATCH_DLS2_SAMPLE(gobject);
171
172 /* nothing should reference the sample after this, but we set
173 pointers to NULL to help catch invalid references. Locking of
174 sample is required since in reality all its children do
175 still hold references */
176
177 IPATCH_ITEM_WLOCK(sample);
178
179 if(sample->sample_data)
180 {
181 ipatch_sample_data_unused(sample->sample_data); // -- dec use count
182 g_object_unref(sample->sample_data); // -- dec reference count
183 }
184
185 if(sample->sample_info)
186 {
187 ipatch_dls2_sample_info_free(sample->sample_info);
188 }
189
190 ipatch_dls2_info_free(sample->info);
191
192 g_free(sample->dlid);
193
194 IPATCH_ITEM_WUNLOCK(sample);
195
196 if(G_OBJECT_CLASS(ipatch_dls2_sample_parent_class)->finalize)
197 {
198 G_OBJECT_CLASS(ipatch_dls2_sample_parent_class)->finalize(gobject);
199 }
200 }
201
202 static void
ipatch_dls2_sample_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)203 ipatch_dls2_sample_set_property(GObject *object, guint property_id,
204 const GValue *value, GParamSpec *pspec)
205 {
206 IpatchDLS2Sample *sample = IPATCH_DLS2_SAMPLE(object);
207 gboolean retval;
208
209 switch(property_id)
210 {
211 case PROP_SAMPLE_RATE:
212 IPATCH_ITEM_WLOCK(sample);
213 sample->rate = g_value_get_int(value);
214 IPATCH_ITEM_WUNLOCK(sample);
215 break;
216
217 case PROP_SAMPLE_DATA:
218 ipatch_dls2_sample_real_set_data(sample, (IpatchSampleData *)
219 (g_value_get_object(value)));
220 break;
221
222 default:
223 IPATCH_ITEM_WLOCK(sample);
224
225 retval = ipatch_dls2_sample_info_set_property(&sample->sample_info,
226 property_id, value);
227
228 if(!retval)
229 retval = ipatch_dls2_info_set_property(&sample->info,
230 property_id, value);
231
232 IPATCH_ITEM_WUNLOCK(sample);
233
234 /* check if "title" property needs to be notified */
235 if(property_id == IPATCH_DLS2_NAME)
236 ipatch_item_prop_notify((IpatchItem *)sample, ipatch_item_pspec_title,
237 value, NULL);
238
239 if(!retval)
240 {
241 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
242 return;
243 }
244
245 break;
246 }
247 }
248
249 static void
ipatch_dls2_sample_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)250 ipatch_dls2_sample_get_property(GObject *object, guint property_id,
251 GValue *value, GParamSpec *pspec)
252 {
253 IpatchDLS2Sample *sample = IPATCH_DLS2_SAMPLE(object);
254 gboolean retval;
255
256 switch(property_id)
257 {
258 case PROP_SAMPLE_SIZE:
259 g_return_if_fail(sample->sample_data != NULL);
260 g_object_get_property((GObject *)(sample->sample_data), "sample-size", value);
261 break;
262
263 case PROP_SAMPLE_FORMAT:
264 g_return_if_fail(sample->sample_data != NULL);
265 g_object_get_property((GObject *)(sample->sample_data), "sample-format", value);
266 break;
267
268 case PROP_SAMPLE_RATE:
269 IPATCH_ITEM_RLOCK(sample);
270 g_value_set_int(value, sample->rate);
271 IPATCH_ITEM_RUNLOCK(sample);
272 break;
273
274 case PROP_SAMPLE_DATA:
275 g_value_take_object(value, ipatch_dls2_sample_get_data(sample));
276 break;
277
278 default:
279 IPATCH_ITEM_RLOCK(sample);
280 retval = ipatch_dls2_sample_info_get_property(sample->sample_info,
281 property_id, value);
282
283 if(!retval)
284 retval = ipatch_dls2_info_get_property(sample->info,
285 property_id, value);
286
287 IPATCH_ITEM_RUNLOCK(sample);
288
289 if(!retval)
290 {
291 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
292 }
293
294 break;
295 }
296 }
297
298 static void
ipatch_dls2_sample_item_copy(IpatchItem * dest,IpatchItem * src,IpatchItemCopyLinkFunc link_func,gpointer user_data)299 ipatch_dls2_sample_item_copy(IpatchItem *dest, IpatchItem *src,
300 IpatchItemCopyLinkFunc link_func,
301 gpointer user_data)
302 {
303 IpatchDLS2Sample *src_sam, *dest_sam;
304
305 src_sam = IPATCH_DLS2_SAMPLE(src);
306 dest_sam = IPATCH_DLS2_SAMPLE(dest);
307
308 IPATCH_ITEM_RLOCK(src_sam);
309
310 dest_sam->sample_info = src_sam->sample_info ?
311 ipatch_dls2_sample_info_duplicate(src_sam->sample_info) : NULL;
312 dest_sam->info = ipatch_dls2_info_duplicate(src_sam->info);
313 ipatch_dls2_sample_set_data(dest_sam, src_sam->sample_data);
314
315 if(src_sam->dlid)
316 {
317 dest_sam->dlid = g_memdup(src_sam->dlid, IPATCH_DLS_DLID_SIZE);
318 }
319
320 IPATCH_ITEM_RUNLOCK(src_sam);
321 }
322
323 static void
ipatch_dls2_sample_item_remove_full(IpatchItem * item,gboolean full)324 ipatch_dls2_sample_item_remove_full(IpatchItem *item, gboolean full)
325 {
326 IpatchList *list;
327 IpatchIter iter;
328 IpatchItem *region;
329
330 /* ++ ref new list */
331 list = ipatch_dls2_get_region_references(IPATCH_DLS2_SAMPLE(item));
332 ipatch_list_init_iter(list, &iter);
333
334 region = ipatch_item_first(&iter);
335
336 while(region)
337 {
338 ipatch_item_remove(region);
339 item = ipatch_item_next(&iter);
340 }
341
342 g_object_unref(list); /* -- unref list */
343
344 if(full)
345 {
346 ipatch_dls2_sample_set_data(IPATCH_DLS2_SAMPLE(item), NULL);
347 }
348
349 if(IPATCH_ITEM_CLASS(ipatch_dls2_sample_parent_class)->remove_full)
350 {
351 IPATCH_ITEM_CLASS(ipatch_dls2_sample_parent_class)->remove_full(item, full);
352 }
353 }
354
355 /**
356 * ipatch_dls2_sample_new:
357 *
358 * Create a new DLS sample object.
359 *
360 * Returns: New DLS sample with a reference count of 1. Caller
361 * owns the reference and removing it will destroy the item, unless another
362 * reference is added (if its parented for example).
363 */
364 IpatchDLS2Sample *
ipatch_dls2_sample_new(void)365 ipatch_dls2_sample_new(void)
366 {
367 return (IPATCH_DLS2_SAMPLE(g_object_new(IPATCH_TYPE_DLS2_SAMPLE, NULL)));
368 }
369
370 /**
371 * ipatch_dls2_sample_first: (skip)
372 * @iter: Patch item iterator containing #IpatchDLS2Sample items
373 *
374 * Gets the first item in a sample iterator. A convenience wrapper for
375 * ipatch_iter_first().
376 *
377 * Returns: The first sample in @iter or %NULL if empty.
378 */
379 IpatchDLS2Sample *
ipatch_dls2_sample_first(IpatchIter * iter)380 ipatch_dls2_sample_first(IpatchIter *iter)
381 {
382 GObject *obj;
383 g_return_val_if_fail(iter != NULL, NULL);
384
385 obj = ipatch_iter_first(iter);
386
387 if(obj)
388 {
389 return (IPATCH_DLS2_SAMPLE(obj));
390 }
391 else
392 {
393 return (NULL);
394 }
395 }
396
397 /**
398 * ipatch_dls2_sample_next: (skip)
399 * @iter: Patch item iterator containing #IpatchDLS2Sample items
400 *
401 * Gets the next item in a sample iterator. A convenience wrapper for
402 * ipatch_iter_next().
403 *
404 * Returns: The next sample in @iter or %NULL if at the end of the list.
405 */
406 IpatchDLS2Sample *
ipatch_dls2_sample_next(IpatchIter * iter)407 ipatch_dls2_sample_next(IpatchIter *iter)
408 {
409 GObject *obj;
410 g_return_val_if_fail(iter != NULL, NULL);
411
412 obj = ipatch_iter_next(iter);
413
414 if(obj)
415 {
416 return (IPATCH_DLS2_SAMPLE(obj));
417 }
418 else
419 {
420 return (NULL);
421 }
422 }
423
424 /**
425 * ipatch_dls2_sample_set_data:
426 * @sample: Sample to set sample data of
427 * @sampledata: Sample data to set sample to. Should be NULL or a IpatchSampleData object
428 *
429 * Set a sample's sample data object.
430 */
431 void
ipatch_dls2_sample_set_data(IpatchDLS2Sample * sample,IpatchSampleData * sampledata)432 ipatch_dls2_sample_set_data(IpatchDLS2Sample *sample, IpatchSampleData *sampledata)
433 {
434 if(ipatch_dls2_sample_real_set_data(sample, sampledata))
435 {
436 g_object_notify(G_OBJECT(sample), "sample-data");
437 }
438 }
439
440 /* the actual setting of sample data, user routine does a g_object_notify */
441 static gboolean
ipatch_dls2_sample_real_set_data(IpatchDLS2Sample * sample,IpatchSampleData * sampledata)442 ipatch_dls2_sample_real_set_data(IpatchDLS2Sample *sample,
443 IpatchSampleData *sampledata)
444 {
445 IpatchSampleData *old_sampledata;
446
447 g_return_val_if_fail(IPATCH_IS_DLS2_SAMPLE(sample), FALSE);
448 if(sampledata != NULL)
449 {
450 g_return_val_if_fail (IPATCH_IS_SAMPLE_DATA (sampledata), FALSE);
451 g_object_ref (sampledata); /* ++ ref for sample */
452 ipatch_sample_data_used (sampledata); /* ++ inc use count */
453 }
454
455 IPATCH_ITEM_WLOCK(sample);
456 old_sampledata = sample->sample_data;
457 sample->sample_data = sampledata; /* !! takes over ref */
458 IPATCH_ITEM_WUNLOCK(sample);
459
460 if(old_sampledata)
461 {
462 ipatch_sample_data_unused(old_sampledata); // -- dec use count
463 g_object_unref(old_sampledata); // -- dec reference count
464 }
465
466 return (TRUE);
467 }
468
469 /**
470 * ipatch_dls2_sample_get_data:
471 * @sample: Sample to get sample data from
472 *
473 * Get the #IpatchSampleData item of a sample. Sample data item is referenced
474 * before returning and caller is responsible for unreferencing it with
475 * g_object_unref() when finished with it.
476 *
477 * Returns: (transfer full): Sample data object of sample or %NULL if none. Remember to
478 * unreference with g_object_unref() when finished with it.
479 */
480 IpatchSampleData *
ipatch_dls2_sample_get_data(IpatchDLS2Sample * sample)481 ipatch_dls2_sample_get_data(IpatchDLS2Sample *sample)
482 {
483 IpatchSampleData *sampledata;
484
485 g_return_val_if_fail(IPATCH_IS_DLS2_SAMPLE(sample), NULL);
486
487 IPATCH_ITEM_RLOCK(sample);
488 sampledata = sample->sample_data;
489
490 if(sampledata)
491 {
492 g_object_ref(sampledata); /* ++ ref */
493 }
494
495 IPATCH_ITEM_RUNLOCK(sample);
496
497 return (sampledata); /* !! caller takes over ref */
498 }
499
500 /**
501 * ipatch_dls2_sample_peek_data: (skip)
502 * @sample: Sample to get sample data from
503 *
504 * Get the #IpatchSampleData item of a sample. Like
505 * ipatch_dls2_sample_get_data() but sample data object is not referenced.
506 * This function should only be used if a reference of the sample data object
507 * is ensured or only the pointer value is of importance.
508 *
509 * Returns: (transfer none): Sample data object of sample or %NULL if none.
510 * Remember that a reference is NOT added.
511 */
512 IpatchSampleData *
ipatch_dls2_sample_peek_data(IpatchDLS2Sample * sample)513 ipatch_dls2_sample_peek_data(IpatchDLS2Sample *sample)
514 {
515 IpatchSampleData *sampledata;
516
517 g_return_val_if_fail(IPATCH_IS_DLS2_SAMPLE(sample), NULL);
518
519 IPATCH_ITEM_RLOCK(sample);
520 sampledata = sample->sample_data;
521 IPATCH_ITEM_RUNLOCK(sample);
522
523 return (sampledata);
524 }
525
526 /**
527 * ipatch_dls2_sample_set_blank:
528 * @sample: Sample to set to blank sample data
529 *
530 * Set the sample data of a sample item to blank data.
531 */
532 void
ipatch_dls2_sample_set_blank(IpatchDLS2Sample * sample)533 ipatch_dls2_sample_set_blank(IpatchDLS2Sample *sample)
534 {
535 IpatchSampleData *sampledata;
536
537 g_return_if_fail(IPATCH_IS_DLS2_SAMPLE(sample));
538
539 sampledata = ipatch_sample_data_get_blank();
540
541 IPATCH_ITEM_WLOCK(sample);
542
543 if(sample->sample_info) /* reset sample info to defaults */
544 {
545 ipatch_dls2_sample_info_free(sample->sample_info);
546 sample->sample_info = NULL;
547 }
548
549 g_object_set(sample,
550 "sample-data", sampledata,
551 "sample-rate", 44100,
552 NULL);
553 IPATCH_ITEM_WUNLOCK(sample);
554
555 g_object_unref(sampledata);
556 }
557
558 GType
ipatch_dls2_sample_info_get_type(void)559 ipatch_dls2_sample_info_get_type(void)
560 {
561 static GType type = 0;
562
563 if(!type)
564 type = g_boxed_type_register_static("IpatchDLS2SampleInfo",
565 (GBoxedCopyFunc)ipatch_dls2_sample_info_duplicate,
566 (GBoxedFreeFunc)ipatch_dls2_sample_info_free);
567
568 return (type);
569 }
570
571 /**
572 * ipatch_dls2_sample_info_new:
573 *
574 * Allocates a new sample info structure.
575 *
576 * Returns: (transfer full): New sample info structure, free it with
577 * ipatch_dls2_sample_info_free() when finished.
578 */
579 IpatchDLS2SampleInfo *
ipatch_dls2_sample_info_new(void)580 ipatch_dls2_sample_info_new(void)
581 {
582 IpatchDLS2SampleInfo *sample_info;
583
584 sample_info = g_slice_new0(IpatchDLS2SampleInfo);
585 sample_info->root_note = 60;
586
587 return (sample_info);
588 }
589
590 /**
591 * ipatch_dls2_sample_info_free:
592 * @sample_info: Sample info structure
593 *
594 * Free a sample info structure allocated with ipatch_dls2_sample_info_new().
595 */
596 void
ipatch_dls2_sample_info_free(IpatchDLS2SampleInfo * sample_info)597 ipatch_dls2_sample_info_free(IpatchDLS2SampleInfo *sample_info)
598 {
599 g_slice_free(IpatchDLS2SampleInfo, sample_info);
600 }
601
602 /**
603 * ipatch_dls2_sample_info_duplicate:
604 * @sample_info: Sample info structure to duplicate
605 *
606 * Duplicate a sample info structure.
607 *
608 * Returns: Newly allocated sample info structure which should be freed
609 * with ipatch_dls2_sample_info_free() when done with it.
610 */
611 IpatchDLS2SampleInfo *
ipatch_dls2_sample_info_duplicate(IpatchDLS2SampleInfo * sample_info)612 ipatch_dls2_sample_info_duplicate(IpatchDLS2SampleInfo *sample_info)
613 {
614 IpatchDLS2SampleInfo *newinfo;
615
616 g_return_val_if_fail(sample_info != NULL, NULL);
617
618 newinfo = ipatch_dls2_sample_info_new();
619 *newinfo = *sample_info;
620
621 return (newinfo);
622 }
623
624 /**
625 * ipatch_dls2_sample_info_init:
626 * @sample_info: Sample info structure to initialize
627 *
628 * Initialize a sample info structure to defaults.
629 */
630 void
ipatch_dls2_sample_info_init(IpatchDLS2SampleInfo * sample_info)631 ipatch_dls2_sample_info_init(IpatchDLS2SampleInfo *sample_info)
632 {
633 g_return_if_fail(sample_info != NULL);
634
635 memset(sample_info, 0, sizeof(IpatchDLS2SampleInfo));
636 sample_info->root_note = 60;
637 }
638
639 /**
640 * ipatch_dls2_sample_info_install_class_properties: (skip)
641 * @obj_class: GObjectClass to install properties for
642 *
643 * Installs sample info properties for the given @obj_class. Useful for
644 * objects that implement #IpatchDLS2SampleInfo properties.
645 */
646 void
ipatch_dls2_sample_info_install_class_properties(GObjectClass * obj_class)647 ipatch_dls2_sample_info_install_class_properties(GObjectClass *obj_class)
648 {
649 ClassPropBag *bag;
650
651 /* add new bag to cache pspecs for this class */
652 bag = g_new(ClassPropBag, 1);
653 bag->klass = obj_class;
654 info_pspec_list = g_slist_append(info_pspec_list, bag);
655
656 /* properties defined by IpatchSample interface */
657 bag->pspecs[0]
658 = ipatch_sample_install_property(obj_class, PROP_LOOP_TYPE, "loop-type");
659 bag->pspecs[1]
660 = ipatch_sample_install_property(obj_class, PROP_LOOP_START, "loop-start");
661 bag->pspecs[2]
662 = ipatch_sample_install_property(obj_class, PROP_LOOP_END, "loop-end");
663 bag->pspecs[3]
664 = ipatch_sample_install_property(obj_class, PROP_ROOT_NOTE, "root-note");
665 bag->pspecs[4]
666 = ipatch_sample_install_property(obj_class, PROP_FINE_TUNE, "fine-tune");
667
668 bag->pspecs[5]
669 = g_param_spec_flags("flags", _("Sample flags"),
670 _("Sample flags"),
671 IPATCH_TYPE_DLS2_SAMPLE_FLAGS,
672 0,
673 G_PARAM_READWRITE);
674 g_object_class_install_property(obj_class, PROP_FLAGS, bag->pspecs[5]);
675
676 bag->pspecs[6]
677 = g_param_spec_int("gain", _("Gain"),
678 _("Gain in DLS relative gain units"),
679 G_MININT, G_MAXINT, 0,
680 G_PARAM_READWRITE);
681 g_object_class_install_property(obj_class, PROP_GAIN, bag->pspecs[6]);
682 }
683
684 /**
685 * ipatch_dls2_sample_info_is_property_id_valid: (skip)
686 * @property_id: Property ID to test
687 *
688 * Check if a property ID is a valid sample info property ID.
689 *
690 * Returns: %TRUE if property_id is a sample info property ID, %FALSE otherwise.
691 */
692 gboolean
ipatch_dls2_sample_info_is_property_id_valid(guint property_id)693 ipatch_dls2_sample_info_is_property_id_valid(guint property_id)
694 {
695 return (property_id == PROP_FLAGS || property_id == PROP_LOOP_TYPE
696 || property_id == PROP_ROOT_NOTE || property_id == PROP_FINE_TUNE
697 || property_id == PROP_GAIN || property_id == PROP_LOOP_START
698 || property_id == PROP_LOOP_END);
699 }
700
701 /**
702 * ipatch_dls2_sample_info_set_property: (skip)
703 * @sample_info: Pointer to pointer to sample info
704 * @property_id: Property ID
705 * @value: Value for property
706 *
707 * A function used by set_property methods that implement #IpatchDLS2SampleInfo
708 * properties.
709 *
710 * Returns: %TRUE if property_id was handled, %FALSE otherwise
711 */
712 gboolean
ipatch_dls2_sample_info_set_property(IpatchDLS2SampleInfo ** sample_info,guint property_id,const GValue * value)713 ipatch_dls2_sample_info_set_property(IpatchDLS2SampleInfo **sample_info,
714 guint property_id, const GValue *value)
715 {
716 IpatchDLS2SampleInfo *saminfo;
717
718 if(!*sample_info)
719 {
720 if(property_id != PROP_FLAGS && property_id != PROP_LOOP_TYPE
721 && property_id != PROP_ROOT_NOTE && property_id != PROP_FINE_TUNE
722 && property_id != PROP_GAIN && property_id != PROP_LOOP_START
723 && property_id != PROP_LOOP_END)
724 {
725 return (FALSE);
726 }
727
728 *sample_info = ipatch_dls2_sample_info_new();
729 }
730
731 saminfo = *sample_info;
732
733 switch(property_id)
734 {
735 case PROP_FLAGS:
736 saminfo->options &= ~IPATCH_DLS2_SAMPLE_FLAGS_MASK;
737 saminfo->options |= g_value_get_flags(value)
738 & IPATCH_DLS2_SAMPLE_FLAGS_MASK;
739 break;
740
741 case PROP_LOOP_TYPE:
742 saminfo->options &= ~IPATCH_DLS2_SAMPLE_LOOP_MASK;
743 saminfo->options |= g_value_get_enum(value)
744 & IPATCH_DLS2_SAMPLE_LOOP_MASK;
745 break;
746
747 case PROP_ROOT_NOTE:
748 saminfo->root_note = g_value_get_int(value);
749 break;
750
751 case PROP_FINE_TUNE:
752 saminfo->fine_tune = g_value_get_int(value);
753 break;
754
755 case PROP_GAIN:
756 saminfo->gain = g_value_get_int(value);
757 break;
758
759 case PROP_LOOP_START:
760 saminfo->loop_start = g_value_get_uint(value);
761 break;
762
763 case PROP_LOOP_END:
764 saminfo->loop_end = g_value_get_uint(value);
765 break;
766
767 default:
768 return (FALSE);
769 }
770
771 return (TRUE);
772 }
773
774 /**
775 * ipatch_dls2_sample_info_get_property: (skip)
776 * @sample_info: Pointer to sample info
777 * @property_id: Property ID
778 * @value: Value to set
779 *
780 * A function used by get_property methods that implement #IpatchDLS2SampleInfo
781 * properties.
782 *
783 * Returns: %TRUE if property_id was handled, %FALSE otherwise
784 */
785 gboolean
ipatch_dls2_sample_info_get_property(IpatchDLS2SampleInfo * sample_info,guint property_id,GValue * value)786 ipatch_dls2_sample_info_get_property(IpatchDLS2SampleInfo *sample_info,
787 guint property_id, GValue *value)
788 {
789 switch(property_id)
790 {
791 case PROP_FLAGS:
792 g_value_set_flags(value, sample_info ?
793 (sample_info->options
794 & IPATCH_DLS2_SAMPLE_FLAGS_MASK) : 0);
795 break;
796
797 case PROP_LOOP_TYPE:
798 g_value_set_enum(value, sample_info ?
799 (sample_info->options
800 & IPATCH_DLS2_SAMPLE_LOOP_MASK)
801 : IPATCH_SAMPLE_LOOP_NONE);
802 break;
803
804 case PROP_ROOT_NOTE:
805 g_value_set_int(value, sample_info ? sample_info->root_note : 60);
806 break;
807
808 case PROP_FINE_TUNE:
809 g_value_set_int(value, sample_info ? sample_info->fine_tune : 0);
810 break;
811
812 case PROP_GAIN:
813 g_value_set_int(value, sample_info ? sample_info->gain : 0);
814 break;
815
816 case PROP_LOOP_START:
817 g_value_set_uint(value, sample_info ? sample_info->loop_start : 0);
818 break;
819
820 case PROP_LOOP_END:
821 g_value_set_uint(value, sample_info ? sample_info->loop_end : 0);
822 break;
823
824 default:
825 return (FALSE);
826 }
827
828 return (TRUE);
829 }
830
831 /**
832 * ipatch_dls2_sample_info_notify_changes: (skip)
833 * @item: Item to send #IpatchItem property notifies on
834 * @newinfo: New sample info values
835 * @oldinfo: Old sample info values
836 *
837 * Sends #IpatchItem property notifies for changed sample info parameters.
838 */
839 void
ipatch_dls2_sample_info_notify_changes(IpatchItem * item,IpatchDLS2SampleInfo * newinfo,IpatchDLS2SampleInfo * oldinfo)840 ipatch_dls2_sample_info_notify_changes(IpatchItem *item,
841 IpatchDLS2SampleInfo *newinfo,
842 IpatchDLS2SampleInfo *oldinfo)
843 {
844 GParamSpec **found_pspec_cache = NULL;
845 GObjectClass *klass;
846 GValue newval = { 0 }, oldval = { 0 };
847 GSList *p;
848
849 g_return_if_fail(IPATCH_IS_ITEM(item));
850
851 klass = G_OBJECT_GET_CLASS(item);
852
853 /* search for param spec cache for object's class */
854 for(p = info_pspec_list; p; p = p->next)
855 {
856 if(((ClassPropBag *)(p->data))->klass == klass)
857 {
858 found_pspec_cache = ((ClassPropBag *)(p->data))->pspecs;
859 break;
860 }
861 }
862
863 g_return_if_fail(found_pspec_cache);
864
865 if((oldinfo->options & IPATCH_DLS2_SAMPLE_LOOP_MASK)
866 != (newinfo->options & IPATCH_DLS2_SAMPLE_LOOP_MASK))
867 {
868 g_value_init(&newval, IPATCH_TYPE_SAMPLE_LOOP_TYPE);
869 g_value_init(&oldval, IPATCH_TYPE_SAMPLE_LOOP_TYPE);
870 g_value_set_enum(&newval, newinfo->options & IPATCH_DLS2_SAMPLE_LOOP_MASK);
871 g_value_set_enum(&oldval, oldinfo->options & IPATCH_DLS2_SAMPLE_LOOP_MASK);
872 ipatch_item_prop_notify(item, found_pspec_cache[0], &newval, &oldval);
873 g_value_unset(&newval);
874 g_value_unset(&oldval);
875 }
876
877 if((oldinfo->options & IPATCH_DLS2_SAMPLE_FLAGS_MASK)
878 != (newinfo->options & IPATCH_DLS2_SAMPLE_FLAGS_MASK))
879 {
880 g_value_init(&newval, IPATCH_TYPE_DLS2_SAMPLE_FLAGS);
881 g_value_init(&oldval, IPATCH_TYPE_DLS2_SAMPLE_FLAGS);
882 g_value_set_flags(&newval, newinfo->options & IPATCH_DLS2_SAMPLE_FLAGS_MASK);
883 g_value_set_flags(&oldval, oldinfo->options & IPATCH_DLS2_SAMPLE_FLAGS_MASK);
884 ipatch_item_prop_notify(item, found_pspec_cache[1], &newval, &oldval);
885 g_value_unset(&newval);
886 g_value_unset(&oldval);
887 }
888
889 if(oldinfo->root_note != newinfo->root_note)
890 {
891 g_value_init(&newval, G_TYPE_INT);
892 g_value_init(&oldval, G_TYPE_INT);
893 g_value_set_int(&newval, newinfo->root_note);
894 g_value_set_int(&oldval, oldinfo->root_note);
895 ipatch_item_prop_notify(item, found_pspec_cache[2], &newval, &oldval);
896 g_value_unset(&newval);
897 g_value_unset(&oldval);
898 }
899
900 if(oldinfo->fine_tune != newinfo->fine_tune)
901 {
902 g_value_init(&newval, G_TYPE_INT);
903 g_value_init(&oldval, G_TYPE_INT);
904 g_value_set_int(&newval, newinfo->fine_tune);
905 g_value_set_int(&oldval, oldinfo->fine_tune);
906 ipatch_item_prop_notify(item, found_pspec_cache[3], &newval, &oldval);
907 g_value_unset(&newval);
908 g_value_unset(&oldval);
909 }
910
911 if(oldinfo->gain != newinfo->gain)
912 {
913 g_value_init(&newval, G_TYPE_INT);
914 g_value_init(&oldval, G_TYPE_INT);
915 g_value_set_int(&newval, newinfo->gain);
916 g_value_set_int(&oldval, oldinfo->gain);
917 ipatch_item_prop_notify(item, found_pspec_cache[4], &newval, &oldval);
918 g_value_unset(&newval);
919 g_value_unset(&oldval);
920 }
921
922 if(oldinfo->loop_start != newinfo->loop_start)
923 {
924 g_value_init(&newval, G_TYPE_UINT);
925 g_value_init(&oldval, G_TYPE_UINT);
926 g_value_set_uint(&newval, newinfo->loop_start);
927 g_value_set_uint(&oldval, oldinfo->loop_start);
928 ipatch_item_prop_notify(item, found_pspec_cache[5], &newval, &oldval);
929 g_value_unset(&newval);
930 g_value_unset(&oldval);
931 }
932
933 if(oldinfo->loop_end != newinfo->loop_end)
934 {
935 g_value_init(&newval, G_TYPE_UINT);
936 g_value_init(&oldval, G_TYPE_UINT);
937 g_value_set_uint(&newval, newinfo->loop_end);
938 g_value_set_uint(&oldval, oldinfo->loop_end);
939 ipatch_item_prop_notify(item, found_pspec_cache[6], &newval, &oldval);
940 g_value_unset(&newval);
941 g_value_unset(&oldval);
942 }
943 }
944