1 /*
2  * libInstPatch
3  * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
4  *
5  * Author of this file: (C) 2012 BALATON Zoltan <balaton@eik.bme.hu>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; version 2.1
10  * of the License only.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA or on the web at http://www.gnu.org.
21  */
22 /**
23  * SECTION: IpatchSLIZone
24  * @short_description: Spectralis instrument zone object
25  * @see_also:
26  *
27  * Zones are children of #IpatchSLIInst and define how
28  * their referenced #IpatchSLISample is synthesized.
29  */
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <glib.h>
34 #include <glib-object.h>
35 #include "IpatchSLIZone.h"
36 #include "IpatchSF2GenItem.h"
37 #include "IpatchSample.h"
38 #include "IpatchContainer.h"
39 #include "IpatchTypeProp.h"
40 #include "IpatchRange.h"
41 #include "builtin_enums.h"
42 #include "ipatch_priv.h"
43 
44 static void ipatch_sli_zone_sample_iface_init(IpatchSampleIface *sample_iface);
45 static gboolean ipatch_sli_zone_sample_iface_open(IpatchSampleHandle *handle,
46         GError **err);
47 static void ipatch_sli_zone_gen_item_iface_init(IpatchSF2GenItemIface *genitem_iface);
48 static void ipatch_sli_zone_class_init(IpatchSLIZoneClass *klass);
49 static inline void ipatch_sli_zone_get_root_note(IpatchSLIZone *zone,
50         GValue *value);
51 static inline void ipatch_sli_zone_get_fine_tune(IpatchSLIZone *zone,
52         GValue *value);
53 static void ipatch_sli_zone_finalize(GObject *gobject);
54 static void ipatch_sli_zone_get_title(IpatchSLIZone *zone, GValue *value);
55 static void ipatch_sli_zone_set_property(GObject *object, guint property_id,
56         const GValue *value, GParamSpec *pspec);
57 static void ipatch_sli_zone_get_property(GObject *object,
58         guint property_id, GValue *value,
59         GParamSpec *pspec);
60 static void ipatch_sli_zone_item_copy(IpatchItem *dest, IpatchItem *src,
61                                       IpatchItemCopyLinkFunc link_func,
62                                       gpointer user_data);
63 static void ipatch_sli_zone_item_remove_full(IpatchItem *item, gboolean full);
64 static void ipatch_sli_zone_real_set_sample(IpatchSLIZone *zone,
65         IpatchSLISample *sample,
66         gboolean sample_notify);
67 
68 /* generator property IDs go before these */
69 enum
70 {
71     PROP_TITLE = IPATCH_SF2_GEN_ITEM_FIRST_PROP_USER_ID,
72     PROP_LINK_ITEM,
73     PROP_SAMPLE_SIZE,
74     PROP_SAMPLE_FORMAT,
75     PROP_SAMPLE_RATE,
76     PROP_SAMPLE_DATA,
77     PROP_LOOP_TYPE,
78     PROP_LOOP_START,
79     PROP_LOOP_END,
80     PROP_ROOT_NOTE,
81     PROP_FINE_TUNE
82 };
83 
84 /* For quicker access without lookup */
85 static GParamSpec *link_item_pspec;
86 static GParamSpec *root_note_pspec;
87 static GParamSpec *fine_tune_pspec;
88 
89 /* For passing data from class init to gen item interface init */
90 static GParamSpec **gen_item_specs = NULL;
91 static GParamSpec **gen_item_setspecs = NULL;
92 
G_DEFINE_TYPE_WITH_CODE(IpatchSLIZone,ipatch_sli_zone,IPATCH_TYPE_ITEM,G_IMPLEMENT_INTERFACE (IPATCH_TYPE_SAMPLE,ipatch_sli_zone_sample_iface_init)G_IMPLEMENT_INTERFACE (IPATCH_TYPE_SF2_GEN_ITEM,ipatch_sli_zone_gen_item_iface_init))93 G_DEFINE_TYPE_WITH_CODE(IpatchSLIZone, ipatch_sli_zone, IPATCH_TYPE_ITEM,
94                         G_IMPLEMENT_INTERFACE(IPATCH_TYPE_SAMPLE,
95                                 ipatch_sli_zone_sample_iface_init)
96                         G_IMPLEMENT_INTERFACE(IPATCH_TYPE_SF2_GEN_ITEM,
97                                 ipatch_sli_zone_gen_item_iface_init))
98 
99 /* sample interface initialization */
100 static void
101 ipatch_sli_zone_sample_iface_init(IpatchSampleIface *sample_iface)
102 {
103     sample_iface->open = ipatch_sli_zone_sample_iface_open;
104     sample_iface->loop_types = ipatch_sample_loop_types_standard;
105 }
106 
107 static gboolean
ipatch_sli_zone_sample_iface_open(IpatchSampleHandle * handle,GError ** err)108 ipatch_sli_zone_sample_iface_open(IpatchSampleHandle *handle, GError **err)
109 {
110     IpatchSLIZone *zone = IPATCH_SLI_ZONE(handle->sample);
111     IpatchSLISample *sample;
112     gboolean retval;
113 
114     sample = ipatch_sli_zone_get_sample(zone);      /* ++ ref sample */
115     g_return_val_if_fail(sample != NULL, FALSE);
116     retval = ipatch_sample_handle_cascade_open(handle, IPATCH_SAMPLE(sample), err);
117     g_object_unref(sample);    /* -- unref sample */
118     return (retval);
119 }
120 
121 /* gen item interface initialization */
122 static void
ipatch_sli_zone_gen_item_iface_init(IpatchSF2GenItemIface * genitem_iface)123 ipatch_sli_zone_gen_item_iface_init(IpatchSF2GenItemIface *genitem_iface)
124 {
125     genitem_iface->genarray_ofs = G_STRUCT_OFFSET(IpatchSLIZone, genarray);
126     genitem_iface->propstype = IPATCH_SF2_GEN_PROPS_INST;
127 
128     g_return_if_fail(gen_item_specs != NULL);
129     g_return_if_fail(gen_item_setspecs != NULL);
130 
131     memcpy(&genitem_iface->specs, gen_item_specs, sizeof(genitem_iface->specs));
132     memcpy(&genitem_iface->setspecs, gen_item_setspecs, sizeof(genitem_iface->setspecs));
133     g_free(gen_item_specs);
134     g_free(gen_item_setspecs);
135 }
136 
137 static void
ipatch_sli_zone_class_init(IpatchSLIZoneClass * klass)138 ipatch_sli_zone_class_init(IpatchSLIZoneClass *klass)
139 {
140     GObjectClass *obj_class = G_OBJECT_CLASS(klass);
141     IpatchItemClass *item_class = IPATCH_ITEM_CLASS(klass);
142 
143     obj_class->finalize = ipatch_sli_zone_finalize;
144     obj_class->get_property = ipatch_sli_zone_get_property;
145 
146     item_class->copy = ipatch_sli_zone_item_copy;
147     item_class->item_set_property = ipatch_sli_zone_set_property;
148     item_class->remove_full = ipatch_sli_zone_item_remove_full;
149 
150     g_object_class_override_property(obj_class, PROP_TITLE, "title");
151 
152     link_item_pspec = g_param_spec_object("link-item", _("Link item"),
153                                           _("Link item"), IPATCH_TYPE_SLI_SAMPLE,
154                                           G_PARAM_READWRITE);
155     g_object_class_install_property(obj_class, PROP_LINK_ITEM, link_item_pspec);
156 
157     /* properties defined by IpatchSample interface */
158     ipatch_sample_install_property_readonly(obj_class, PROP_SAMPLE_SIZE,
159                                             "sample-size");
160     ipatch_sample_install_property_readonly(obj_class, PROP_SAMPLE_FORMAT,
161                                             "sample-format");
162     ipatch_sample_install_property(obj_class, PROP_SAMPLE_RATE, "sample-rate");
163     ipatch_sample_install_property_readonly(obj_class, PROP_SAMPLE_DATA,
164                                             "sample-data");
165     ipatch_sample_install_property(obj_class, PROP_LOOP_TYPE, "loop-type");
166     ipatch_sample_install_property(obj_class, PROP_LOOP_START, "loop-start");
167     ipatch_sample_install_property(obj_class, PROP_LOOP_END, "loop-end");
168     root_note_pspec = ipatch_sample_install_property(obj_class, PROP_ROOT_NOTE,
169                       "root-note");
170     fine_tune_pspec = ipatch_sample_install_property(obj_class, PROP_FINE_TUNE,
171                       "fine-tune");
172 
173     /* install generator properties */
174     ipatch_sf2_gen_item_iface_install_properties(obj_class,
175             IPATCH_SF2_GEN_PROPS_INST,
176             &gen_item_specs,
177             &gen_item_setspecs);
178 }
179 
180 static void
ipatch_sli_zone_init(IpatchSLIZone * zone)181 ipatch_sli_zone_init(IpatchSLIZone *zone)
182 {
183     ipatch_sf2_gen_array_init(&zone->genarray, FALSE, FALSE);
184 }
185 
186 static void
ipatch_sli_zone_finalize(GObject * gobject)187 ipatch_sli_zone_finalize(GObject *gobject)
188 {
189     IpatchSLIZone *zone = IPATCH_SLI_ZONE(gobject);
190 
191     IPATCH_ITEM_WLOCK(zone);
192 
193     if(zone->sample)
194     {
195         g_object_unref(zone->sample);
196         zone->sample = NULL;
197     }
198 
199     IPATCH_ITEM_WUNLOCK(zone);
200 
201     if(G_OBJECT_CLASS(ipatch_sli_zone_parent_class)->finalize)
202     {
203         G_OBJECT_CLASS(ipatch_sli_zone_parent_class)->finalize(gobject);
204     }
205 }
206 
207 static inline void
ipatch_sli_zone_get_root_note(IpatchSLIZone * zone,GValue * value)208 ipatch_sli_zone_get_root_note(IpatchSLIZone *zone, GValue *value)
209 {
210     IpatchSF2GenAmount amount;
211     IpatchSLISample *sample;
212     int val = 0;
213 
214     /* root note override not set or -1? - Get sample root note value. */
215     if(!ipatch_sf2_gen_item_get_amount(IPATCH_SF2_GEN_ITEM(zone),
216                                        IPATCH_SF2_GEN_ROOT_NOTE_OVERRIDE, &amount)
217             || amount.sword == -1)
218     {
219         /* root note override not set, get from sample */
220         sample = ipatch_sli_zone_get_sample(zone);  /* ++ ref sample */
221 
222         if(sample)
223         {
224             g_object_get(sample, "root-note", &val, NULL);
225             g_object_unref(sample);  /* -- unref sample */
226         }
227     }
228     else
229     {
230         val = amount.uword;
231     }
232 
233     g_value_set_int(value, val);
234 }
235 
236 static inline void
ipatch_sli_zone_get_fine_tune(IpatchSLIZone * zone,GValue * value)237 ipatch_sli_zone_get_fine_tune(IpatchSLIZone *zone, GValue *value)
238 {
239     IpatchSF2GenAmount amount;
240     IpatchSLISample *sample;
241     int val = 0;
242 
243     /* fine tune override set? */
244     if(!ipatch_sf2_gen_item_get_amount(IPATCH_SF2_GEN_ITEM(zone),
245                                        IPATCH_SF2_GEN_FINE_TUNE_OVERRIDE, &amount))
246     {
247         /* fine tune override not set, get from sample */
248         sample = ipatch_sli_zone_get_sample(zone);  /* ++ ref sample */
249 
250         if(sample)
251         {
252             g_object_get(sample, "fine-tune", &val, NULL);
253             g_object_unref(sample);  /* -- unref sample */
254         }
255     }
256     else
257     {
258         val = amount.sword;
259     }
260 
261     g_value_set_int(value, val);
262 }
263 
264 static void
ipatch_sli_zone_get_title(IpatchSLIZone * zone,GValue * value)265 ipatch_sli_zone_get_title(IpatchSLIZone *zone, GValue *value)
266 {
267     IpatchSLISample *sample;
268     char *s = NULL;
269 
270     sample = ipatch_sli_zone_get_sample(zone);  /* ++ ref sample */
271 
272     if(sample)
273     {
274         g_object_get(sample, "name", &s, NULL);
275         g_object_unref(sample);  /* -- unref sample */
276     }
277 
278     g_value_take_string(value, s);
279 }
280 
281 static void
ipatch_sli_zone_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)282 ipatch_sli_zone_set_property(GObject *object, guint property_id,
283                              const GValue *value, GParamSpec *pspec)
284 {
285     IpatchSLIZone *zone = IPATCH_SLI_ZONE(object);
286     IpatchSLISample *sample;
287     IpatchSF2GenAmount amount;
288     GValue vals[2];	/* Gets zeroed below */
289     guint genid;
290     guint uval;
291     int val = 0;
292 
293     /* "root-note" and "fine-tune" sample properties get updated for Zone
294      * override property or -set property */
295     if(property_id >= IPATCH_SF2_GEN_ITEM_FIRST_PROP_SET_ID)
296     {
297         genid = property_id - IPATCH_SF2_GEN_ITEM_FIRST_PROP_SET_ID;
298     }
299     else
300     {
301         genid = property_id - IPATCH_SF2_GEN_ITEM_FIRST_PROP_ID;
302     }
303 
304     if(genid == IPATCH_SF2_GEN_ROOT_NOTE_OVERRIDE)
305     {
306         memset(vals, 0, sizeof(vals));
307         g_value_init(&vals[0], G_TYPE_INT);
308         ipatch_sli_zone_get_root_note(zone, &vals[0]);
309     }
310     else if(genid == IPATCH_SF2_GEN_FINE_TUNE_OVERRIDE)
311     {
312         memset(vals, 0, sizeof(vals));
313         g_value_init(&vals[0], G_TYPE_INT);
314         ipatch_sli_zone_get_fine_tune(zone, &vals[0]);
315     }
316 
317     if(ipatch_sf2_gen_item_iface_set_property((IpatchSF2GenItem *)object,
318             property_id, value))
319     {
320         if(genid == IPATCH_SF2_GEN_ROOT_NOTE_OVERRIDE)
321         {
322             g_value_init(&vals[1], G_TYPE_INT);
323             ipatch_sli_zone_get_root_note(zone, &vals[1]);
324             ipatch_item_prop_notify((IpatchItem *)object, root_note_pspec,
325                                     &vals[1], &vals[0]);
326         }
327         else if(genid == IPATCH_SF2_GEN_FINE_TUNE_OVERRIDE)
328         {
329             g_value_init(&vals[1], G_TYPE_INT);
330             ipatch_sli_zone_get_fine_tune(zone, &vals[1]);
331             ipatch_item_prop_notify((IpatchItem *)object, fine_tune_pspec,
332                                     &vals[1], &vals[0]);
333         }
334     }
335     else
336     {
337         switch(property_id)
338         {
339         case PROP_LINK_ITEM:
340             ipatch_sli_zone_real_set_sample(zone, IPATCH_SLI_SAMPLE
341                                             (g_value_get_object(value)), FALSE);
342             break;
343 
344         case PROP_SAMPLE_RATE:
345             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
346 
347             if(sample)
348             {
349                 g_object_set(sample, "sample-rate", g_value_get_int(value), NULL);
350                 g_object_unref(sample);  /* -- unref sample */
351             }
352 
353             break;
354 
355         case PROP_LOOP_TYPE:
356             val = g_value_get_enum(value);
357 
358             if(val == IPATCH_SAMPLE_LOOP_NONE)
359             {
360                 amount.uword = IPATCH_SF2_GEN_SAMPLE_MODE_NOLOOP;
361             }
362             else
363             {
364                 amount.uword = IPATCH_SF2_GEN_SAMPLE_MODE_LOOP;
365             }
366 
367             ipatch_sf2_gen_item_set_amount(IPATCH_SF2_GEN_ITEM(zone),
368                                            IPATCH_SF2_GEN_SAMPLE_MODES, &amount);
369             break;
370 
371         case PROP_LOOP_START:
372             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
373 
374             if(sample)
375             {
376                 g_object_get(sample, "loop-start", &uval, NULL);
377                 val = g_value_get_uint(value) - uval;  /* loop start offset */
378                 g_object_unref(sample);  /* -- unref sample */
379 
380                 if(val >= 0)
381                 {
382                     amount.sword = val >> 15;
383                 }
384                 else
385                 {
386                     amount.sword = -(-val >> 15);
387                 }
388 
389                 ipatch_sf2_gen_item_set_amount(IPATCH_SF2_GEN_ITEM(zone),
390                                                IPATCH_SF2_GEN_SAMPLE_COARSE_LOOP_START, &amount);
391 
392                 if(val >= 0)
393                 {
394                     amount.sword = val & 0x7FFF;
395                 }
396                 else
397                 {
398                     amount.sword = -(-val & 0x7FFF);
399                 }
400 
401                 ipatch_sf2_gen_item_set_amount(IPATCH_SF2_GEN_ITEM(zone),
402                                                IPATCH_SF2_GEN_SAMPLE_LOOP_START, &amount);
403             }
404 
405             break;
406 
407         case PROP_LOOP_END:
408             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
409 
410             if(sample)
411             {
412                 g_object_get(sample, "loop-end", &uval, NULL);
413                 val = g_value_get_uint(value) - uval;  /* loop end offset */
414                 g_object_unref(sample);  /* -- unref sample */
415 
416                 if(val >= 0)
417                 {
418                     amount.sword = val >> 15;
419                 }
420                 else
421                 {
422                     amount.sword = -(-val >> 15);
423                 }
424 
425                 ipatch_sf2_gen_item_set_amount(IPATCH_SF2_GEN_ITEM(zone),
426                                                IPATCH_SF2_GEN_SAMPLE_COARSE_LOOP_END, &amount);
427 
428                 if(val >= 0)
429                 {
430                     amount.sword = val & 0x7FFF;
431                 }
432                 else
433                 {
434                     amount.sword = -(-val & 0x7FFF);
435                 }
436 
437                 ipatch_sf2_gen_item_set_amount(IPATCH_SF2_GEN_ITEM(zone),
438                                                IPATCH_SF2_GEN_SAMPLE_LOOP_END, &amount);
439             }
440 
441             break;
442 
443         case PROP_ROOT_NOTE:
444             amount.uword = g_value_get_int(value);
445             ipatch_sf2_gen_item_set_amount(IPATCH_SF2_GEN_ITEM(zone),
446                                            IPATCH_SF2_GEN_ROOT_NOTE_OVERRIDE, &amount);
447             break;
448 
449         case PROP_FINE_TUNE:
450             amount.sword = g_value_get_int(value);
451             ipatch_sf2_gen_item_set_amount(IPATCH_SF2_GEN_ITEM(zone),
452                                            IPATCH_SF2_GEN_FINE_TUNE_OVERRIDE, &amount);
453             break;
454 
455         default:
456             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
457             return;
458         }
459     }
460 }
461 
462 static void
ipatch_sli_zone_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)463 ipatch_sli_zone_get_property(GObject *object, guint property_id,
464                              GValue *value, GParamSpec *pspec)
465 {
466     IpatchSLIZone *zone = IPATCH_SLI_ZONE(object);
467     IpatchSLISample *sample;
468     IpatchSF2GenAmount amount;
469     guint uval = 0;
470     int val = 0;
471 
472     if(!ipatch_sf2_gen_item_iface_get_property((IpatchSF2GenItem *)object,
473             property_id, value))
474     {
475         switch(property_id)
476         {
477         case PROP_TITLE:
478             ipatch_sli_zone_get_title(zone, value);
479             break;
480 
481         case PROP_LINK_ITEM:
482             g_value_take_object(value, ipatch_sli_zone_get_sample(zone));
483             break;
484 
485         case PROP_SAMPLE_SIZE:
486             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
487 
488             if(sample)
489             {
490                 g_object_get_property((GObject *)sample, "sample-size", value);
491                 g_object_unref(sample);  /* -- unref sample */
492             }
493 
494             break;
495 
496         case PROP_SAMPLE_FORMAT:
497             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
498 
499             if(sample)
500             {
501                 g_object_get_property((GObject *)sample, "sample-format", value);
502                 g_object_unref(sample);  /* -- unref sample */
503             }
504 
505             break;
506 
507         case PROP_SAMPLE_RATE:
508             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
509 
510             if(sample)
511             {
512                 g_object_get_property((GObject *)sample, "sample-rate", value);
513                 g_object_unref(sample);  /* -- unref sample */
514             }
515 
516             break;
517 
518         case PROP_SAMPLE_DATA:
519             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
520 
521             if(sample)
522             {
523                 g_object_get_property((GObject *)sample, "sample-data", value);
524                 g_object_unref(sample);  /* -- unref sample */
525             }
526 
527             break;
528 
529         case PROP_LOOP_TYPE:
530             ipatch_sf2_gen_item_get_amount(IPATCH_SF2_GEN_ITEM(zone),
531                                            IPATCH_SF2_GEN_SAMPLE_MODES, &amount);
532 
533             if(amount.uword == IPATCH_SF2_GEN_SAMPLE_MODE_NOLOOP)
534             {
535                 val = IPATCH_SAMPLE_LOOP_NONE;
536             }
537             else
538             {
539                 val = IPATCH_SAMPLE_LOOP_STANDARD;
540             }
541 
542             g_value_set_enum(value, val);
543             break;
544 
545         case PROP_LOOP_START:
546             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
547 
548             if(sample)
549             {
550                 g_object_get(sample, "loop-start", &uval, NULL);
551                 g_object_unref(sample);  /* -- unref sample */
552                 val = uval;
553             }
554 
555             ipatch_sf2_gen_item_get_amount(IPATCH_SF2_GEN_ITEM(zone),
556                                            IPATCH_SF2_GEN_SAMPLE_COARSE_LOOP_START,
557                                            &amount);
558             val += (int)amount.sword << 15;
559 
560             ipatch_sf2_gen_item_get_amount(IPATCH_SF2_GEN_ITEM(zone),
561                                            IPATCH_SF2_GEN_SAMPLE_LOOP_START, &amount);
562             val += amount.sword;
563 
564             g_value_set_uint(value, CLAMP(val, 0, G_MAXINT));
565             break;
566 
567         case PROP_LOOP_END:
568             sample = ipatch_sli_zone_get_sample(zone);	/* ++ ref sample */
569 
570             if(sample)
571             {
572                 g_object_get(sample, "loop-end", &uval, NULL);
573                 g_object_unref(sample);  /* -- unref sample */
574                 val = uval;
575             }
576 
577             ipatch_sf2_gen_item_get_amount(IPATCH_SF2_GEN_ITEM(zone),
578                                            IPATCH_SF2_GEN_SAMPLE_COARSE_LOOP_END,
579                                            &amount);
580             val += (int)amount.sword << 15;
581 
582             ipatch_sf2_gen_item_get_amount(IPATCH_SF2_GEN_ITEM(zone),
583                                            IPATCH_SF2_GEN_SAMPLE_LOOP_END, &amount);
584             val += amount.sword;
585 
586             g_value_set_uint(value, CLAMP(val, 0, G_MAXINT));
587             break;
588 
589         case PROP_ROOT_NOTE:
590             ipatch_sli_zone_get_root_note(zone, value);
591             break;
592 
593         case PROP_FINE_TUNE:
594             ipatch_sli_zone_get_fine_tune(zone, value);
595             break;
596 
597         default:
598             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
599             return;
600         }
601     }
602 }
603 
604 static void
ipatch_sli_zone_item_copy(IpatchItem * dest,IpatchItem * src,IpatchItemCopyLinkFunc link_func,gpointer user_data)605 ipatch_sli_zone_item_copy(IpatchItem *dest, IpatchItem *src,
606                           IpatchItemCopyLinkFunc link_func,
607                           gpointer user_data)
608 {
609     IpatchSLIZone *src_zone, *dest_zone;
610     IpatchSLISample *refsample;
611 
612     src_zone = IPATCH_SLI_ZONE(src);
613     dest_zone = IPATCH_SLI_ZONE(dest);
614 
615     IPATCH_ITEM_RLOCK(src_zone);
616 
617     /* pass the link to the link handler (if any) */
618     refsample = (IpatchSLISample *)
619                 IPATCH_ITEM_COPY_LINK_FUNC(dest,
620                                            IPATCH_ITEM(src_zone->sample),
621                                            link_func, user_data);
622 
623     if(refsample)
624     {
625         ipatch_sli_zone_set_sample(dest_zone, refsample);
626     }
627 
628     /* duplicate generator array */
629     memcpy(&dest_zone->genarray, &src_zone->genarray,
630            sizeof(IpatchSF2GenArray));
631 
632     IPATCH_ITEM_RUNLOCK(src_zone);
633 }
634 
635 static void
ipatch_sli_zone_item_remove_full(IpatchItem * item,gboolean full)636 ipatch_sli_zone_item_remove_full(IpatchItem *item, gboolean full)
637 {
638     if(full)
639     {
640         ipatch_sli_zone_set_sample(IPATCH_SLI_ZONE(item), NULL);
641     }
642 
643     if(IPATCH_ITEM_CLASS(ipatch_sli_zone_parent_class)->remove_full)
644     {
645         IPATCH_ITEM_CLASS(ipatch_sli_zone_parent_class)->remove_full(item, full);
646     }
647 }
648 
649 /**
650  * ipatch_sli_zone_new:
651  *
652  * Create a new Spectralis instrument zone object.
653  *
654  * Returns: New Spectralis instrument zone with a reference count of 1. Caller
655  * owns the reference and removing it will destroy the item, unless another
656  * reference is added (if its parented for example).
657  */
658 IpatchSLIZone *
ipatch_sli_zone_new(void)659 ipatch_sli_zone_new(void)
660 {
661     return (IPATCH_SLI_ZONE(g_object_new(IPATCH_TYPE_SLI_ZONE, NULL)));
662 }
663 
664 /**
665  * ipatch_sli_zone_first: (skip)
666  * @iter: Patch item iterator containing #IpatchSLIZone items
667  *
668  * Gets the first item in a zone iterator. A convenience
669  * wrapper for ipatch_iter_first().
670  *
671  * Returns: The first zone in @iter or %NULL if empty.
672  */
673 IpatchSLIZone *
ipatch_sli_zone_first(IpatchIter * iter)674 ipatch_sli_zone_first(IpatchIter *iter)
675 {
676     GObject *obj;
677     g_return_val_if_fail(iter != NULL, NULL);
678 
679     obj = ipatch_iter_first(iter);
680 
681     if(obj)
682     {
683         return (IPATCH_SLI_ZONE(obj));
684     }
685     else
686     {
687         return (NULL);
688     }
689 }
690 
691 /**
692  * ipatch_sli_zone_next: (skip)
693  * @iter: Patch item iterator containing #IpatchSLIZone items
694  *
695  * Gets the next item in a zone iterator. A convenience wrapper
696  * for ipatch_iter_next().
697  *
698  * Returns: The next zone in @iter or %NULL if at the end of
699  *   the list.
700  */
701 IpatchSLIZone *
ipatch_sli_zone_next(IpatchIter * iter)702 ipatch_sli_zone_next(IpatchIter *iter)
703 {
704     GObject *obj;
705     g_return_val_if_fail(iter != NULL, NULL);
706 
707     obj = ipatch_iter_next(iter);
708 
709     if(obj)
710     {
711         return (IPATCH_SLI_ZONE(obj));
712     }
713     else
714     {
715         return (NULL);
716     }
717 }
718 
719 /**
720  * ipatch_sli_zone_set_sample:
721  * @zone: Zone to set sample of
722  * @sample: Sample to set zone to
723  *
724  * Sets the referenced sample of a zone.
725  */
726 void
ipatch_sli_zone_set_sample(IpatchSLIZone * zone,IpatchSLISample * sample)727 ipatch_sli_zone_set_sample(IpatchSLIZone *zone, IpatchSLISample *sample)
728 {
729     g_return_if_fail(IPATCH_IS_SLI_ZONE(zone));
730     g_return_if_fail(IPATCH_IS_SLI_SAMPLE(sample));
731 
732     ipatch_sli_zone_real_set_sample(zone, sample, TRUE);
733 }
734 
735 static void
ipatch_sli_zone_real_set_sample(IpatchSLIZone * zone,IpatchSLISample * sample,gboolean sample_notify)736 ipatch_sli_zone_real_set_sample(IpatchSLIZone *zone, IpatchSLISample *sample,
737                                 gboolean sample_notify)
738 {
739     GValue oldval = { 0 }, newval = { 0 };
740     IpatchSLISample *oldsample;
741 
742     if(sample_notify)
743         ipatch_item_get_property_fast((IpatchItem *)zone, link_item_pspec,
744                                       &oldval);
745 
746     if(sample)
747     {
748         g_object_ref(sample);    /* ref for zone */
749     }
750 
751     IPATCH_ITEM_WLOCK(zone);
752     oldsample = zone->sample;
753     zone->sample = sample;
754     IPATCH_ITEM_WUNLOCK(zone);
755 
756     if(oldsample)
757     {
758         g_object_unref(oldsample);
759     }
760 
761     if(sample_notify)
762     {
763         g_value_init(&newval, IPATCH_TYPE_SLI_SAMPLE);
764         g_value_set_object(&newval, sample);
765         ipatch_item_prop_notify((IpatchItem *)zone, link_item_pspec,
766                                 &newval, &oldval);
767         g_value_unset(&oldval);
768         g_value_unset(&newval);
769     }
770 
771     /* notify title property change */
772     g_value_init(&newval, G_TYPE_STRING);
773     ipatch_sli_zone_get_title(zone, &newval);
774     ipatch_item_prop_notify((IpatchItem *)zone, ipatch_item_pspec_title,
775                             &newval, NULL);
776     g_value_unset(&newval);
777 }
778 
779 /**
780  * ipatch_sli_zone_get_sample:
781  * @zone: Zone to get referenced sample from
782  *
783  * Gets the referenced sample from a zone.
784  * The returned item's reference count is incremented and the caller
785  * is responsible for unrefing it with g_object_unref() when
786  * done with it.
787  *
788  * Returns: (transfer full): Zone's referenced sample or %NULL if global zone. Remember to
789  * unreference the item with g_object_unref() when done with it.
790  */
791 IpatchSLISample *
ipatch_sli_zone_get_sample(IpatchSLIZone * zone)792 ipatch_sli_zone_get_sample(IpatchSLIZone *zone)
793 {
794     IpatchSLISample *sample;
795 
796     g_return_val_if_fail(IPATCH_IS_SLI_ZONE(zone), NULL);
797 
798     IPATCH_ITEM_RLOCK(zone);
799     sample = zone->sample;
800 
801     if(sample)
802     {
803         g_object_ref(sample);
804     }
805 
806     IPATCH_ITEM_RUNLOCK(zone);
807 
808     return sample;
809 }
810 
811 /**
812  * ipatch_sli_zone_peek_sample: (skip)
813  * @zone: Zone to get referenced item of
814  *
815  * Like ipatch_sli_zone_get_sample() but does not add a reference to
816  * the returned sample. This function should only be used if a reference
817  * of the returned sample is ensured or only the pointer value is of
818  * interest.
819  *
820  * Returns: Zone's linked sample.
821  * Remember that the item has NOT been referenced.
822  */
823 IpatchSLISample *
ipatch_sli_zone_peek_sample(IpatchSLIZone * zone)824 ipatch_sli_zone_peek_sample(IpatchSLIZone *zone)
825 {
826     g_return_val_if_fail(IPATCH_IS_SLI_ZONE(zone), NULL);
827     return (zone->sample);	/* atomic read */
828 }
829