1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2020 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/audio/file/ags_sfz_region.h>
21
22 #include <ags/audio/file/ags_sfz_group.h>
23 #include <ags/audio/file/ags_sfz_sample.h>
24
25 #include <stdlib.h>
26
27 #include <ags/i18n.h>
28
29 void ags_sfz_region_class_init(AgsSFZRegionClass *sfz_region);
30 void ags_sfz_region_connectable_interface_init(AgsConnectableInterface *connectable);
31 void ags_sfz_region_init(AgsSFZRegion *sfz_region);
32 void ags_sfz_region_set_property(GObject *gobject,
33 guint prop_id,
34 const GValue *value,
35 GParamSpec *param_spec);
36 void ags_sfz_region_get_property(GObject *gobject,
37 guint prop_id,
38 GValue *value,
39 GParamSpec *param_spec);
40 void ags_sfz_region_dispose(GObject *gobject);
41 void ags_sfz_region_finalize(GObject *gobject);
42
43 AgsUUID* ags_sfz_region_get_uuid(AgsConnectable *connectable);
44 gboolean ags_sfz_region_has_resource(AgsConnectable *connectable);
45 gboolean ags_sfz_region_is_ready(AgsConnectable *connectable);
46 void ags_sfz_region_add_to_registry(AgsConnectable *connectable);
47 void ags_sfz_region_remove_from_registry(AgsConnectable *connectable);
48 xmlNode* ags_sfz_region_list_resource(AgsConnectable *connectable);
49 xmlNode* ags_sfz_region_xml_compose(AgsConnectable *connectable);
50 void ags_sfz_region_xml_parse(AgsConnectable *connectable,
51 xmlNode *node);
52 gboolean ags_sfz_region_is_connected(AgsConnectable *connectable);
53 void ags_sfz_region_connect(AgsConnectable *connectable);
54 void ags_sfz_region_disconnect(AgsConnectable *connectable);
55
56 /**
57 * SECTION:ags_sfz_region
58 * @short_description: interfacing SFZ regions
59 * @title: AgsSFZRegion
60 * @section_id:
61 * @include: ags/audio/file/ags_sfz_region.h
62 *
63 * #AgsSFZRegion is the base object to ineract with SFZ regions.
64 */
65
66 enum{
67 PROP_0,
68 PROP_NTH_REGION,
69 PROP_GROUP,
70 PROP_SAMPLE,
71 };
72
73 static gpointer ags_sfz_region_parent_class = NULL;
74
75 GType
ags_sfz_region_get_type()76 ags_sfz_region_get_type()
77 {
78 static volatile gsize g_define_type_id__volatile = 0;
79
80 if(g_once_init_enter (&g_define_type_id__volatile)){
81 GType ags_type_sfz_region = 0;
82
83 static const GTypeInfo ags_sfz_region_info = {
84 sizeof(AgsSFZRegionClass),
85 NULL, /* base_init */
86 NULL, /* base_finalize */
87 (GClassInitFunc) ags_sfz_region_class_init,
88 NULL, /* class_finalize */
89 NULL, /* class_data */
90 sizeof(AgsSFZRegion),
91 0, /* n_preallocs */
92 (GInstanceInitFunc) ags_sfz_region_init,
93 };
94
95 static const GInterfaceInfo ags_connectable_interface_info = {
96 (GInterfaceInitFunc) ags_sfz_region_connectable_interface_init,
97 NULL, /* interface_finalize */
98 NULL, /* interface_data */
99 };
100
101 ags_type_sfz_region = g_type_register_static(G_TYPE_OBJECT,
102 "AgsSFZRegion",
103 &ags_sfz_region_info,
104 0);
105
106 g_type_add_interface_static(ags_type_sfz_region,
107 AGS_TYPE_CONNECTABLE,
108 &ags_connectable_interface_info);
109
110 g_once_init_leave(&g_define_type_id__volatile, ags_type_sfz_region);
111 }
112
113 return g_define_type_id__volatile;
114 }
115
116 void
ags_sfz_region_class_init(AgsSFZRegionClass * sfz_region)117 ags_sfz_region_class_init(AgsSFZRegionClass *sfz_region)
118 {
119 GObjectClass *gobject;
120
121 GParamSpec *param_spec;
122
123 ags_sfz_region_parent_class = g_type_class_peek_parent(sfz_region);
124
125 gobject = (GObjectClass *) sfz_region;
126
127 gobject->set_property = ags_sfz_region_set_property;
128 gobject->get_property = ags_sfz_region_get_property;
129
130 gobject->dispose = ags_sfz_region_dispose;
131 gobject->finalize = ags_sfz_region_finalize;
132
133 /* properties */
134 /**
135 * AgsSFZRegion:nth-region:
136 *
137 * The nth region.
138 *
139 * Since: 3.0.0
140 */
141 param_spec = g_param_spec_int("nth-region",
142 i18n_pspec("nth region"),
143 i18n_pspec("The nth region it belongs to"),
144 -1,
145 G_MAXINT32,
146 -1,
147 G_PARAM_READABLE | G_PARAM_WRITABLE);
148 g_object_class_install_property(gobject,
149 PROP_NTH_REGION,
150 param_spec);
151
152 /**
153 * AgsSFZRegion:group:
154 *
155 * The group assigned with.
156 *
157 * Since: 3.0.0
158 */
159 param_spec = g_param_spec_object("group",
160 i18n_pspec("assigned group"),
161 i18n_pspec("The group it is assigned with"),
162 AGS_TYPE_SFZ_GROUP,
163 G_PARAM_READABLE | G_PARAM_WRITABLE);
164 g_object_class_install_property(gobject,
165 PROP_GROUP,
166 param_spec);
167
168 /**
169 * AgsSFZRegion:sample:
170 *
171 * The sample assigned with.
172 *
173 * Since: 3.0.0
174 */
175 param_spec = g_param_spec_object("sample",
176 i18n_pspec("assigned sample"),
177 i18n_pspec("The sample it is assigned with"),
178 AGS_TYPE_SFZ_SAMPLE,
179 G_PARAM_READABLE | G_PARAM_WRITABLE);
180 g_object_class_install_property(gobject,
181 PROP_SAMPLE,
182 param_spec);
183 }
184
185 void
ags_sfz_region_connectable_interface_init(AgsConnectableInterface * connectable)186 ags_sfz_region_connectable_interface_init(AgsConnectableInterface *connectable)
187 {
188 connectable->get_uuid = ags_sfz_region_get_uuid;
189 connectable->has_resource = ags_sfz_region_has_resource;
190 connectable->is_ready = ags_sfz_region_is_ready;
191
192 connectable->add_to_registry = ags_sfz_region_add_to_registry;
193 connectable->remove_from_registry = ags_sfz_region_remove_from_registry;
194
195 connectable->list_resource = ags_sfz_region_list_resource;
196 connectable->xml_compose = ags_sfz_region_xml_compose;
197 connectable->xml_parse = ags_sfz_region_xml_parse;
198
199 connectable->is_connected = ags_sfz_region_is_connected;
200
201 connectable->connect = ags_sfz_region_connect;
202 connectable->disconnect = ags_sfz_region_disconnect;
203
204 connectable->connect_connection = NULL;
205 connectable->disconnect_connection = NULL;
206 }
207
208 void
ags_sfz_region_init(AgsSFZRegion * sfz_region)209 ags_sfz_region_init(AgsSFZRegion *sfz_region)
210 {
211 AgsConfig *config;
212
213 sfz_region->flags = 0;
214
215 /* add audio file mutex */
216 g_rec_mutex_init(&(sfz_region->obj_mutex));
217
218 /* uuid */
219 sfz_region->uuid = ags_uuid_alloc();
220 ags_uuid_generate(sfz_region->uuid);
221
222 sfz_region->nth_region = -1;
223
224 sfz_region->group = NULL;
225 sfz_region->sample = NULL;
226
227 sfz_region->control = g_hash_table_new_full(g_str_hash, g_str_equal,
228 NULL,
229 NULL);
230 }
231
232 void
ags_sfz_region_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)233 ags_sfz_region_set_property(GObject *gobject,
234 guint prop_id,
235 const GValue *value,
236 GParamSpec *param_spec)
237 {
238 AgsSFZRegion *sfz_region;
239
240 GRecMutex *sfz_region_mutex;
241
242 sfz_region = AGS_SFZ_REGION(gobject);
243
244 /* get sfz region mutex */
245 sfz_region_mutex = AGS_SFZ_REGION_GET_OBJ_MUTEX(sfz_region);
246
247 switch(prop_id){
248 case PROP_NTH_REGION:
249 {
250 gint nth_region;
251
252 nth_region = g_value_get_int(value);
253
254 g_rec_mutex_lock(sfz_region_mutex);
255
256 if(nth_region == sfz_region->nth_region){
257 g_rec_mutex_unlock(sfz_region_mutex);
258
259 return;
260 }
261
262 sfz_region->nth_region = nth_region;
263
264 g_rec_mutex_unlock(sfz_region_mutex);
265 }
266 break;
267 case PROP_GROUP:
268 {
269 GObject *group;
270
271 group = g_value_get_object(value);
272
273 g_rec_mutex_lock(sfz_region_mutex);
274
275 if(sfz_region->group == group){
276 g_rec_mutex_unlock(sfz_region_mutex);
277
278 return;
279 }
280
281 if(sfz_region->group != NULL){
282 g_object_unref(sfz_region->group);
283 }
284
285 if(group != NULL){
286 g_object_ref(group);
287 }
288
289 sfz_region->group = group;
290
291 g_rec_mutex_unlock(sfz_region_mutex);
292 }
293 break;
294 case PROP_SAMPLE:
295 {
296 GObject *sample;
297
298 sample = g_value_get_object(value);
299
300 g_rec_mutex_lock(sfz_region_mutex);
301
302 if(sfz_region->sample == sample){
303 g_rec_mutex_unlock(sfz_region_mutex);
304
305 return;
306 }
307
308 if(sfz_region->sample != NULL){
309 g_object_unref(sfz_region->sample);
310 }
311
312 if(sample != NULL){
313 g_object_ref(sample);
314 }
315
316 sfz_region->sample = sample;
317
318 g_rec_mutex_unlock(sfz_region_mutex);
319 }
320 break;
321 default:
322 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
323 }
324 }
325
326 void
ags_sfz_region_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)327 ags_sfz_region_get_property(GObject *gobject,
328 guint prop_id,
329 GValue *value,
330 GParamSpec *param_spec)
331 {
332 AgsSFZRegion *sfz_region;
333
334 GRecMutex *sfz_region_mutex;
335
336 sfz_region = (AgsSFZRegion *) gobject;
337
338 /* get sfz region mutex */
339 sfz_region_mutex = AGS_SFZ_REGION_GET_OBJ_MUTEX(sfz_region);
340
341 switch(prop_id){
342 case PROP_NTH_REGION:
343 {
344 g_rec_mutex_lock(sfz_region_mutex);
345
346 g_value_set_int(value, sfz_region->nth_region);
347
348 g_rec_mutex_unlock(sfz_region_mutex);
349 }
350 break;
351 case PROP_GROUP:
352 {
353 g_rec_mutex_lock(sfz_region_mutex);
354
355 g_value_set_object(value, sfz_region->group);
356
357 g_rec_mutex_unlock(sfz_region_mutex);
358 }
359 break;
360 case PROP_SAMPLE:
361 {
362 g_rec_mutex_lock(sfz_region_mutex);
363
364 g_value_set_object(value, sfz_region->sample);
365
366 g_rec_mutex_unlock(sfz_region_mutex);
367 }
368 break;
369 default:
370 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
371 }
372 }
373
374 void
ags_sfz_region_dispose(GObject * gobject)375 ags_sfz_region_dispose(GObject *gobject)
376 {
377 AgsSFZRegion *sfz_region;
378
379 sfz_region = AGS_SFZ_REGION(gobject);
380
381 if(sfz_region->sample != NULL){
382 g_object_unref(sfz_region->sample);
383
384 sfz_region->sample = NULL;
385 }
386
387 if(sfz_region->group != NULL){
388 g_object_unref(sfz_region->group);
389
390 sfz_region->group = NULL;
391 }
392
393 /* call parent */
394 G_OBJECT_CLASS(ags_sfz_region_parent_class)->dispose(gobject);
395 }
396
397 void
ags_sfz_region_finalize(GObject * gobject)398 ags_sfz_region_finalize(GObject *gobject)
399 {
400 AgsSFZRegion *sfz_region;
401
402 sfz_region = AGS_SFZ_REGION(gobject);
403
404 if(sfz_region->sample != NULL){
405 g_object_unref(sfz_region->sample);
406 }
407
408 if(sfz_region->group != NULL){
409 g_object_unref(sfz_region->group);
410 }
411
412 /* call parent */
413 G_OBJECT_CLASS(ags_sfz_region_parent_class)->finalize(gobject);
414 }
415
416 AgsUUID*
ags_sfz_region_get_uuid(AgsConnectable * connectable)417 ags_sfz_region_get_uuid(AgsConnectable *connectable)
418 {
419 AgsSFZRegion *sfz_region;
420
421 AgsUUID *ptr;
422
423 GRecMutex *sfz_region_mutex;
424
425 sfz_region = AGS_SFZ_REGION(connectable);
426
427 /* get audio file mutex */
428 sfz_region_mutex = AGS_SFZ_REGION_GET_OBJ_MUTEX(sfz_region);
429
430 /* get UUID */
431 g_rec_mutex_lock(sfz_region_mutex);
432
433 ptr = sfz_region->uuid;
434
435 g_rec_mutex_unlock(sfz_region_mutex);
436
437 return(ptr);
438 }
439
440 gboolean
ags_sfz_region_has_resource(AgsConnectable * connectable)441 ags_sfz_region_has_resource(AgsConnectable *connectable)
442 {
443 return(TRUE);
444 }
445
446 gboolean
ags_sfz_region_is_ready(AgsConnectable * connectable)447 ags_sfz_region_is_ready(AgsConnectable *connectable)
448 {
449 AgsSFZRegion *sfz_region;
450
451 gboolean is_ready;
452
453 sfz_region = AGS_SFZ_REGION(connectable);
454
455 /* check is ready */
456 is_ready = ags_sfz_region_test_flags(sfz_region, AGS_SFZ_REGION_ADDED_TO_REGISTRY);
457
458 return(is_ready);
459 }
460
461 void
ags_sfz_region_add_to_registry(AgsConnectable * connectable)462 ags_sfz_region_add_to_registry(AgsConnectable *connectable)
463 {
464 AgsSFZRegion *sfz_region;
465
466 AgsRegistry *registry;
467 AgsRegistryEntry *entry;
468
469 AgsApplicationContext *application_context;
470
471 if(ags_connectable_is_ready(connectable)){
472 return;
473 }
474
475 sfz_region = AGS_SFZ_REGION(connectable);
476
477 ags_sfz_region_set_flags(sfz_region, AGS_SFZ_REGION_ADDED_TO_REGISTRY);
478
479 application_context = ags_application_context_get_instance();
480
481 registry = (AgsRegistry *) ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
482
483 if(registry != NULL){
484 entry = ags_registry_entry_alloc(registry);
485 g_value_set_object(entry->entry,
486 (gpointer) sfz_region);
487 ags_registry_add_entry(registry,
488 entry);
489 }
490 }
491
492 void
ags_sfz_region_remove_from_registry(AgsConnectable * connectable)493 ags_sfz_region_remove_from_registry(AgsConnectable *connectable)
494 {
495 if(!ags_connectable_is_ready(connectable)){
496 return;
497 }
498
499 //TODO:JK: implement me
500 }
501
502 xmlNode*
ags_sfz_region_list_resource(AgsConnectable * connectable)503 ags_sfz_region_list_resource(AgsConnectable *connectable)
504 {
505 xmlNode *node;
506
507 node = NULL;
508
509 //TODO:JK: implement me
510
511 return(node);
512 }
513
514 xmlNode*
ags_sfz_region_xml_compose(AgsConnectable * connectable)515 ags_sfz_region_xml_compose(AgsConnectable *connectable)
516 {
517 xmlNode *node;
518
519 node = NULL;
520
521 //TODO:JK: implement me
522
523 return(node);
524 }
525
526 void
ags_sfz_region_xml_parse(AgsConnectable * connectable,xmlNode * node)527 ags_sfz_region_xml_parse(AgsConnectable *connectable,
528 xmlNode *node)
529 {
530 //TODO:JK: implement me
531 }
532
533 gboolean
ags_sfz_region_is_connected(AgsConnectable * connectable)534 ags_sfz_region_is_connected(AgsConnectable *connectable)
535 {
536 AgsSFZRegion *sfz_region;
537
538 gboolean is_connected;
539
540 sfz_region = AGS_SFZ_REGION(connectable);
541
542 /* check is connected */
543 is_connected = ags_sfz_region_test_flags(sfz_region, AGS_SFZ_REGION_CONNECTED);
544
545 return(is_connected);
546 }
547
548 void
ags_sfz_region_connect(AgsConnectable * connectable)549 ags_sfz_region_connect(AgsConnectable *connectable)
550 {
551 AgsSFZRegion *sfz_region;
552
553 if(ags_connectable_is_connected(connectable)){
554 return;
555 }
556
557 sfz_region = AGS_SFZ_REGION(connectable);
558
559 ags_sfz_region_set_flags(sfz_region, AGS_SFZ_REGION_CONNECTED);
560 }
561
562 void
ags_sfz_region_disconnect(AgsConnectable * connectable)563 ags_sfz_region_disconnect(AgsConnectable *connectable)
564 {
565 AgsSFZRegion *sfz_region;
566
567 if(!ags_connectable_is_connected(connectable)){
568 return;
569 }
570
571 sfz_region = AGS_SFZ_REGION(connectable);
572
573 ags_sfz_region_unset_flags(sfz_region, AGS_SFZ_REGION_CONNECTED);
574 }
575
576 /**
577 * ags_sfz_region_test_flags:
578 * @sfz_region: the #AgsSFZRegion
579 * @flags: the flags
580 *
581 * Test @flags to be set on @sfz_region.
582 *
583 * Returns: %TRUE if flags are set, else %FALSE
584 *
585 * Since: 3.0.0
586 */
587 gboolean
ags_sfz_region_test_flags(AgsSFZRegion * sfz_region,guint flags)588 ags_sfz_region_test_flags(AgsSFZRegion *sfz_region, guint flags)
589 {
590 gboolean retval;
591
592 GRecMutex *sfz_region_mutex;
593
594 if(!AGS_IS_SFZ_REGION(sfz_region)){
595 return(FALSE);
596 }
597
598 /* get sfz_region mutex */
599 sfz_region_mutex = AGS_SFZ_REGION_GET_OBJ_MUTEX(sfz_region);
600
601 /* test */
602 g_rec_mutex_lock(sfz_region_mutex);
603
604 retval = (flags & (sfz_region->flags)) ? TRUE: FALSE;
605
606 g_rec_mutex_unlock(sfz_region_mutex);
607
608 return(retval);
609 }
610
611 /**
612 * ags_sfz_region_set_flags:
613 * @sfz_region: the #AgsSFZRegion
614 * @flags: see #AgsSFZRegionFlags-enum
615 *
616 * Enable a feature of @sfz_region.
617 *
618 * Since: 3.0.0
619 */
620 void
ags_sfz_region_set_flags(AgsSFZRegion * sfz_region,guint flags)621 ags_sfz_region_set_flags(AgsSFZRegion *sfz_region, guint flags)
622 {
623 GRecMutex *sfz_region_mutex;
624
625 if(!AGS_IS_SFZ_REGION(sfz_region)){
626 return;
627 }
628
629 /* get sfz_region mutex */
630 sfz_region_mutex = AGS_SFZ_REGION_GET_OBJ_MUTEX(sfz_region);
631
632 //TODO:JK: add more?
633
634 /* set flags */
635 g_rec_mutex_lock(sfz_region_mutex);
636
637 sfz_region->flags |= flags;
638
639 g_rec_mutex_unlock(sfz_region_mutex);
640 }
641
642 /**
643 * ags_sfz_region_unset_flags:
644 * @sfz_region: the #AgsSFZRegion
645 * @flags: see #AgsSFZRegionFlags-enum
646 *
647 * Disable a feature of @sfz_region.
648 *
649 * Since: 3.0.0
650 */
651 void
ags_sfz_region_unset_flags(AgsSFZRegion * sfz_region,guint flags)652 ags_sfz_region_unset_flags(AgsSFZRegion *sfz_region, guint flags)
653 {
654 GRecMutex *sfz_region_mutex;
655
656 if(!AGS_IS_SFZ_REGION(sfz_region)){
657 return;
658 }
659
660 /* get sfz_region mutex */
661 sfz_region_mutex = AGS_SFZ_REGION_GET_OBJ_MUTEX(sfz_region);
662
663 //TODO:JK: add more?
664
665 /* unset flags */
666 g_rec_mutex_lock(sfz_region_mutex);
667
668 sfz_region->flags &= (~flags);
669
670 g_rec_mutex_unlock(sfz_region_mutex);
671 }
672
673 /**
674 * ags_sfz_region_insert_control:
675 * @sfz_region: the #AgsSFZRegion
676 * @key: the key
677 * @value: the value
678 *
679 * Insert control specified by @key and @value to @sfz_region.
680 *
681 * Since: 3.0.0
682 */
683 void
ags_sfz_region_insert_control(AgsSFZRegion * sfz_region,gchar * key,gchar * value)684 ags_sfz_region_insert_control(AgsSFZRegion *sfz_region,
685 gchar *key,
686 gchar *value)
687 {
688 GRecMutex *sfz_region_mutex;
689
690 if(!AGS_IS_SFZ_REGION(sfz_region)){
691 return;
692 }
693
694 /* get sfz_region mutex */
695 sfz_region_mutex = AGS_SFZ_REGION_GET_OBJ_MUTEX(sfz_region);
696
697 /* insert */
698 g_rec_mutex_lock(sfz_region_mutex);
699
700 g_hash_table_insert(sfz_region->control,
701 key,
702 value);
703
704 g_rec_mutex_unlock(sfz_region_mutex);
705 }
706
707 /**
708 * ags_sfz_region_lookup_control:
709 * @sfz_region: the #AgsSFZRegion
710 * @key: the key
711 *
712 * Lookup control specified by @key of @sfz_region.
713 *
714 * Since: 3.0.0
715 */
716 gchar*
ags_sfz_region_lookup_control(AgsSFZRegion * sfz_region,gchar * key)717 ags_sfz_region_lookup_control(AgsSFZRegion *sfz_region,
718 gchar *key)
719 {
720 gchar *value;
721
722 GRecMutex *sfz_region_mutex;
723
724 if(!AGS_IS_SFZ_REGION(sfz_region)){
725 return(NULL);
726 }
727
728 /* get sfz_region mutex */
729 sfz_region_mutex = AGS_SFZ_REGION_GET_OBJ_MUTEX(sfz_region);
730
731 /* lookup */
732 g_rec_mutex_lock(sfz_region_mutex);
733
734 value = g_hash_table_lookup(sfz_region->control,
735 key);
736
737 value = g_strdup(value);
738
739 g_rec_mutex_unlock(sfz_region_mutex);
740
741 return(value);
742 }
743
744 /**
745 * ags_sfz_region_new:
746 *
747 * Creates a new instance of #AgsSFZRegion.
748 *
749 * Returns: the new #AgsSFZRegion.
750 *
751 * Since: 3.0.0
752 */
753 AgsSFZRegion*
ags_sfz_region_new()754 ags_sfz_region_new()
755 {
756 AgsSFZRegion *sfz_region;
757
758 sfz_region = (AgsSFZRegion *) g_object_new(AGS_TYPE_SFZ_REGION,
759 NULL);
760
761 return(sfz_region);
762 }
763