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: IpatchDLS2Inst
22  * @short_description: DLS instrument object
23  * @see_also:
24  * @stability: Stable
25  *
26  * Defines a DLS instrument object.  DLS instruments are the toplevel objects
27  * in the DLS instrument file tree hierarchy.
28  */
29 #include <stdarg.h>
30 #include <glib.h>
31 #include <glib-object.h>
32 #include "IpatchDLS2Inst.h"
33 #include "IpatchDLS2Conn.h"
34 #include "IpatchDLS2Region.h"
35 #include "IpatchDLSFile.h"
36 #include "IpatchDLSFile_priv.h"
37 #include "IpatchParamProp.h"
38 #include "IpatchTypeProp.h"
39 #include "ipatch_priv.h"
40 
41 enum
42 {
43     PROP_0,
44     PROP_TITLE,
45     PROP_BANK,
46     PROP_PROGRAM,
47     PROP_PERCUSSION
48 };
49 
50 static void ipatch_dls2_inst_class_init(IpatchDLS2InstClass *klass);
51 static void ipatch_dls2_inst_finalize(GObject *gobject);
52 static void get_title(IpatchDLS2Inst *inst, GValue *value);
53 static void ipatch_dls2_inst_set_property(GObject *object,
54         guint property_id,
55         const GValue *value,
56         GParamSpec *pspec);
57 static void ipatch_dls2_inst_get_property(GObject *object,
58         guint property_id,
59         GValue *value,
60         GParamSpec *pspec);
61 static void ipatch_dls2_inst_item_copy(IpatchItem *dest, IpatchItem *src,
62                                        IpatchItemCopyLinkFunc link_func,
63                                        gpointer user_data);
64 
65 static const GType *ipatch_dls2_inst_container_child_types(void);
66 static gboolean
67 ipatch_dls2_inst_container_init_iter(IpatchContainer *container,
68                                      IpatchIter *iter, GType type);
69 
70 static gpointer parent_class = NULL;
71 static GType inst_child_types[2] = { 0 };
72 
73 
74 GType
ipatch_dls2_inst_get_type(void)75 ipatch_dls2_inst_get_type(void)
76 {
77     static GType item_type = 0;
78 
79     if(!item_type)
80     {
81         static const GTypeInfo item_info =
82         {
83             sizeof(IpatchDLS2InstClass), NULL, NULL,
84             (GClassInitFunc)ipatch_dls2_inst_class_init, NULL, NULL,
85             sizeof(IpatchDLS2Inst), 0,
86             (GInstanceInitFunc) NULL,
87         };
88 
89         item_type = g_type_register_static(IPATCH_TYPE_CONTAINER,
90                                            "IpatchDLS2Inst", &item_info, 0);
91     }
92 
93     return (item_type);
94 }
95 
96 static void
ipatch_dls2_inst_class_init(IpatchDLS2InstClass * klass)97 ipatch_dls2_inst_class_init(IpatchDLS2InstClass *klass)
98 {
99     GObjectClass *obj_class = G_OBJECT_CLASS(klass);
100     IpatchItemClass *item_class = IPATCH_ITEM_CLASS(klass);
101     IpatchContainerClass *container_class = IPATCH_CONTAINER_CLASS(klass);
102     GParamSpec *pspec;
103 
104     parent_class = g_type_class_peek_parent(klass);
105 
106     obj_class->finalize = ipatch_dls2_inst_finalize;
107     obj_class->get_property = ipatch_dls2_inst_get_property;
108 
109     /* we use the IpatchItem item_set_property method */
110     item_class->item_set_property = ipatch_dls2_inst_set_property;
111     item_class->copy = ipatch_dls2_inst_item_copy;
112 
113     container_class->child_types = ipatch_dls2_inst_container_child_types;
114     container_class->init_iter = ipatch_dls2_inst_container_init_iter;
115 
116     g_object_class_override_property(obj_class, PROP_TITLE, "title");
117 
118     /* bank and program numbers are flagged as UNIQUE properties and are
119        grouped together (i.e., siblings with same bank/preset are considered
120        conflicting) */
121 
122     pspec = g_param_spec_int("bank", _("Bank"),
123                              _("MIDI bank number"),
124                              0, IPATCH_DLS2_INST_BANK_MAX, 0,
125                              G_PARAM_READWRITE | IPATCH_PARAM_UNIQUE);
126     ipatch_param_set(pspec, "unique-group-id", 1, NULL);
127     g_object_class_install_property(obj_class, PROP_BANK, pspec);
128 
129     pspec = g_param_spec_int("program", _("Program"),
130                              _("MIDI program number"),
131                              0, 127, 0,
132                              G_PARAM_READWRITE | IPATCH_PARAM_UNIQUE);
133     ipatch_param_set(pspec, "unique-group-id", 1, NULL);
134     g_object_class_install_property(obj_class, PROP_PROGRAM, pspec);
135 
136     g_object_class_install_property(obj_class, PROP_PERCUSSION,
137                                     g_param_spec_boolean("percussion", _("Percussion"),
138                                             _("Percussion instrument?"), FALSE,
139                                             G_PARAM_READWRITE));
140 
141     ipatch_dls2_info_install_class_properties(obj_class);
142 
143     inst_child_types[0] = IPATCH_TYPE_DLS2_REGION;
144 }
145 
146 static void
ipatch_dls2_inst_finalize(GObject * gobject)147 ipatch_dls2_inst_finalize(GObject *gobject)
148 {
149     IpatchDLS2Inst *inst = IPATCH_DLS2_INST(gobject);
150     GSList *p;
151 
152     IPATCH_ITEM_WLOCK(inst);
153 
154     ipatch_dls2_info_free(inst->info);
155     inst->info = NULL;
156 
157     p = inst->conns;
158 
159     while(p)
160     {
161         ipatch_dls2_conn_free((IpatchDLS2Conn *)(p->data));
162         p = g_slist_delete_link(p, p);
163     }
164 
165     inst->conns = NULL;
166 
167     g_free(inst->dlid);
168     inst->dlid = NULL;
169 
170     IPATCH_ITEM_WUNLOCK(inst);
171 
172     if(G_OBJECT_CLASS(parent_class)->finalize)
173     {
174         G_OBJECT_CLASS(parent_class)->finalize(gobject);
175     }
176 }
177 
178 static void
get_title(IpatchDLS2Inst * inst,GValue * value)179 get_title(IpatchDLS2Inst *inst, GValue *value)
180 {
181     char *name;
182     char *s;
183 
184     g_object_get(inst, "name", &name, NULL);
185 
186     if(name)
187     {
188         s = g_strdup_printf("%05d-%03d %s", inst->bank, inst->program, name);
189         g_free(name);
190     }
191     else
192         s = g_strdup_printf("%05d-%03d %s", inst->bank, inst->program,
193                             IPATCH_UNTITLED);
194 
195     g_value_take_string(value, s);
196 }
197 
198 static void
ipatch_dls2_inst_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)199 ipatch_dls2_inst_set_property(GObject *object, guint property_id,
200                               const GValue *value, GParamSpec *pspec)
201 {
202     IpatchDLS2Inst *inst = IPATCH_DLS2_INST(object);
203     gboolean retval;
204 
205     switch(property_id)
206     {
207     case PROP_BANK:
208         IPATCH_ITEM_WLOCK(inst);	/* locked to ensure bank/program atomicity */
209         inst->bank = g_value_get_int(value);
210         IPATCH_ITEM_WUNLOCK(inst);
211         break;
212 
213     case PROP_PROGRAM:
214         IPATCH_ITEM_WLOCK(inst);	/* locked to ensure bank/program atomicity */
215         inst->program = g_value_get_int(value);
216         IPATCH_ITEM_WUNLOCK(inst);
217         break;
218 
219     case PROP_PERCUSSION:
220         if(g_value_get_boolean(value))
221         {
222             ipatch_item_set_flags((IpatchItem *)inst, IPATCH_DLS2_INST_PERCUSSION);
223         }
224         else
225         {
226             ipatch_item_clear_flags((IpatchItem *)inst, IPATCH_DLS2_INST_PERCUSSION);
227         }
228 
229         break;
230 
231     default:
232         IPATCH_ITEM_WLOCK(inst);
233         retval = ipatch_dls2_info_set_property(&inst->info, property_id, value);
234         IPATCH_ITEM_WUNLOCK(inst);
235 
236         if(!retval)
237         {
238             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
239             return;
240         }
241 
242         break;
243     }
244 
245     /* does title property need to be notified? */
246     if(property_id == PROP_BANK || property_id == PROP_PROGRAM
247             || property_id == IPATCH_DLS2_NAME)
248     {
249         GValue newval = { 0 };
250 
251         g_value_init(&newval, G_TYPE_STRING);
252         get_title(inst, &newval);
253         ipatch_item_prop_notify((IpatchItem *)inst, ipatch_item_pspec_title,
254                                 &newval, NULL);
255         g_value_unset(&newval);
256     }
257 }
258 
259 static void
ipatch_dls2_inst_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)260 ipatch_dls2_inst_get_property(GObject *object, guint property_id,
261                               GValue *value, GParamSpec *pspec)
262 {
263     IpatchDLS2Inst *inst = IPATCH_DLS2_INST(object);
264     gboolean retval;
265 
266     switch(property_id)
267     {
268     case PROP_TITLE:
269         get_title(inst, value);
270         break;
271 
272     case PROP_BANK:
273         g_value_set_int(value, inst->bank);
274         break;
275 
276     case PROP_PROGRAM:
277         g_value_set_int(value, inst->program);
278         break;
279 
280     case PROP_PERCUSSION:
281         g_value_set_boolean(value, (ipatch_item_get_flags((IpatchItem *)inst)
282                                     & IPATCH_DLS2_INST_PERCUSSION) != 0);
283         break;
284 
285     default:
286         IPATCH_ITEM_RLOCK(inst);
287         retval = ipatch_dls2_info_get_property(inst->info, property_id, value);
288         IPATCH_ITEM_RUNLOCK(inst);
289 
290         if(!retval)
291         {
292             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
293         }
294 
295         break;
296     }
297 }
298 
299 static void
ipatch_dls2_inst_item_copy(IpatchItem * dest,IpatchItem * src,IpatchItemCopyLinkFunc link_func,gpointer user_data)300 ipatch_dls2_inst_item_copy(IpatchItem *dest, IpatchItem *src,
301                            IpatchItemCopyLinkFunc link_func,
302                            gpointer user_data)
303 {
304     IpatchDLS2Inst *src_inst, *dest_inst;
305     IpatchItem *ritem;
306     GSList *p;
307 
308     src_inst = IPATCH_DLS2_INST(src);
309     dest_inst = IPATCH_DLS2_INST(dest);
310 
311     IPATCH_ITEM_RLOCK(src_inst);
312 
313     /* set the percussion flag if set in src */
314     if(ipatch_item_get_flags(src_inst) & IPATCH_DLS2_INST_PERCUSSION)
315     {
316         ipatch_item_set_flags(dest_inst, IPATCH_DLS2_INST_PERCUSSION);
317     }
318 
319     dest_inst->bank = src_inst->bank;
320     dest_inst->program = src_inst->program;
321 
322     dest_inst->info = ipatch_dls2_info_duplicate(src_inst->info);
323 
324     if(src_inst->dlid)
325     {
326         dest_inst->dlid = g_memdup(src_inst->dlid, IPATCH_DLS_DLID_SIZE);
327     }
328 
329     p = src_inst->regions;
330 
331     while(p)			/* duplicate regions */
332     {
333         /* ++ ref new duplicate item */
334         ritem = ipatch_item_duplicate_link_func(IPATCH_ITEM(p->data), link_func,
335                                                 user_data);
336         g_return_if_fail(ritem != NULL);
337 
338         /* !! take over duplicate item reference */
339         dest_inst->regions = g_slist_prepend(dest_inst->regions, ritem);
340         ipatch_item_set_parent(ritem, IPATCH_ITEM(dest_inst));
341 
342         p = g_slist_next(p);
343     }
344 
345     dest_inst->conns = ipatch_dls2_conn_list_duplicate(src_inst->conns);
346 
347     IPATCH_ITEM_RUNLOCK(src_inst);
348 
349     dest_inst->regions = g_slist_reverse(dest_inst->regions);
350 }
351 
352 static const GType *
ipatch_dls2_inst_container_child_types(void)353 ipatch_dls2_inst_container_child_types(void)
354 {
355     return (inst_child_types);
356 }
357 
358 /* container is locked by caller */
359 static gboolean
ipatch_dls2_inst_container_init_iter(IpatchContainer * container,IpatchIter * iter,GType type)360 ipatch_dls2_inst_container_init_iter(IpatchContainer *container,
361                                      IpatchIter *iter, GType type)
362 {
363     IpatchDLS2Inst *inst = IPATCH_DLS2_INST(container);
364 
365     if(!g_type_is_a(type, IPATCH_TYPE_DLS2_REGION))
366     {
367         g_critical("Invalid child type '%s' for parent of type '%s'",
368                    g_type_name(type), g_type_name(G_OBJECT_TYPE(container)));
369         return (FALSE);
370     }
371 
372     ipatch_iter_GSList_init(iter, &inst->regions);
373     return (TRUE);
374 }
375 
376 /**
377  * ipatch_dls2_inst_new:
378  *
379  * Create a new DLS instrument object.
380  *
381  * Returns: New DLS instrument with a reference count of 1. Caller
382  * owns the reference and removing it will destroy the item, unless another
383  * reference is added (if its parented for example).
384  */
385 IpatchDLS2Inst *
ipatch_dls2_inst_new(void)386 ipatch_dls2_inst_new(void)
387 {
388     return (IPATCH_DLS2_INST(g_object_new(IPATCH_TYPE_DLS2_INST, NULL)));
389 }
390 
391 /**
392  * ipatch_dls2_inst_first: (skip)
393  * @iter: Patch item iterator containing #IpatchDLS2Inst items
394  *
395  * Gets the first item in an instrument iterator. A convenience wrapper for
396  * ipatch_iter_first().
397  *
398  * Returns: The first instrument in @iter or %NULL if empty.
399  */
400 IpatchDLS2Inst *
ipatch_dls2_inst_first(IpatchIter * iter)401 ipatch_dls2_inst_first(IpatchIter *iter)
402 {
403     GObject *obj;
404     g_return_val_if_fail(iter != NULL, NULL);
405 
406     obj = ipatch_iter_first(iter);
407 
408     if(obj)
409     {
410         return (IPATCH_DLS2_INST(obj));
411     }
412     else
413     {
414         return (NULL);
415     }
416 }
417 
418 /**
419  * ipatch_dls2_inst_next: (skip)
420  * @iter: Patch item iterator containing #IpatchDLS2Inst items
421  *
422  * Gets the next item in an instrument iterator. A convenience wrapper for
423  * ipatch_iter_next().
424  *
425  * Returns: The next instrument in @iter or %NULL if at the end of the list.
426  */
427 IpatchDLS2Inst *
ipatch_dls2_inst_next(IpatchIter * iter)428 ipatch_dls2_inst_next(IpatchIter *iter)
429 {
430     GObject *obj;
431     g_return_val_if_fail(iter != NULL, NULL);
432 
433     obj = ipatch_iter_next(iter);
434 
435     if(obj)
436     {
437         return (IPATCH_DLS2_INST(obj));
438     }
439     else
440     {
441         return (NULL);
442     }
443 }
444 
445 /**
446  * ipatch_dls2_inst_get_info:
447  * @inst: DLS instrument to get info from
448  * @fourcc: FOURCC integer id of INFO to get
449  *
450  * Get a DLS instrument info string by FOURCC integer ID (integer
451  * representation of a 4 character RIFF chunk ID, see
452  * #IpatchRiff).
453  *
454  * Returns: (transfer full): New allocated info string value or %NULL if no info with the
455  * given @fourcc ID. String should be freed when finished with it.
456  */
457 char *
ipatch_dls2_inst_get_info(IpatchDLS2Inst * inst,guint32 fourcc)458 ipatch_dls2_inst_get_info(IpatchDLS2Inst *inst, guint32 fourcc)
459 {
460     char *val;
461 
462     g_return_val_if_fail(IPATCH_IS_DLS2_INST(inst), NULL);
463 
464     IPATCH_ITEM_RLOCK(inst);
465     val = ipatch_dls2_info_get(inst->info, fourcc);
466     IPATCH_ITEM_RUNLOCK(inst);
467 
468     return (val);
469 }
470 
471 /**
472  * ipatch_dls2_inst_set_info:
473  * @inst: DLS instrument to set info of
474  * @fourcc: FOURCC integer ID of INFO to set
475  * @val: (nullable): Value to set info to or %NULL to unset (clear) info.
476  *
477  * Sets an INFO value in a DLS instrument object.
478  * Emits changed signal.
479  */
480 void
ipatch_dls2_inst_set_info(IpatchDLS2Inst * inst,guint32 fourcc,const char * val)481 ipatch_dls2_inst_set_info(IpatchDLS2Inst *inst, guint32 fourcc,
482                           const char *val)
483 {
484     GValue newval = { 0 }, oldval = { 0 };
485 
486     g_return_if_fail(IPATCH_IS_DLS2_INST(inst));
487 
488     g_value_init(&newval, G_TYPE_STRING);
489     g_value_set_static_string(&newval, val);
490 
491     g_value_init(&oldval, G_TYPE_STRING);
492     g_value_take_string(&oldval, ipatch_dls2_inst_get_info(inst, fourcc));
493 
494     IPATCH_ITEM_WLOCK(inst);
495     ipatch_dls2_info_set(&inst->info, fourcc, val);
496     IPATCH_ITEM_WUNLOCK(inst);
497 
498     ipatch_dls2_info_notify((IpatchItem *)inst, fourcc, &newval, &oldval);
499 
500     /* does title property need to be notified? */
501     if(fourcc == IPATCH_DLS2_NAME)
502         ipatch_item_prop_notify((IpatchItem *)inst, ipatch_item_pspec_title,
503                                 &newval, &oldval);
504 
505     g_value_unset(&oldval);
506     g_value_unset(&newval);
507 }
508 
509 /**
510  * ipatch_dls2_inst_set_midi_locale:
511  * @inst: DLS instrument to set MIDI locale of
512  * @bank: MIDI bank number to assign to instrument
513  * @program: MIDI program number to assign to instrument
514  *
515  * Sets the MIDI locale of a DLS instrument (bank and program numbers).
516  */
517 void
ipatch_dls2_inst_set_midi_locale(IpatchDLS2Inst * inst,int bank,int program)518 ipatch_dls2_inst_set_midi_locale(IpatchDLS2Inst *inst, int bank, int program)
519 {
520     g_object_set(inst, "bank", bank, "program", program, NULL);
521 }
522 
523 /**
524  * ipatch_dls2_inst_get_midi_locale:
525  * @inst: Instrument to get MIDI locale from
526  * @bank: (out) (optional): Location to store instrument's MIDI bank number or %NULL
527  * @program: (out) (optional): Location to store instrument's MIDI program number or %NULL
528  *
529  * Gets the MIDI locale of a DLS instrument (bank and program numbers).
530  */
531 void
ipatch_dls2_inst_get_midi_locale(IpatchDLS2Inst * inst,int * bank,int * program)532 ipatch_dls2_inst_get_midi_locale(IpatchDLS2Inst *inst,
533                                  int *bank, int *program)
534 {
535     g_return_if_fail(IPATCH_IS_DLS2_INST(inst));
536 
537     IPATCH_ITEM_RLOCK(inst);
538 
539     if(bank)
540     {
541         *bank = inst->bank;
542     }
543 
544     if(program)
545     {
546         *program = inst->program;
547     }
548 
549     IPATCH_ITEM_RUNLOCK(inst);
550 }
551 
552 /**
553  * ipatch_dls2_inst_compare:
554  * @p1: First instrument in comparison
555  * @p2: Second instrument in comparison
556  *
557  * Instrument comparison function for sorting. Compare two instruments by their
558  * MIDI bank:program numbers. Note that this function is compatible with
559  * GCompareFunc and can therefore be used with g_list_sort, etc.
560  *
561  * FIXME: Also note that percussion instruments are sorted after regular ones.
562  *
563  * Returns: Comparison result that is less than, equal to, or greater than zero
564  * if @p1 is found, respectively, to be less than, to match, or be greater
565  * than @p2.
566  */
567 int
ipatch_dls2_inst_compare(const IpatchDLS2Inst * p1,const IpatchDLS2Inst * p2)568 ipatch_dls2_inst_compare(const IpatchDLS2Inst *p1,
569                          const IpatchDLS2Inst *p2)
570 {
571     gint32 aval, bval;
572     guint32 aperc, bperc;
573 
574     aperc = (ipatch_item_get_flags((IpatchItem *)p1)
575              & IPATCH_DLS2_INST_PERCUSSION) ? 1 << 31 : 0;
576     bperc = (ipatch_item_get_flags((IpatchItem *)p2)
577              & IPATCH_DLS2_INST_PERCUSSION) ? 1 << 31 : 0;
578 
579     aval = aperc | ((gint32)(p1->bank) << 16) | p1->program;
580     bval = bperc | ((gint32)(p2->bank) << 16) | p2->program;
581 
582     return (aval - bval);
583 }
584 
585 /**
586  * ipatch_dls2_inst_get_conns:
587  * @inst: Instrument to get connections from
588  *
589  * Gets a list of connections from a DLS instrument. List should be freed with
590  * ipatch_dls2_conn_list_free() (free_conns set to %TRUE) when finished
591  * with it.
592  *
593  * Returns: (element-type IpatchDLS2Conn) (transfer full): New list of connections
594  *   (#IpatchDLS2Conn) in @inst or %NULL if no connections. Remember to free it
595  *   when finished.
596  */
597 GSList *
ipatch_dls2_inst_get_conns(IpatchDLS2Inst * inst)598 ipatch_dls2_inst_get_conns(IpatchDLS2Inst *inst)
599 {
600     GSList *newlist;
601 
602     g_return_val_if_fail(IPATCH_IS_DLS2_INST(inst), NULL);
603 
604     IPATCH_ITEM_RLOCK(inst);
605     newlist = ipatch_dls2_conn_list_duplicate(inst->conns);
606     IPATCH_ITEM_RUNLOCK(inst);
607 
608     return (newlist);
609 }
610 
611 /**
612  * ipatch_dls2_inst_set_conn:
613  * @inst: DLS instrument
614  * @conn: Connection
615  *
616  * Set a global DLS connection in an instrument. See
617  * ipatch_dls2_conn_list_set() for more details.
618  */
619 void
ipatch_dls2_inst_set_conn(IpatchDLS2Inst * inst,const IpatchDLS2Conn * conn)620 ipatch_dls2_inst_set_conn(IpatchDLS2Inst *inst, const IpatchDLS2Conn *conn)
621 {
622     g_return_if_fail(IPATCH_IS_DLS2_INST(inst));
623     g_return_if_fail(conn != NULL);
624 
625     IPATCH_ITEM_WLOCK(inst);
626     ipatch_dls2_conn_list_set(&inst->conns, conn);
627     IPATCH_ITEM_WUNLOCK(inst);
628 }
629 
630 /**
631  * ipatch_dls2_inst_unset_conn:
632  * @inst: DLS instrument
633  * @conn: Connection
634  *
635  * Remove a global DLS connection from an instrument. See
636  * ipatch_dls2_conn_list_unset() for more details.
637  */
638 void
ipatch_dls2_inst_unset_conn(IpatchDLS2Inst * inst,const IpatchDLS2Conn * conn)639 ipatch_dls2_inst_unset_conn(IpatchDLS2Inst *inst, const IpatchDLS2Conn *conn)
640 {
641     g_return_if_fail(IPATCH_IS_DLS2_INST(inst));
642     g_return_if_fail(conn != NULL);
643 
644     IPATCH_ITEM_WLOCK(inst);
645     ipatch_dls2_conn_list_unset(&inst->conns, conn);
646     IPATCH_ITEM_WUNLOCK(inst);
647 }
648 
649 /**
650  * ipatch_dls2_inst_unset_all_conns:
651  * @inst: DLS instrument
652  *
653  * Remove all global connections in an instrument.
654  */
655 void
ipatch_dls2_inst_unset_all_conns(IpatchDLS2Inst * inst)656 ipatch_dls2_inst_unset_all_conns(IpatchDLS2Inst *inst)
657 {
658     g_return_if_fail(IPATCH_IS_DLS2_INST(inst));
659 
660     IPATCH_ITEM_WLOCK(inst);
661     ipatch_dls2_conn_list_free(inst->conns, TRUE);
662     inst->conns = NULL;
663     IPATCH_ITEM_WUNLOCK(inst);
664 }
665 
666 /**
667  * ipatch_dls2_inst_conn_count:
668  * @inst: Instrument to count connections in
669  *
670  * Count number of connections in a instrument
671  *
672  * Returns: Count of connections
673  */
674 guint
ipatch_dls2_inst_conn_count(IpatchDLS2Inst * inst)675 ipatch_dls2_inst_conn_count(IpatchDLS2Inst *inst)
676 {
677     guint i;
678 
679     IPATCH_ITEM_RLOCK(inst);
680     i = g_slist_length(inst->conns);
681     IPATCH_ITEM_RUNLOCK(inst);
682 
683     return (i);
684 }
685