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_file.h>
21
22 #include <ags/audio/ags_diatonic_scale.h>
23
24 #include <ags/audio/file/ags_sound_container.h>
25 #include <ags/audio/file/ags_sound_resource.h>
26 #include <ags/audio/file/ags_sfz_group.h>
27 #include <ags/audio/file/ags_sfz_region.h>
28 #include <ags/audio/file/ags_sfz_sample.h>
29
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #include <string.h>
34 #include <strings.h>
35
36 #include <ags/i18n.h>
37
38 void ags_sfz_file_class_init(AgsSFZFileClass *sfz_file);
39 void ags_sfz_file_connectable_interface_init(AgsConnectableInterface *connectable);
40 void ags_sfz_file_sound_container_interface_init(AgsSoundContainerInterface *sound_container);
41 void ags_sfz_file_init(AgsSFZFile *sfz_file);
42 void ags_sfz_file_set_property(GObject *gobject,
43 guint prop_id,
44 const GValue *value,
45 GParamSpec *param_spec);
46 void ags_sfz_file_get_property(GObject *gobject,
47 guint prop_id,
48 GValue *value,
49 GParamSpec *param_spec);
50 void ags_sfz_file_dispose(GObject *gobject);
51 void ags_sfz_file_finalize(GObject *gobject);
52
53 AgsUUID* ags_sfz_file_get_uuid(AgsConnectable *connectable);
54 gboolean ags_sfz_file_has_resource(AgsConnectable *connectable);
55 gboolean ags_sfz_file_is_ready(AgsConnectable *connectable);
56 void ags_sfz_file_add_to_registry(AgsConnectable *connectable);
57 void ags_sfz_file_remove_from_registry(AgsConnectable *connectable);
58 xmlNode* ags_sfz_file_list_resource(AgsConnectable *connectable);
59 xmlNode* ags_sfz_file_xml_compose(AgsConnectable *connectable);
60 void ags_sfz_file_xml_parse(AgsConnectable *connectable,
61 xmlNode *node);
62 gboolean ags_sfz_file_is_connected(AgsConnectable *connectable);
63 void ags_sfz_file_connect(AgsConnectable *connectable);
64 void ags_sfz_file_disconnect(AgsConnectable *connectable);
65
66 gboolean ags_sfz_file_open(AgsSoundContainer *sound_container, gchar *filename);
67 guint ags_sfz_file_get_level_count(AgsSoundContainer *sound_container);
68 guint ags_sfz_file_get_nesting_level(AgsSoundContainer *sound_container);
69 gchar* ags_sfz_file_get_level_id(AgsSoundContainer *sound_container);
70 guint ags_sfz_file_get_level_index(AgsSoundContainer *sound_container);
71 guint ags_sfz_file_level_up(AgsSoundContainer *sound_container,
72 guint level_count);
73 guint ags_sfz_file_select_level_by_id(AgsSoundContainer *sound_container,
74 gchar *level_id);
75 guint ags_sfz_file_select_level_by_index(AgsSoundContainer *sound_container,
76 guint level_index);
77 gchar** ags_sfz_file_get_sublevel_name(AgsSoundContainer *sound_container);
78 GList* ags_sfz_file_get_resource_all(AgsSoundContainer *sound_container);
79 GList* ags_sfz_file_get_resource_by_name(AgsSoundContainer *sound_container,
80 gchar *resource_name);
81 GList* ags_sfz_file_get_resource_by_index(AgsSoundContainer *sound_container,
82 guint resource_index);
83 GList* ags_sfz_file_get_resource_current(AgsSoundContainer *sound_container);
84 void ags_sfz_file_close(AgsSoundContainer *sound_container);
85
86 gchar* ags_sfz_file_parse_skip_comments_and_blanks(gchar *buffer, gsize buffer_length,
87 gchar **iter);
88
89 /**
90 * SECTION:ags_sfz_file
91 * @short_description: SFZ file
92 * @title: AgsSFZFile
93 * @section_id:
94 * @include: ags/audio/file/ags_sfz_file.h
95 *
96 * #AgsSFZFile is the base object to ineract with SFZ files.
97 */
98
99 enum{
100 PROP_0,
101 PROP_SOUNDCARD,
102 PROP_FILENAME,
103 PROP_MODE,
104 PROP_GROUP,
105 PROP_REGION,
106 PROP_SAMPLE,
107 };
108
109 static gpointer ags_sfz_file_parent_class = NULL;
110
111 static GMutex regex_mutex;
112
113 GType
ags_sfz_file_get_type()114 ags_sfz_file_get_type()
115 {
116 static volatile gsize g_define_type_id__volatile = 0;
117
118 if(g_once_init_enter (&g_define_type_id__volatile)){
119 GType ags_type_sfz_file = 0;
120
121 static const GTypeInfo ags_sfz_file_info = {
122 sizeof (AgsSFZFileClass),
123 NULL, /* base_init */
124 NULL, /* base_finalize */
125 (GClassInitFunc) ags_sfz_file_class_init,
126 NULL, /* class_finalize */
127 NULL, /* class_data */
128 sizeof (AgsSFZFile),
129 0, /* n_preallocs */
130 (GInstanceInitFunc) ags_sfz_file_init,
131 };
132
133 static const GInterfaceInfo ags_connectable_interface_info = {
134 (GInterfaceInitFunc) ags_sfz_file_connectable_interface_init,
135 NULL, /* interface_finalize */
136 NULL, /* interface_data */
137 };
138
139 static const GInterfaceInfo ags_sound_container_interface_info = {
140 (GInterfaceInitFunc) ags_sfz_file_sound_container_interface_init,
141 NULL, /* interface_finalize */
142 NULL, /* interface_data */
143 };
144
145 ags_type_sfz_file = g_type_register_static(G_TYPE_OBJECT,
146 "AgsSFZFile",
147 &ags_sfz_file_info,
148 0);
149
150 g_type_add_interface_static(ags_type_sfz_file,
151 AGS_TYPE_CONNECTABLE,
152 &ags_connectable_interface_info);
153
154 g_type_add_interface_static(ags_type_sfz_file,
155 AGS_TYPE_SOUND_CONTAINER,
156 &ags_sound_container_interface_info);
157
158 g_once_init_leave(&g_define_type_id__volatile, ags_type_sfz_file);
159 }
160
161 return g_define_type_id__volatile;
162 }
163
164 void
ags_sfz_file_class_init(AgsSFZFileClass * sfz_file)165 ags_sfz_file_class_init(AgsSFZFileClass *sfz_file)
166 {
167 GObjectClass *gobject;
168 GParamSpec *param_spec;
169
170 ags_sfz_file_parent_class = g_type_class_peek_parent(sfz_file);
171
172 /* GObjectClass */
173 gobject = (GObjectClass *) sfz_file;
174
175 gobject->set_property = ags_sfz_file_set_property;
176 gobject->get_property = ags_sfz_file_get_property;
177
178 gobject->dispose = ags_sfz_file_dispose;
179 gobject->finalize = ags_sfz_file_finalize;
180
181 /* properties */
182 /**
183 * AgsSFZFile:soundcard:
184 *
185 * The assigned soundcard.
186 *
187 * Since: 3.0.0
188 */
189 param_spec = g_param_spec_object("soundcard",
190 i18n_pspec("soundcard of sfz_file"),
191 i18n_pspec("The soundcard what sfz_file has it's presets"),
192 G_TYPE_OBJECT,
193 G_PARAM_READABLE | G_PARAM_WRITABLE);
194 g_object_class_install_property(gobject,
195 PROP_SOUNDCARD,
196 param_spec);
197
198 /**
199 * AgsSFZFile:filename:
200 *
201 * The assigned filename.
202 *
203 * Since: 3.0.0
204 */
205 param_spec = g_param_spec_string("filename",
206 i18n_pspec("the filename"),
207 i18n_pspec("The filename to open"),
208 NULL,
209 G_PARAM_READABLE | G_PARAM_WRITABLE);
210 g_object_class_install_property(gobject,
211 PROP_FILENAME,
212 param_spec);
213
214 /**
215 * AgsSFZFile:mode:
216 *
217 * The assigned mode.
218 *
219 * Since: 3.0.0
220 */
221 param_spec = g_param_spec_string("mode",
222 i18n_pspec("the mode"),
223 i18n_pspec("The mode to open the file"),
224 NULL,
225 G_PARAM_READABLE | G_PARAM_WRITABLE);
226 g_object_class_install_property(gobject,
227 PROP_MODE,
228 param_spec);
229
230 /**
231 * AgsSFZFile:group: (type GList(AgsSFZGroup)) (transfer full)
232 *
233 * The containing groups.
234 *
235 * Since: 3.0.0
236 */
237 param_spec = g_param_spec_pointer("group",
238 i18n_pspec("containing group"),
239 i18n_pspec("The containing groups"),
240 G_PARAM_READABLE | G_PARAM_WRITABLE);
241 g_object_class_install_property(gobject,
242 PROP_GROUP,
243 param_spec);
244
245 /**
246 * AgsSFZFile:region: (type GList(AgsSFZRegion)) (transfer full)
247 *
248 * The containing regions.
249 *
250 * Since: 3.0.0
251 */
252 param_spec = g_param_spec_pointer("region",
253 i18n_pspec("containing region"),
254 i18n_pspec("The containing regions"),
255 G_PARAM_READABLE | G_PARAM_WRITABLE);
256 g_object_class_install_property(gobject,
257 PROP_REGION,
258 param_spec);
259
260 /**
261 * AgsSFZFile:sample: (type GList(AgsSFZSample)) (transfer full)
262 *
263 * The containing samples.
264 *
265 * Since: 3.0.0
266 */
267 param_spec = g_param_spec_pointer("sample",
268 i18n_pspec("containing sample"),
269 i18n_pspec("The containing samples"),
270 G_PARAM_READABLE | G_PARAM_WRITABLE);
271 g_object_class_install_property(gobject,
272 PROP_SAMPLE,
273 param_spec);
274 }
275
276 void
ags_sfz_file_connectable_interface_init(AgsConnectableInterface * connectable)277 ags_sfz_file_connectable_interface_init(AgsConnectableInterface *connectable)
278 {
279 connectable->get_uuid = ags_sfz_file_get_uuid;
280 connectable->has_resource = ags_sfz_file_has_resource;
281 connectable->is_ready = ags_sfz_file_is_ready;
282
283 connectable->add_to_registry = ags_sfz_file_add_to_registry;
284 connectable->remove_from_registry = ags_sfz_file_remove_from_registry;
285
286 connectable->list_resource = ags_sfz_file_list_resource;
287 connectable->xml_compose = ags_sfz_file_xml_compose;
288 connectable->xml_parse = ags_sfz_file_xml_parse;
289
290 connectable->is_connected = ags_sfz_file_is_connected;
291
292 connectable->connect = ags_sfz_file_connect;
293 connectable->disconnect = ags_sfz_file_disconnect;
294
295 connectable->connect_connection = NULL;
296 connectable->disconnect_connection = NULL;
297 }
298
299 void
ags_sfz_file_sound_container_interface_init(AgsSoundContainerInterface * sound_container)300 ags_sfz_file_sound_container_interface_init(AgsSoundContainerInterface *sound_container)
301 {
302 sound_container->open = ags_sfz_file_open;
303
304 sound_container->get_level_count = ags_sfz_file_get_level_count;
305 sound_container->get_nesting_level = ags_sfz_file_get_nesting_level;
306
307 sound_container->get_level_id = ags_sfz_file_get_level_id;
308 sound_container->get_level_index = ags_sfz_file_get_level_index;
309
310 sound_container->get_sublevel_name = ags_sfz_file_get_sublevel_name;
311
312 sound_container->level_up = ags_sfz_file_level_up;
313 sound_container->select_level_by_id = ags_sfz_file_select_level_by_id;
314 sound_container->select_level_by_index = ags_sfz_file_select_level_by_index;
315
316 sound_container->get_resource_all = ags_sfz_file_get_resource_all;
317 sound_container->get_resource_by_name = ags_sfz_file_get_resource_by_name;
318 sound_container->get_resource_by_index = ags_sfz_file_get_resource_by_index;
319 sound_container->get_resource_current = ags_sfz_file_get_resource_current;
320
321 sound_container->close = ags_sfz_file_close;
322 }
323
324 void
ags_sfz_file_init(AgsSFZFile * sfz_file)325 ags_sfz_file_init(AgsSFZFile *sfz_file)
326 {
327 guint i;
328
329 sfz_file->flags = 0;
330
331 /* add audio file mutex */
332 g_rec_mutex_init(&(sfz_file->obj_mutex));
333
334 /* uuid */
335 sfz_file->uuid = ags_uuid_alloc();
336 ags_uuid_generate(sfz_file->uuid);
337
338 sfz_file->soundcard = NULL;
339
340 sfz_file->filename = NULL;
341 sfz_file->mode = AGS_SFZ_FILE_READ;
342
343 sfz_file->file = NULL;
344
345 sfz_file->nesting_level = 0;
346
347 sfz_file->level_id = NULL;
348 sfz_file->level_index = 0;
349
350 sfz_file->reader = NULL;
351 sfz_file->writer = NULL;
352
353 sfz_file->group = NULL;
354 sfz_file->region = NULL;
355 sfz_file->sample = NULL;
356
357 /* selected */
358 sfz_file->index_selected = (guint *) malloc(2 * sizeof(guint));
359 memset(sfz_file->index_selected, 0, 2 * sizeof(guint));
360
361 sfz_file->name_selected = (gchar **) malloc(3 * sizeof(gchar *));
362
363 for(i = 0; i < 3; i++){
364 sfz_file->name_selected[i] = NULL;
365 }
366
367 sfz_file->current_sample = NULL;
368
369 sfz_file->audio_signal= NULL;
370 }
371
372 void
ags_sfz_file_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)373 ags_sfz_file_set_property(GObject *gobject,
374 guint prop_id,
375 const GValue *value,
376 GParamSpec *param_spec)
377 {
378 AgsSFZFile *sfz_file;
379
380 GRecMutex *sfz_file_mutex;
381
382 sfz_file = AGS_SFZ_FILE(gobject);
383
384 /* get sfz file mutex */
385 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
386
387 switch(prop_id){
388 case PROP_SOUNDCARD:
389 {
390 GObject *soundcard;
391
392 soundcard = (GObject *) g_value_get_object(value);
393
394 g_rec_mutex_lock(sfz_file_mutex);
395
396 if(soundcard == ((GObject *) sfz_file->soundcard)){
397 g_rec_mutex_unlock(sfz_file_mutex);
398
399 return;
400 }
401
402 if(sfz_file->soundcard != NULL){
403 g_object_unref(sfz_file->soundcard);
404 }
405
406 if(soundcard != NULL){
407 g_object_ref(G_OBJECT(soundcard));
408 }
409
410 sfz_file->soundcard = (GObject *) soundcard;
411
412 g_rec_mutex_unlock(sfz_file_mutex);
413 }
414 break;
415 case PROP_FILENAME:
416 {
417 gchar *filename;
418
419 filename = (gchar *) g_value_get_string(value);
420
421 ags_sound_container_open(AGS_SOUND_CONTAINER(sfz_file), filename);
422 }
423 break;
424 case PROP_MODE:
425 {
426 gchar *mode;
427
428 mode = (gchar *) g_value_get_string(value);
429
430 g_rec_mutex_lock(sfz_file_mutex);
431
432 sfz_file->mode = mode;
433
434 g_rec_mutex_lock(sfz_file_mutex);
435 }
436 break;
437 case PROP_GROUP:
438 {
439 GObject *group;
440
441 group = g_value_get_pointer(value);
442
443 g_rec_mutex_lock(sfz_file_mutex);
444
445 if(group == NULL ||
446 g_list_find(sfz_file->group, group) != NULL){
447 g_rec_mutex_unlock(sfz_file_mutex);
448
449 return;
450 }
451
452 g_object_ref(group);
453 sfz_file->group = g_list_prepend(sfz_file->group,
454 group);
455
456 g_rec_mutex_unlock(sfz_file_mutex);
457 }
458 break;
459 case PROP_REGION:
460 {
461 GObject *region;
462
463 region = g_value_get_pointer(value);
464
465 g_rec_mutex_lock(sfz_file_mutex);
466
467 if(region == NULL ||
468 g_list_find(sfz_file->region, region) != NULL){
469 g_rec_mutex_unlock(sfz_file_mutex);
470
471 return;
472 }
473
474 g_object_ref(region);
475 sfz_file->region = g_list_prepend(sfz_file->region,
476 region);
477
478 g_rec_mutex_unlock(sfz_file_mutex);
479 }
480 break;
481 case PROP_SAMPLE:
482 {
483 GObject *sample;
484
485 sample = g_value_get_pointer(value);
486
487 g_rec_mutex_lock(sfz_file_mutex);
488
489 if(sample == NULL ||
490 g_list_find(sfz_file->sample, sample) != NULL){
491 g_rec_mutex_unlock(sfz_file_mutex);
492
493 return;
494 }
495
496 g_object_ref(sample);
497 sfz_file->sample = g_list_prepend(sfz_file->sample,
498 sample);
499
500 g_rec_mutex_unlock(sfz_file_mutex);
501 }
502 break;
503 default:
504 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
505 break;
506 }
507 }
508
509 void
ags_sfz_file_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)510 ags_sfz_file_get_property(GObject *gobject,
511 guint prop_id,
512 GValue *value,
513 GParamSpec *param_spec)
514 {
515 AgsSFZFile *sfz_file;
516
517 GRecMutex *sfz_file_mutex;
518
519 sfz_file = AGS_SFZ_FILE(gobject);
520
521 /* get sfz file mutex */
522 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
523
524 switch(prop_id){
525 case PROP_SOUNDCARD:
526 {
527 g_rec_mutex_lock(sfz_file_mutex);
528
529 g_value_set_object(value, sfz_file->soundcard);
530
531 g_rec_mutex_unlock(sfz_file_mutex);
532 }
533 break;
534 case PROP_FILENAME:
535 {
536 g_rec_mutex_lock(sfz_file_mutex);
537
538 g_value_set_string(value, sfz_file->filename);
539
540 g_rec_mutex_unlock(sfz_file_mutex);
541 }
542 break;
543 case PROP_MODE:
544 {
545 g_rec_mutex_lock(sfz_file_mutex);
546
547 g_value_set_string(value, sfz_file->mode);
548
549 g_rec_mutex_unlock(sfz_file_mutex);
550 }
551 break;
552 case PROP_GROUP:
553 {
554 g_rec_mutex_lock(sfz_file_mutex);
555
556 g_value_set_pointer(value, g_list_copy_deep(sfz_file->group,
557 (GCopyFunc) g_object_ref,
558 NULL));
559
560 g_rec_mutex_unlock(sfz_file_mutex);
561 }
562 break;
563 case PROP_REGION:
564 {
565 g_rec_mutex_lock(sfz_file_mutex);
566
567 g_value_set_pointer(value, g_list_copy_deep(sfz_file->region,
568 (GCopyFunc) g_object_ref,
569 NULL));
570
571 g_rec_mutex_unlock(sfz_file_mutex);
572 }
573 break;
574 case PROP_SAMPLE:
575 {
576 g_rec_mutex_lock(sfz_file_mutex);
577
578 g_value_set_pointer(value, g_list_copy_deep(sfz_file->sample,
579 (GCopyFunc) g_object_ref,
580 NULL));
581
582 g_rec_mutex_unlock(sfz_file_mutex);
583 }
584 break;
585 default:
586 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
587 break;
588 }
589 }
590
591 void
ags_sfz_file_dispose(GObject * gobject)592 ags_sfz_file_dispose(GObject *gobject)
593 {
594 AgsSFZFile *sfz_file;
595
596 sfz_file = AGS_SFZ_FILE(gobject);
597
598 if(sfz_file->group != NULL){
599 g_list_free_full(sfz_file->group,
600 g_object_unref);
601
602 sfz_file->group = NULL;
603 }
604
605 if(sfz_file->region != NULL){
606 g_list_free_full(sfz_file->region,
607 g_object_unref);
608
609 sfz_file->region = NULL;
610 }
611
612 if(sfz_file->sample != NULL){
613 g_list_free_full(sfz_file->sample,
614 g_object_unref);
615
616 sfz_file->sample = NULL;
617 }
618
619 /* call parent */
620 G_OBJECT_CLASS(ags_sfz_file_parent_class)->dispose(gobject);
621 }
622
623 void
ags_sfz_file_finalize(GObject * gobject)624 ags_sfz_file_finalize(GObject *gobject)
625 {
626 AgsSFZFile *sfz_file;
627
628 sfz_file = AGS_SFZ_FILE(gobject);
629
630 if(sfz_file->soundcard != NULL){
631 g_object_unref(sfz_file->soundcard);
632 }
633
634 g_free(sfz_file->filename);
635 g_free(sfz_file->mode);
636
637 if(sfz_file->reader != NULL){
638 g_object_unref(sfz_file->reader);
639 }
640
641 if(sfz_file->group != NULL){
642 g_list_free_full(sfz_file->group,
643 g_object_unref);
644 }
645
646 if(sfz_file->region != NULL){
647 g_list_free_full(sfz_file->region,
648 g_object_unref);
649 }
650
651 if(sfz_file->sample != NULL){
652 g_list_free_full(sfz_file->sample,
653 g_object_unref);
654 }
655
656 g_list_free_full(sfz_file->audio_signal,
657 g_object_unref);
658
659 /* call parent */
660 G_OBJECT_CLASS(ags_sfz_file_parent_class)->finalize(gobject);
661 }
662
663 AgsUUID*
ags_sfz_file_get_uuid(AgsConnectable * connectable)664 ags_sfz_file_get_uuid(AgsConnectable *connectable)
665 {
666 AgsSFZFile *sfz_file;
667
668 AgsUUID *ptr;
669
670 GRecMutex *sfz_file_mutex;
671
672 sfz_file = AGS_SFZ_FILE(connectable);
673
674 /* get audio file mutex */
675 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
676
677 /* get UUID */
678 g_rec_mutex_lock(sfz_file_mutex);
679
680 ptr = sfz_file->uuid;
681
682 g_rec_mutex_unlock(sfz_file_mutex);
683
684 return(ptr);
685 }
686
687 gboolean
ags_sfz_file_has_resource(AgsConnectable * connectable)688 ags_sfz_file_has_resource(AgsConnectable *connectable)
689 {
690 return(TRUE);
691 }
692
693 gboolean
ags_sfz_file_is_ready(AgsConnectable * connectable)694 ags_sfz_file_is_ready(AgsConnectable *connectable)
695 {
696 AgsSFZFile *sfz_file;
697
698 gboolean is_ready;
699
700 sfz_file = AGS_SFZ_FILE(connectable);
701
702 /* check is ready */
703 is_ready = ags_sfz_file_test_flags(sfz_file, AGS_SFZ_FILE_ADDED_TO_REGISTRY);
704
705 return(is_ready);
706 }
707
708 void
ags_sfz_file_add_to_registry(AgsConnectable * connectable)709 ags_sfz_file_add_to_registry(AgsConnectable *connectable)
710 {
711 AgsSFZFile *sfz_file;
712
713 AgsRegistry *registry;
714 AgsRegistryEntry *entry;
715
716 AgsApplicationContext *application_context;
717
718 if(ags_connectable_is_ready(connectable)){
719 return;
720 }
721
722 sfz_file = AGS_SFZ_FILE(connectable);
723
724 ags_sfz_file_set_flags(sfz_file, AGS_SFZ_FILE_ADDED_TO_REGISTRY);
725
726 application_context = ags_application_context_get_instance();
727
728 registry = (AgsRegistry *) ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
729
730 if(registry != NULL){
731 entry = ags_registry_entry_alloc(registry);
732 g_value_set_object(entry->entry,
733 (gpointer) sfz_file);
734 ags_registry_add_entry(registry,
735 entry);
736 }
737 }
738
739 void
ags_sfz_file_remove_from_registry(AgsConnectable * connectable)740 ags_sfz_file_remove_from_registry(AgsConnectable *connectable)
741 {
742 if(!ags_connectable_is_ready(connectable)){
743 return;
744 }
745
746 //TODO:JK: implement me
747 }
748
749 xmlNode*
ags_sfz_file_list_resource(AgsConnectable * connectable)750 ags_sfz_file_list_resource(AgsConnectable *connectable)
751 {
752 xmlNode *node;
753
754 node = NULL;
755
756 //TODO:JK: implement me
757
758 return(node);
759 }
760
761 xmlNode*
ags_sfz_file_xml_compose(AgsConnectable * connectable)762 ags_sfz_file_xml_compose(AgsConnectable *connectable)
763 {
764 xmlNode *node;
765
766 node = NULL;
767
768 //TODO:JK: implement me
769
770 return(node);
771 }
772
773 void
ags_sfz_file_xml_parse(AgsConnectable * connectable,xmlNode * node)774 ags_sfz_file_xml_parse(AgsConnectable *connectable,
775 xmlNode *node)
776 {
777 //TODO:JK: implement me
778 }
779
780 gboolean
ags_sfz_file_is_connected(AgsConnectable * connectable)781 ags_sfz_file_is_connected(AgsConnectable *connectable)
782 {
783 AgsSFZFile *sfz_file;
784
785 gboolean is_connected;
786
787 sfz_file = AGS_SFZ_FILE(connectable);
788
789 /* check is connected */
790 is_connected = ags_sfz_file_test_flags(sfz_file, AGS_SFZ_FILE_CONNECTED);
791
792 return(is_connected);
793 }
794
795 void
ags_sfz_file_connect(AgsConnectable * connectable)796 ags_sfz_file_connect(AgsConnectable *connectable)
797 {
798 AgsSFZFile *sfz_file;
799
800 if(ags_connectable_is_connected(connectable)){
801 return;
802 }
803
804 sfz_file = AGS_SFZ_FILE(connectable);
805
806 ags_sfz_file_set_flags(sfz_file, AGS_SFZ_FILE_CONNECTED);
807 }
808
809 void
ags_sfz_file_disconnect(AgsConnectable * connectable)810 ags_sfz_file_disconnect(AgsConnectable *connectable)
811 {
812 AgsSFZFile *sfz_file;
813
814 if(!ags_connectable_is_connected(connectable)){
815 return;
816 }
817
818 sfz_file = AGS_SFZ_FILE(connectable);
819
820 ags_sfz_file_unset_flags(sfz_file, AGS_SFZ_FILE_CONNECTED);
821 }
822
823 gboolean
ags_sfz_file_open(AgsSoundContainer * sound_container,gchar * filename)824 ags_sfz_file_open(AgsSoundContainer *sound_container, gchar *filename)
825 {
826 AgsSFZFile *sfz_file;
827
828 FILE *file;
829
830 gchar *old_filename;
831
832 gboolean retval;
833
834 GRecMutex *sfz_file_mutex;
835
836 sfz_file = AGS_SFZ_FILE(sound_container);
837
838 /* get sfz_file mutex */
839 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
840
841 /* get some fields */
842 g_rec_mutex_lock(sfz_file_mutex);
843
844 old_filename = sfz_file->filename;
845
846 g_rec_mutex_unlock(sfz_file_mutex);
847
848 /* close current */
849 if(old_filename != NULL){
850 ags_sound_container_close(sound_container);
851
852 g_free(old_filename);
853 }
854
855 /* check suffix */
856 g_rec_mutex_lock(sfz_file_mutex);
857
858 sfz_file->filename = g_strdup(filename);
859
860 g_rec_mutex_unlock(sfz_file_mutex);
861
862 if(!ags_sfz_file_check_suffix(filename)){
863 g_message("unsupported suffix");
864
865 return(FALSE);
866 }
867
868 /* open file */
869 file = fopen(filename,
870 "r");
871
872 g_rec_mutex_lock(sfz_file_mutex);
873
874 sfz_file->file = file;
875
876 g_rec_mutex_unlock(sfz_file_mutex);
877
878 if(file == NULL){
879 g_message("failed to open file");
880
881 return(FALSE);
882 }
883
884 /* load samples */
885 retval = TRUE;
886
887 ags_sfz_file_parse(sfz_file);
888
889 return(retval);
890 }
891
892 guint
ags_sfz_file_get_level_count(AgsSoundContainer * sound_container)893 ags_sfz_file_get_level_count(AgsSoundContainer *sound_container)
894 {
895 AgsSFZFile *sfz_file;
896
897 sfz_file = AGS_SFZ_FILE(sound_container);
898
899 return(3);
900 }
901
902 guint
ags_sfz_file_get_nesting_level(AgsSoundContainer * sound_container)903 ags_sfz_file_get_nesting_level(AgsSoundContainer *sound_container)
904 {
905 AgsSFZFile *sfz_file;
906
907 guint nesting_level;
908
909 GRecMutex *sfz_file_mutex;
910
911 sfz_file = AGS_SFZ_FILE(sound_container);
912
913 /* get sfz_file mutex */
914 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
915
916 /* get nesting level */
917 g_rec_mutex_lock(sfz_file_mutex);
918
919 nesting_level = sfz_file->nesting_level;
920
921 g_rec_mutex_unlock(sfz_file_mutex);
922
923 return(nesting_level);
924 }
925
926 gchar*
ags_sfz_file_get_level_id(AgsSoundContainer * sound_container)927 ags_sfz_file_get_level_id(AgsSoundContainer *sound_container)
928 {
929 AgsSFZFile *sfz_file;
930
931 gchar *level_id;
932
933 GRecMutex *sfz_file_mutex;
934
935 sfz_file = AGS_SFZ_FILE(sound_container);
936
937 /* get sfz_file mutex */
938 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
939
940 /* get level id */
941 g_rec_mutex_lock(sfz_file_mutex);
942
943 level_id = sfz_file->level_id;
944
945 g_rec_mutex_unlock(sfz_file_mutex);
946
947 return(level_id);
948 }
949
950 guint
ags_sfz_file_get_level_index(AgsSoundContainer * sound_container)951 ags_sfz_file_get_level_index(AgsSoundContainer *sound_container)
952 {
953 AgsSFZFile *sfz_file;
954
955 guint level_index;
956
957 GRecMutex *sfz_file_mutex;
958
959 sfz_file = AGS_SFZ_FILE(sound_container);
960
961 /* get sfz_file mutex */
962 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
963
964 /* get nesting level */
965 g_rec_mutex_lock(sfz_file_mutex);
966
967 level_index = sfz_file->level_index;
968
969 g_rec_mutex_unlock(sfz_file_mutex);
970
971 return(level_index);
972 }
973
974 gchar**
ags_sfz_file_get_sublevel_name(AgsSoundContainer * sound_container)975 ags_sfz_file_get_sublevel_name(AgsSoundContainer *sound_container)
976 {
977 AgsSFZFile *sfz_file;
978
979 guint sublevel;
980
981 GRecMutex *sfz_file_mutex;
982
983 sfz_file = AGS_SFZ_FILE(sound_container);
984
985 /* get sfz_file mutex */
986 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
987
988 /* sublevel */
989 sublevel = ags_sound_container_get_nesting_level(AGS_SOUND_CONTAINER(sfz_file));
990
991 switch(sublevel){
992 case AGS_SFZ_LEVEL_FILENAME:
993 {
994 gchar **sublevel_name;
995
996 sublevel_name = (gchar **) malloc(2 * sizeof(gchar*));
997
998 g_rec_mutex_lock(sfz_file_mutex);
999
1000 sublevel_name[0] = g_strdup(sfz_file->filename);
1001
1002 g_rec_mutex_unlock(sfz_file_mutex);
1003
1004 sublevel_name[1] = NULL;
1005
1006 return(sublevel_name);
1007 }
1008 case AGS_SFZ_LEVEL_SAMPLE:
1009 {
1010 GList *start_list, *list;
1011
1012 gchar **sublevel_name;
1013
1014 guint sample_count;
1015 guint i;
1016
1017 g_object_get(sfz_file,
1018 "sample", &start_list,
1019 NULL);
1020
1021 list = start_list;
1022
1023 sample_count = g_list_length(start_list);
1024
1025 sublevel_name = (gchar **) malloc((sample_count + 1) * sizeof(gchar*));
1026
1027 for(i = 0; i < sample_count; i++){
1028 gchar *str;
1029
1030 g_object_get(list->data,
1031 "filename", &str,
1032 NULL);
1033 sublevel_name[i] = str;
1034
1035 list = list->next;
1036 }
1037
1038 sublevel_name[i] = NULL;
1039
1040 g_list_free_full(start_list,
1041 g_object_unref);
1042
1043 return(sublevel_name);
1044 }
1045 };
1046
1047 return(NULL);
1048 }
1049
1050 guint
ags_sfz_file_level_up(AgsSoundContainer * sound_container,guint level_count)1051 ags_sfz_file_level_up(AgsSoundContainer *sound_container,
1052 guint level_count)
1053 {
1054 AgsSFZFile *sfz_file;
1055
1056 guint retval;
1057
1058 GRecMutex *sfz_file_mutex;
1059
1060 if(level_count == 0){
1061 return(0);
1062 }
1063
1064 sfz_file = AGS_SFZ_FILE(sound_container);
1065
1066 /* get sfz_file mutex */
1067 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
1068
1069 /* check boundaries */
1070 if(ags_sound_container_get_nesting_level(AGS_SOUND_CONTAINER(sfz_file)) >= level_count){
1071 /* level up */
1072 g_rec_mutex_lock(sfz_file_mutex);
1073
1074 retval = level_count;
1075
1076 sfz_file->nesting_level -= level_count;
1077
1078 g_rec_mutex_unlock(sfz_file_mutex);
1079 }else{
1080 /* level up */
1081 g_rec_mutex_lock(sfz_file_mutex);
1082
1083 retval = sfz_file->nesting_level;
1084
1085 sfz_file->nesting_level = 0;
1086
1087 g_rec_mutex_unlock(sfz_file_mutex);
1088 }
1089
1090 return(retval);
1091 }
1092
1093 guint
ags_sfz_file_select_level_by_id(AgsSoundContainer * sound_container,gchar * level_id)1094 ags_sfz_file_select_level_by_id(AgsSoundContainer *sound_container,
1095 gchar *level_id)
1096 {
1097 return(0);
1098 }
1099
1100 guint
ags_sfz_file_select_level_by_index(AgsSoundContainer * sound_container,guint level_index)1101 ags_sfz_file_select_level_by_index(AgsSoundContainer *sound_container,
1102 guint level_index)
1103 {
1104 AgsSFZFile *sfz_file;
1105
1106 guint sublevel;
1107 guint retval;
1108
1109 GRecMutex *sfz_file_mutex;
1110
1111 sfz_file = AGS_SFZ_FILE(sound_container);
1112
1113 /* get sfz_file mutex */
1114 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
1115
1116 /* sublevel */
1117 sublevel = ags_sound_container_get_nesting_level(AGS_SOUND_CONTAINER(sfz_file));
1118 retval = 0;
1119
1120 switch(sublevel){
1121 case AGS_SFZ_LEVEL_FILENAME:
1122 {
1123 if(ags_sfz_file_select_sample(sfz_file, level_index)){
1124 retval = AGS_SFZ_LEVEL_FILENAME;
1125 }
1126 }
1127 break;
1128 case AGS_SFZ_LEVEL_SAMPLE:
1129 {
1130 retval = AGS_SFZ_LEVEL_SAMPLE;
1131 }
1132 break;
1133 };
1134
1135 return(retval);
1136 }
1137
1138 GList*
ags_sfz_file_get_resource_all(AgsSoundContainer * sound_container)1139 ags_sfz_file_get_resource_all(AgsSoundContainer *sound_container)
1140 {
1141 AgsSFZFile *sfz_file;
1142
1143 GList *resource;
1144
1145 sfz_file = AGS_SFZ_FILE(sound_container);
1146
1147 resource = NULL;
1148
1149 //TODO:JK: implement me
1150
1151 return(resource);
1152 }
1153
1154 GList*
ags_sfz_file_get_resource_by_name(AgsSoundContainer * sound_container,gchar * resource_name)1155 ags_sfz_file_get_resource_by_name(AgsSoundContainer *sound_container,
1156 gchar *resource_name)
1157 {
1158 //TODO:JK: implement me
1159
1160 return(NULL);
1161 }
1162
1163 GList*
ags_sfz_file_get_resource_by_index(AgsSoundContainer * sound_container,guint resource_index)1164 ags_sfz_file_get_resource_by_index(AgsSoundContainer *sound_container,
1165 guint resource_index)
1166 {
1167 //TODO:JK: implement me
1168
1169 return(NULL);
1170 }
1171
1172 GList*
ags_sfz_file_get_resource_current(AgsSoundContainer * sound_container)1173 ags_sfz_file_get_resource_current(AgsSoundContainer *sound_container)
1174 {
1175 AgsSFZFile *sfz_file;
1176
1177 GList *sound_resource;
1178
1179 GRecMutex *sfz_file_mutex;
1180
1181 sfz_file = AGS_SFZ_FILE(sound_container);
1182
1183 /* get sfz_file mutex */
1184 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
1185
1186 /* get sound resource */
1187 sound_resource = NULL;
1188
1189 g_object_get(sfz_file,
1190 "sample", &sound_resource,
1191 NULL);
1192
1193 return(sound_resource);
1194 }
1195
1196 void
ags_sfz_file_close(AgsSoundContainer * sound_container)1197 ags_sfz_file_close(AgsSoundContainer *sound_container)
1198 {
1199 //TODO:JK: implement me
1200 }
1201
1202 /**
1203 * ags_sfz_file_test_flags:
1204 * @sfz_file: the #AgsSFZFile
1205 * @flags: the flags
1206 *
1207 * Test @flags to be set on @sfz_file.
1208 *
1209 * Returns: %TRUE if flags are set, else %FALSE
1210 *
1211 * Since: 3.0.0
1212 */
1213 gboolean
ags_sfz_file_test_flags(AgsSFZFile * sfz_file,guint flags)1214 ags_sfz_file_test_flags(AgsSFZFile *sfz_file, guint flags)
1215 {
1216 gboolean retval;
1217
1218 GRecMutex *sfz_file_mutex;
1219
1220 if(!AGS_IS_SFZ_FILE(sfz_file)){
1221 return(FALSE);
1222 }
1223
1224 /* get sfz_file mutex */
1225 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
1226
1227 /* test */
1228 g_rec_mutex_lock(sfz_file_mutex);
1229
1230 retval = (flags & (sfz_file->flags)) ? TRUE: FALSE;
1231
1232 g_rec_mutex_unlock(sfz_file_mutex);
1233
1234 return(retval);
1235 }
1236
1237 /**
1238 * ags_sfz_file_set_flags:
1239 * @sfz_file: the #AgsSFZFile
1240 * @flags: see #AgsSFZFileFlags-enum
1241 *
1242 * Enable a feature of @sfz_file.
1243 *
1244 * Since: 3.0.0
1245 */
1246 void
ags_sfz_file_set_flags(AgsSFZFile * sfz_file,guint flags)1247 ags_sfz_file_set_flags(AgsSFZFile *sfz_file, guint flags)
1248 {
1249 GRecMutex *sfz_file_mutex;
1250
1251 if(!AGS_IS_SFZ_FILE(sfz_file)){
1252 return;
1253 }
1254
1255 /* get sfz_file mutex */
1256 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
1257
1258 //TODO:JK: add more?
1259
1260 /* set flags */
1261 g_rec_mutex_lock(sfz_file_mutex);
1262
1263 sfz_file->flags |= flags;
1264
1265 g_rec_mutex_unlock(sfz_file_mutex);
1266 }
1267
1268 /**
1269 * ags_sfz_file_unset_flags:
1270 * @sfz_file: the #AgsSFZFile
1271 * @flags: see #AgsSFZFileFlags-enum
1272 *
1273 * Disable a feature of @sfz_file.
1274 *
1275 * Since: 3.0.0
1276 */
1277 void
ags_sfz_file_unset_flags(AgsSFZFile * sfz_file,guint flags)1278 ags_sfz_file_unset_flags(AgsSFZFile *sfz_file, guint flags)
1279 {
1280 GRecMutex *sfz_file_mutex;
1281
1282 if(!AGS_IS_SFZ_FILE(sfz_file)){
1283 return;
1284 }
1285
1286 /* get sfz_file mutex */
1287 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
1288
1289 //TODO:JK: add more?
1290
1291 /* unset flags */
1292 g_rec_mutex_lock(sfz_file_mutex);
1293
1294 sfz_file->flags &= (~flags);
1295
1296 g_rec_mutex_unlock(sfz_file_mutex);
1297 }
1298
1299 /**
1300 * ags_sfz_file_select_sample:
1301 * @sfz_file: the #AgsSFZFile
1302 * @sample_index: the sample index
1303 *
1304 * Select sample.
1305 *
1306 * Returns: %TRUE on success, else %FALSE on failure
1307 *
1308 * Since: 3.0.0
1309 */
1310 gboolean
ags_sfz_file_select_sample(AgsSFZFile * sfz_file,guint sample_index)1311 ags_sfz_file_select_sample(AgsSFZFile *sfz_file,
1312 guint sample_index)
1313 {
1314 GList *start_list, *list;
1315
1316 gboolean success;
1317
1318 GRecMutex *sfz_file_mutex;
1319
1320 if(!AGS_IS_SFZ_FILE(sfz_file)){
1321 return(FALSE);
1322 }
1323
1324 /* get sfz file mutex */
1325 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
1326
1327 success = FALSE;
1328
1329 g_object_get(sfz_file,
1330 "sample", &start_list,
1331 NULL);
1332
1333 if(start_list != NULL){
1334 list = start_list;
1335
1336 if(sample_index < g_list_length(start_list)){
1337 gchar *filename;
1338
1339 success = TRUE;
1340
1341 list = g_list_nth(start_list,
1342 sample_index);
1343
1344 /* selected index and name */
1345 filename = NULL;
1346
1347 g_object_get(list->data,
1348 "filename", &filename,
1349 NULL);
1350
1351 g_rec_mutex_lock(sfz_file_mutex);
1352
1353 sfz_file->index_selected[AGS_SFZ_LEVEL_SAMPLE] = sample_index;
1354
1355 g_free(sfz_file->name_selected[AGS_SFZ_LEVEL_SAMPLE]);
1356
1357 sfz_file->name_selected[AGS_SFZ_LEVEL_SAMPLE] = filename;
1358
1359 /* container */
1360 sfz_file->current_sample = (AgsSFZSample *) list->data;
1361
1362 g_rec_mutex_unlock(sfz_file_mutex);
1363 }
1364
1365 g_list_free_full(start_list,
1366 g_object_unref);
1367 }
1368
1369 return(success);
1370 }
1371
1372 /**
1373 * ags_sfz_file_get_range:
1374 * @sfz_file: the #AgsSFZFile
1375 * @hikey: (out): the return location of key high
1376 * @lokey: (out): the return location of key low
1377 *
1378 * Get range of @sfz_file, set return location @hikey and @lokey.
1379 *
1380 * Since: 3.0.0
1381 */
1382 void
ags_sfz_file_get_range(AgsSFZFile * sfz_file,glong * hikey,glong * lokey)1383 ags_sfz_file_get_range(AgsSFZFile *sfz_file,
1384 glong *hikey, glong *lokey)
1385 {
1386 GList *start_group, *group;
1387 GList *start_region, *region;
1388
1389 gchar *str;
1390
1391 glong upper, lower;
1392 glong value;
1393 int retval;
1394
1395 if(!AGS_IS_SFZ_FILE(sfz_file)){
1396 return;
1397 }
1398
1399 g_object_get(sfz_file,
1400 "group", &start_group,
1401 "region", &start_region,
1402 NULL);
1403
1404 upper = 0;
1405 lower = AGS_SFZ_FILE_LOOP_MAX;
1406
1407 group = start_group;
1408
1409 while(group != NULL){
1410 /* hikey */
1411 str = ags_sfz_group_lookup_control(group->data,
1412 "hikey");
1413
1414 value = 0;
1415
1416 if(str != NULL){
1417 retval = sscanf(str, "%3ld", &value);
1418
1419 if(retval <= 0){
1420 glong tmp;
1421 guint tmp_retval;
1422
1423 tmp_retval = ags_diatonic_scale_note_to_midi_key(str,
1424 &tmp);
1425
1426 if(retval > 0){
1427 value = tmp;
1428 }
1429 }
1430 }
1431
1432 if(value > upper){
1433 upper = value;
1434 }
1435
1436 /* lokey */
1437 str = ags_sfz_group_lookup_control(group->data,
1438 "hikey");
1439
1440 value = AGS_SFZ_FILE_LOOP_MAX;
1441
1442 if(str != NULL){
1443 retval = sscanf(str, "%3ld", &value);
1444
1445 if(retval <= 0){
1446 glong tmp;
1447 guint tmp_retval;
1448
1449 tmp_retval = ags_diatonic_scale_note_to_midi_key(str,
1450 &tmp);
1451
1452 if(retval > 0){
1453 value = tmp;
1454 }
1455 }
1456 }
1457
1458 if(value < lower){
1459 lower = value;
1460 }
1461
1462 /* iterate */
1463 group = group->next;
1464 }
1465
1466 region = start_region;
1467
1468 while(region != NULL){
1469 /* hikey */
1470 str = ags_sfz_region_lookup_control(region->data,
1471 "hikey");
1472
1473 value = 0;
1474
1475 if(str != NULL){
1476 retval = sscanf(str, "%3ld", &value);
1477
1478 if(retval <= 0){
1479 glong tmp;
1480 guint tmp_retval;
1481
1482 tmp_retval = ags_diatonic_scale_note_to_midi_key(str,
1483 &tmp);
1484
1485 if(retval > 0){
1486 value = tmp;
1487 }
1488 }
1489 }
1490
1491 if(value > upper){
1492 upper = value;
1493 }
1494
1495 /* lokey */
1496 str = ags_sfz_region_lookup_control(region->data,
1497 "hikey");
1498
1499 value = AGS_SFZ_FILE_LOOP_MAX;
1500
1501 if(str != NULL){
1502 retval = sscanf(str, "%3ld", &value);
1503
1504 if(retval <= 0){
1505 glong tmp;
1506 guint tmp_retval;
1507
1508 tmp_retval = ags_diatonic_scale_note_to_midi_key(str,
1509 &tmp);
1510
1511 if(retval > 0){
1512 value = tmp;
1513 }
1514 }
1515 }
1516
1517 if(value < lower){
1518 lower = value;
1519 }
1520
1521 /* iterate */
1522 region = region->next;
1523 }
1524
1525 /* set return location */
1526 if(lokey < hikey){
1527 if(lokey != NULL){
1528 lokey[0] = lower;
1529 }
1530
1531 if(hikey != NULL){
1532 hikey[0] = upper;
1533 }
1534 }else{
1535 if(lokey != NULL){
1536 lokey[0] = 49;
1537 }
1538
1539 if(hikey != NULL){
1540 hikey[0] = 49;
1541 }
1542 }
1543 }
1544
1545 /**
1546 * ags_sfz_file_check_suffix:
1547 * @filename: the filename
1548 *
1549 * Check @filename's suffix to be supported.
1550 *
1551 * Returns: %TRUE if supported, else %FALSE
1552 *
1553 * Since: 3.0.0
1554 */
1555 gboolean
ags_sfz_file_check_suffix(gchar * filename)1556 ags_sfz_file_check_suffix(gchar *filename)
1557 {
1558 if(g_str_has_suffix(filename, ".sfz")){
1559 return(TRUE);
1560 }
1561
1562 return(FALSE);
1563 }
1564
1565 gchar*
ags_sfz_file_parse_skip_comments_and_blanks(gchar * buffer,gsize buffer_length,gchar ** iter)1566 ags_sfz_file_parse_skip_comments_and_blanks(gchar *buffer, gsize buffer_length,
1567 gchar **iter)
1568 {
1569 gchar *look_ahead;
1570 gchar *next;
1571
1572 if(iter == NULL){
1573 return(NULL);
1574 }
1575
1576 look_ahead = *iter;
1577
1578 if(look_ahead == NULL){
1579 return(NULL);
1580 }
1581
1582 /* skip whitespaces and comments */
1583 for(; (look_ahead < &(buffer[buffer_length])) && *look_ahead != '\0';){
1584 /* skip comments */
1585 if(buffer == look_ahead){
1586 if(look_ahead + 1 < &(buffer[buffer_length]) && buffer[0] == '/' && buffer[1] == '/'){
1587 next = strchr(look_ahead, '\n');
1588
1589 if(next != NULL){
1590 look_ahead = next + 1;
1591 }else{
1592 look_ahead = &(buffer[buffer_length]);
1593
1594 break;
1595 }
1596
1597 continue;
1598 }
1599 }else if(buffer[look_ahead - buffer - 1] == '\n' && look_ahead + 1 < &(buffer[buffer_length]) && look_ahead[0] == '/' && look_ahead[1] == '/'){
1600 next = strchr(look_ahead, '\n');
1601
1602 if(next != NULL){
1603 look_ahead = next + 1;
1604 }else{
1605 look_ahead = &(buffer[buffer_length]);
1606
1607 break;
1608 }
1609
1610 continue;
1611 }
1612
1613 /* spaces */
1614 if(!(look_ahead[0] == ' ' || look_ahead[0] == '\t' || look_ahead[0] == '\n' || look_ahead[0] == '\r')){
1615 break;
1616 }else{
1617 look_ahead++;
1618 }
1619 }
1620
1621 return(look_ahead);
1622 }
1623
1624 /**
1625 * ags_sfz_file_parse:
1626 * @sfz_file: the #AgsSFZFile
1627 *
1628 * Parse @sfz_file.
1629 *
1630 * Since: 3.0.0
1631 */
1632 void
ags_sfz_file_parse(AgsSFZFile * sfz_file)1633 ags_sfz_file_parse(AgsSFZFile *sfz_file)
1634 {
1635 AgsSFZGroup *current_group;
1636 AgsSFZRegion *current_region;
1637 AgsSFZSample *current_sample;
1638
1639 FILE *file;
1640
1641 struct stat *sb;
1642
1643 GList *start_list, *list;
1644
1645 regmatch_t match_arr[2];
1646
1647 gchar *filename;
1648 gchar *buffer, *iter;
1649
1650 size_t n_read;
1651 gint nth_group;
1652 gint nth_region;
1653 gboolean group_active;
1654 gboolean region_active;
1655 gboolean sample_active;
1656
1657 GRecMutex *sfz_file_mutex;
1658
1659 static regex_t opcode_regex;
1660 static regex_t opcode_regex_next;
1661
1662 static const gchar *opcode_pattern = "^([a-zA-Z_]+)\\=";
1663 static const gchar *opcode_pattern_next = "([a-zA-Z_]+)\\=";
1664
1665 static const size_t max_matches = 2;
1666 static gboolean regex_compiled = FALSE;
1667
1668 if(!AGS_IS_SFZ_FILE(sfz_file)){
1669 return;
1670 }
1671
1672 g_message("SFZ parse");
1673
1674 /* get sfz_file mutex */
1675 sfz_file_mutex = AGS_SFZ_FILE_GET_OBJ_MUTEX(sfz_file);
1676
1677 /* stat file */
1678 g_object_get(sfz_file,
1679 "filename", &filename,
1680 NULL);
1681
1682 sb = (struct stat *) malloc(sizeof(struct stat));
1683 stat(filename,
1684 sb);
1685
1686 if(sb->st_size == 0){
1687 g_free(filename);
1688
1689 free(sb);
1690
1691 return;
1692 }
1693
1694 g_free(filename);
1695
1696 /* read SFZ */
1697 g_rec_mutex_lock(sfz_file_mutex);
1698
1699 file = sfz_file->file;
1700
1701 g_rec_mutex_unlock(sfz_file_mutex);
1702
1703 buffer = (gchar *) malloc((sb->st_size + 1) * sizeof(gchar));
1704
1705 if(buffer == NULL){
1706 free(sb);
1707
1708 return;
1709 }
1710
1711 n_read = fread(buffer, sizeof(gchar), sb->st_size, file);
1712
1713 if(n_read != sb->st_size){
1714 g_critical("number of read bytes doesn't match buffer size");
1715 }
1716
1717 buffer[sb->st_size] = '\0';
1718
1719 iter = buffer;
1720
1721 current_group = NULL;
1722 current_region = NULL;
1723 current_sample = NULL;
1724
1725 nth_group = -1;
1726 nth_region = -1;
1727
1728 group_active = FALSE;
1729 region_active = FALSE;
1730 sample_active = FALSE;
1731
1732 g_mutex_lock(®ex_mutex);
1733
1734 if(!regex_compiled){
1735 regex_compiled = TRUE;
1736
1737 ags_regcomp(&opcode_regex, opcode_pattern, REG_EXTENDED);
1738 ags_regcomp(&opcode_regex_next, opcode_pattern_next, REG_EXTENDED);
1739 }
1740
1741 g_mutex_unlock(®ex_mutex);
1742
1743 do{
1744 /* skip blanks and comments */
1745 iter = ags_sfz_file_parse_skip_comments_and_blanks(buffer, sb->st_size,
1746 &iter);
1747
1748 if(iter >= &(buffer[sb->st_size])){
1749 break;
1750 }
1751
1752 if(!g_ascii_strncasecmp(iter,
1753 "<group>",
1754 7)){
1755 g_message("SFZ group");
1756
1757 nth_group++;
1758
1759 group_active = TRUE;
1760 region_active = FALSE;
1761 sample_active = FALSE;
1762
1763 current_group = ags_sfz_group_new();
1764 g_object_set(sfz_file,
1765 "group", current_group,
1766 NULL);
1767
1768 iter += 7;
1769 }else if(!g_ascii_strncasecmp(iter,
1770 "<region>",
1771 8)){
1772 g_message("SFZ region");
1773
1774 nth_region++;
1775
1776 region_active = TRUE;
1777 sample_active = FALSE;
1778
1779 current_region = ags_sfz_region_new();
1780 g_object_set(sfz_file,
1781 "region", current_region,
1782 NULL);
1783
1784 iter += 8;
1785 }else if(ags_regexec(&opcode_regex, iter, max_matches, match_arr, 0) == 0){
1786 gchar *opcode;
1787 gchar *str;
1788 gchar *next, *tmp0_next, *tmp1_next;
1789
1790 iter += match_arr[1].rm_so;
1791
1792 opcode = g_strndup(iter,
1793 match_arr[1].rm_eo - match_arr[1].rm_so);
1794
1795 iter += strlen(opcode) + 1;
1796
1797 if(ags_regexec(&opcode_regex_next, iter, max_matches, match_arr, 0) == 0){
1798 tmp0_next = strchr(iter, '\n');
1799 tmp1_next = strchr(iter, '\r');
1800
1801 if((tmp0_next != NULL || tmp1_next != NULL) &&
1802 ((tmp0_next != NULL && tmp0_next < iter + match_arr[1].rm_so) || (tmp1_next != NULL && tmp1_next < iter + match_arr[1].rm_so))){
1803 if(tmp0_next != NULL && (tmp1_next == NULL || tmp0_next < tmp1_next)){
1804 next = tmp0_next;
1805 }else{
1806 next = tmp1_next;
1807 }
1808 }else{
1809 next = iter + match_arr[1].rm_so;
1810 }
1811 }else{
1812 tmp0_next = strchr(iter, '\n');
1813 tmp1_next = strchr(iter, '\r');
1814
1815 if(tmp0_next != NULL || tmp1_next != NULL){
1816 if(tmp0_next != NULL && (tmp1_next == NULL || tmp0_next < tmp1_next)){
1817 next = tmp0_next;
1818 }else{
1819 next = tmp1_next;
1820 }
1821 }else{
1822 next = &(buffer[sb->st_size]);
1823 }
1824 }
1825
1826 while(next > iter){
1827 if((next - 1)[0] == ' '){
1828 next--;
1829 }else{
1830 break;
1831 }
1832 }
1833
1834 str = g_strndup(iter,
1835 next - iter);
1836
1837 iter = next;
1838
1839 g_message("opcode - %s=%s", opcode, str);
1840
1841 if(!g_ascii_strncasecmp(opcode,
1842 "sample",
1843 6)){
1844 gchar *filename;
1845 gchar *tmp;
1846
1847 gboolean success;
1848
1849 tmp = str;
1850
1851 while((tmp = strchr(tmp, '\\')) != NULL){
1852 tmp[0] = '/';
1853
1854 tmp++;
1855 }
1856
1857 sample_active = TRUE;
1858
1859 if(g_path_is_absolute(str)){
1860 filename = g_strdup(str);
1861 }else{
1862 gchar *path;
1863
1864 path = g_path_get_dirname(sfz_file->filename);
1865
1866 filename = g_strdup_printf("%s/%s",
1867 path,
1868 str);
1869 }
1870
1871 current_sample = ags_sfz_sample_new();
1872 g_object_set(current_sample,
1873 "group", current_group,
1874 "region", current_region,
1875 NULL);
1876
1877 success = ags_sound_resource_open(AGS_SOUND_RESOURCE(current_sample),
1878 filename);
1879
1880 if(!success){
1881 g_message("failed to open %s", filename);
1882 }
1883
1884 g_object_set(sfz_file,
1885 "sample", current_sample,
1886 NULL);
1887
1888 if(region_active){
1889 g_object_set(current_region,
1890 "sample", current_sample,
1891 NULL);
1892 }else if(group_active){
1893 g_object_set(current_group,
1894 "sample", current_sample,
1895 NULL);
1896 }
1897
1898 g_free(filename);
1899 }
1900
1901 if(region_active){
1902 ags_sfz_region_insert_control(current_region,
1903 opcode, str);
1904 }else if(group_active){
1905 ags_sfz_group_insert_control(current_group,
1906 opcode, str);
1907 }else{
1908 g_warning("SFZ neither group nor region defined");
1909 }
1910 }else{
1911 /* bad byte */
1912 iter++;
1913 }
1914 }while(iter < &(buffer[sb->st_size]));
1915
1916 free(sb);
1917 free(buffer);
1918
1919 /* apply loop start/end */
1920 g_object_get(sfz_file,
1921 "sample", &start_list,
1922 NULL);
1923
1924 list = start_list;
1925
1926 while(list != NULL){
1927 AgsSFZGroup *group;
1928 AgsSFZRegion *region;
1929 AgsSFZSample *sample;
1930
1931 guint loop_start, loop_end;
1932
1933 sample = (AgsSFZSample *) list->data;
1934
1935 loop_start = 0;
1936 loop_end = 0;
1937
1938 g_object_get(sample,
1939 "group", &group,
1940 "region", ®ion,
1941 NULL);
1942
1943 /* check group */
1944 if(group != NULL){
1945 gchar *str;
1946
1947 str = ags_sfz_group_lookup_control(group,
1948 "loop_start");
1949
1950 if(str != NULL){
1951 loop_start = g_ascii_strtoull(str,
1952 NULL,
1953 10);
1954
1955 g_free(str);
1956 }
1957
1958 str = ags_sfz_group_lookup_control(group,
1959 "loop_end");
1960
1961 if(str != NULL){
1962 loop_end = g_ascii_strtoull(str,
1963 NULL,
1964 10);
1965
1966 g_free(str);
1967 }
1968 }
1969
1970 /* check region */
1971 if(region != NULL){
1972 gchar *str;
1973
1974 str = ags_sfz_region_lookup_control(region,
1975 "loop_start");
1976
1977 if(str != NULL){
1978 loop_start = g_ascii_strtoull(str,
1979 NULL,
1980 10);
1981
1982 g_free(str);
1983 }
1984
1985 str = ags_sfz_region_lookup_control(region,
1986 "loop_end");
1987
1988 if(str != NULL){
1989 loop_end = g_ascii_strtoull(str,
1990 NULL,
1991 10);
1992
1993 g_free(str);
1994 }
1995 }
1996
1997 g_object_set(sample,
1998 "loop-start", loop_start,
1999 "loop-end", loop_end,
2000 NULL);
2001
2002 /* iterate */
2003 list = list->next;
2004 }
2005
2006 g_list_free_full(start_list,
2007 g_object_unref);
2008 }
2009
2010 /**
2011 * ags_sfz_file_new:
2012 *
2013 * Creates an #AgsSFZFile.
2014 *
2015 * Returns: an empty #AgsSFZFile.
2016 *
2017 * Since: 3.0.0
2018 */
2019 AgsSFZFile*
ags_sfz_file_new()2020 ags_sfz_file_new()
2021 {
2022 AgsSFZFile *sfz_file;
2023
2024 sfz_file = (AgsSFZFile *) g_object_new(AGS_TYPE_SFZ_FILE,
2025 NULL);
2026
2027 return(sfz_file);
2028 }
2029