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