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_sample.h>
21
22 #include <ags/audio/ags_diatonic_scale.h>
23 #include <ags/audio/ags_audio_signal.h>
24 #include <ags/audio/ags_audio_buffer_util.h>
25
26 #include <ags/audio/file/ags_sound_resource.h>
27 #include <ags/audio/file/ags_sfz_group.h>
28 #include <ags/audio/file/ags_sfz_region.h>
29
30 #include <stdlib.h>
31
32 #include <ags/i18n.h>
33
34 void ags_sfz_sample_class_init(AgsSFZSampleClass *sfz_sample);
35 void ags_sfz_sample_connectable_interface_init(AgsConnectableInterface *connectable);
36 void ags_sfz_sample_sound_resource_interface_init(AgsSoundResourceInterface *sound_resource);
37 void ags_sfz_sample_init(AgsSFZSample *sfz_sample);
38 void ags_sfz_sample_set_property(GObject *gobject,
39 guint prop_id,
40 const GValue *value,
41 GParamSpec *param_spec);
42 void ags_sfz_sample_get_property(GObject *gobject,
43 guint prop_id,
44 GValue *value,
45 GParamSpec *param_spec);
46 void ags_sfz_sample_dispose(GObject *gobject);
47 void ags_sfz_sample_finalize(GObject *gobject);
48
49 AgsUUID* ags_sfz_sample_get_uuid(AgsConnectable *connectable);
50 gboolean ags_sfz_sample_has_resource(AgsConnectable *connectable);
51 gboolean ags_sfz_sample_is_ready(AgsConnectable *connectable);
52 void ags_sfz_sample_add_to_registry(AgsConnectable *connectable);
53 void ags_sfz_sample_remove_from_registry(AgsConnectable *connectable);
54 xmlNode* ags_sfz_sample_list_resource(AgsConnectable *connectable);
55 xmlNode* ags_sfz_sample_xml_compose(AgsConnectable *connectable);
56 void ags_sfz_sample_xml_parse(AgsConnectable *connectable,
57 xmlNode *node);
58 gboolean ags_sfz_sample_is_connected(AgsConnectable *connectable);
59 void ags_sfz_sample_connect(AgsConnectable *connectable);
60 void ags_sfz_sample_disconnect(AgsConnectable *connectable);
61
62 gboolean ags_sfz_sample_open(AgsSoundResource *sound_resource,
63 gchar *filename);
64 gboolean ags_sfz_sample_rw_open(AgsSoundResource *sound_resource,
65 gchar *filename,
66 guint audio_channels, guint samplerate,
67 gboolean create);
68 gboolean ags_sfz_sample_info(AgsSoundResource *sound_resource,
69 guint *frame_count,
70 guint *loop_start, guint *loop_end);
71 void ags_sfz_sample_set_presets(AgsSoundResource *sound_resource,
72 guint channels,
73 guint samplerate,
74 guint buffer_size,
75 guint format);
76 void ags_sfz_sample_get_presets(AgsSoundResource *sound_resource,
77 guint *channels,
78 guint *samplerate,
79 guint *buffer_size,
80 guint *format);
81 guint ags_sfz_sample_read(AgsSoundResource *sound_resource,
82 void *dbuffer, guint daudio_channels,
83 guint audio_channel,
84 guint frame_count, guint format);
85 void ags_sfz_sample_write(AgsSoundResource *sound_resource,
86 void *sbuffer, guint saudio_channels,
87 guint audio_channel,
88 guint frame_count, guint format);
89 void ags_sfz_sample_flush(AgsSoundResource *sound_resource);
90 void ags_sfz_sample_seek(AgsSoundResource *sound_resource,
91 gint64 frame_count, gint whence);
92 void ags_sfz_sample_close(AgsSoundResource *sound_resource);
93
94 /**
95 * SECTION:ags_sfz_sample
96 * @short_description: interfacing SFZ samples
97 * @title: AgsSFZSample
98 * @section_id:
99 * @include: ags/audio/file/ags_sfz_sample.h
100 *
101 * #AgsSFZSample is the base object to ineract with SFZ samples.
102 */
103
104 enum{
105 PROP_0,
106 PROP_AUDIO_CHANNELS,
107 PROP_FILENAME,
108 PROP_BUFFER_SIZE,
109 PROP_FORMAT,
110 PROP_LOOP_START,
111 PROP_LOOP_END,
112 PROP_GROUP,
113 PROP_REGION,
114 };
115
116 static gpointer ags_sfz_sample_parent_class = NULL;
117
118 GType
ags_sfz_sample_get_type()119 ags_sfz_sample_get_type()
120 {
121 static volatile gsize g_define_type_id__volatile = 0;
122
123 if(g_once_init_enter (&g_define_type_id__volatile)){
124 GType ags_type_sfz_sample = 0;
125
126 static const GTypeInfo ags_sfz_sample_info = {
127 sizeof(AgsSFZSampleClass),
128 NULL, /* base_init */
129 NULL, /* base_finalize */
130 (GClassInitFunc) ags_sfz_sample_class_init,
131 NULL, /* class_finalize */
132 NULL, /* class_data */
133 sizeof(AgsSFZSample),
134 0, /* n_preallocs */
135 (GInstanceInitFunc) ags_sfz_sample_init,
136 };
137
138 static const GInterfaceInfo ags_connectable_interface_info = {
139 (GInterfaceInitFunc) ags_sfz_sample_connectable_interface_init,
140 NULL, /* interface_finalize */
141 NULL, /* interface_data */
142 };
143
144 static const GInterfaceInfo ags_sound_resource_interface_info = {
145 (GInterfaceInitFunc) ags_sfz_sample_sound_resource_interface_init,
146 NULL, /* interface_finalize */
147 NULL, /* interface_data */
148 };
149
150 ags_type_sfz_sample = g_type_register_static(G_TYPE_OBJECT,
151 "AgsSFZSample",
152 &ags_sfz_sample_info,
153 0);
154
155 g_type_add_interface_static(ags_type_sfz_sample,
156 AGS_TYPE_CONNECTABLE,
157 &ags_connectable_interface_info);
158
159 g_type_add_interface_static(ags_type_sfz_sample,
160 AGS_TYPE_SOUND_RESOURCE,
161 &ags_sound_resource_interface_info);
162
163 g_once_init_leave(&g_define_type_id__volatile, ags_type_sfz_sample);
164 }
165
166 return g_define_type_id__volatile;
167 }
168
169 void
ags_sfz_sample_class_init(AgsSFZSampleClass * sfz_sample)170 ags_sfz_sample_class_init(AgsSFZSampleClass *sfz_sample)
171 {
172 GObjectClass *gobject;
173
174 GParamSpec *param_spec;
175
176 ags_sfz_sample_parent_class = g_type_class_peek_parent(sfz_sample);
177
178 gobject = (GObjectClass *) sfz_sample;
179
180 gobject->set_property = ags_sfz_sample_set_property;
181 gobject->get_property = ags_sfz_sample_get_property;
182
183 gobject->dispose = ags_sfz_sample_dispose;
184 gobject->finalize = ags_sfz_sample_finalize;
185
186 /* properties */
187 /**
188 * AgsSFZSample:audio-channels:
189 *
190 * The audio channels to be used.
191 *
192 * Since: 3.0.0
193 */
194 param_spec = g_param_spec_uint("audio-channels",
195 i18n_pspec("using audio channels"),
196 i18n_pspec("The audio channels to be used"),
197 0,
198 G_MAXUINT32,
199 0,
200 G_PARAM_READABLE | G_PARAM_WRITABLE);
201 g_object_class_install_property(gobject,
202 PROP_AUDIO_CHANNELS,
203 param_spec);
204
205 /**
206 * AgsSFZSample:filename:
207 *
208 * The filename to be used.
209 *
210 * Since: 3.0.0
211 */
212 param_spec = g_param_spec_string("filename",
213 i18n_pspec("using filename"),
214 i18n_pspec("The filename to be used"),
215 NULL,
216 G_PARAM_READABLE | G_PARAM_WRITABLE);
217 g_object_class_install_property(gobject,
218 PROP_FILENAME,
219 param_spec);
220
221 /**
222 * AgsSFZSample:buffer-size:
223 *
224 * The buffer size to be used.
225 *
226 * Since: 3.0.0
227 */
228 param_spec = g_param_spec_uint("buffer-size",
229 i18n_pspec("using buffer size"),
230 i18n_pspec("The buffer size to be used"),
231 0,
232 G_MAXUINT32,
233 0,
234 G_PARAM_READABLE | G_PARAM_WRITABLE);
235 g_object_class_install_property(gobject,
236 PROP_BUFFER_SIZE,
237 param_spec);
238
239 /**
240 * AgsSFZSample:format:
241 *
242 * The format to be used.
243 *
244 * Since: 3.0.0
245 */
246 param_spec = g_param_spec_uint("format",
247 i18n_pspec("using format"),
248 i18n_pspec("The format to be used"),
249 0,
250 G_MAXUINT32,
251 0,
252 G_PARAM_READABLE | G_PARAM_WRITABLE);
253 g_object_class_install_property(gobject,
254 PROP_FORMAT,
255 param_spec);
256
257 /**
258 * AgsSFZSample:loop-start:
259 *
260 * The loop start to be used.
261 *
262 * Since: 3.0.0
263 */
264 param_spec = g_param_spec_uint("loop-start",
265 i18n_pspec("using loop start"),
266 i18n_pspec("The loop start to be used"),
267 0,
268 G_MAXUINT32,
269 0,
270 G_PARAM_READABLE | G_PARAM_WRITABLE);
271 g_object_class_install_property(gobject,
272 PROP_LOOP_START,
273 param_spec);
274
275 /**
276 * AgsSFZSample:loop-end:
277 *
278 * The loop end to be used.
279 *
280 * Since: 3.0.0
281 */
282 param_spec = g_param_spec_uint("loop-end",
283 i18n_pspec("using loop end"),
284 i18n_pspec("The loop end to be used"),
285 0,
286 G_MAXUINT32,
287 0,
288 G_PARAM_READABLE | G_PARAM_WRITABLE);
289 g_object_class_install_property(gobject,
290 PROP_LOOP_END,
291 param_spec);
292
293 /**
294 * AgsSFZSample:group:
295 *
296 * The group assigned with.
297 *
298 * Since: 3.0.0
299 */
300 param_spec = g_param_spec_object("group",
301 i18n_pspec("assigned group"),
302 i18n_pspec("The group it is assigned with"),
303 AGS_TYPE_SFZ_GROUP,
304 G_PARAM_READABLE | G_PARAM_WRITABLE);
305 g_object_class_install_property(gobject,
306 PROP_GROUP,
307 param_spec);
308
309 /**
310 * AgsSFZSample:region:
311 *
312 * The region assigned with.
313 *
314 * Since: 3.0.0
315 */
316 param_spec = g_param_spec_object("region",
317 i18n_pspec("assigned region"),
318 i18n_pspec("The region it is assigned with"),
319 AGS_TYPE_SFZ_REGION,
320 G_PARAM_READABLE | G_PARAM_WRITABLE);
321 g_object_class_install_property(gobject,
322 PROP_REGION,
323 param_spec);
324 }
325
326 void
ags_sfz_sample_connectable_interface_init(AgsConnectableInterface * connectable)327 ags_sfz_sample_connectable_interface_init(AgsConnectableInterface *connectable)
328 {
329 connectable->get_uuid = ags_sfz_sample_get_uuid;
330 connectable->has_resource = ags_sfz_sample_has_resource;
331 connectable->is_ready = ags_sfz_sample_is_ready;
332
333 connectable->add_to_registry = ags_sfz_sample_add_to_registry;
334 connectable->remove_from_registry = ags_sfz_sample_remove_from_registry;
335
336 connectable->list_resource = ags_sfz_sample_list_resource;
337 connectable->xml_compose = ags_sfz_sample_xml_compose;
338 connectable->xml_parse = ags_sfz_sample_xml_parse;
339
340 connectable->is_connected = ags_sfz_sample_is_connected;
341
342 connectable->connect = ags_sfz_sample_connect;
343 connectable->disconnect = ags_sfz_sample_disconnect;
344
345 connectable->connect_connection = NULL;
346 connectable->disconnect_connection = NULL;
347 }
348
349 void
ags_sfz_sample_sound_resource_interface_init(AgsSoundResourceInterface * sound_resource)350 ags_sfz_sample_sound_resource_interface_init(AgsSoundResourceInterface *sound_resource)
351 {
352 sound_resource->open = ags_sfz_sample_open;
353 sound_resource->rw_open = ags_sfz_sample_rw_open;
354
355 sound_resource->load = NULL;
356
357 sound_resource->info = ags_sfz_sample_info;
358
359 sound_resource->set_presets = ags_sfz_sample_set_presets;
360 sound_resource->get_presets = ags_sfz_sample_get_presets;
361
362 sound_resource->read = ags_sfz_sample_read;
363
364 sound_resource->write = ags_sfz_sample_write;
365 sound_resource->flush = ags_sfz_sample_flush;
366
367 sound_resource->seek = ags_sfz_sample_seek;
368
369 sound_resource->close = ags_sfz_sample_close;
370 }
371
372 void
ags_sfz_sample_init(AgsSFZSample * sfz_sample)373 ags_sfz_sample_init(AgsSFZSample *sfz_sample)
374 {
375 AgsConfig *config;
376
377 sfz_sample->flags = 0;
378
379 /* add audio file mutex */
380 g_rec_mutex_init(&(sfz_sample->obj_mutex));
381
382 /* uuid */
383 sfz_sample->uuid = ags_uuid_alloc();
384 ags_uuid_generate(sfz_sample->uuid);
385
386 config = ags_config_get_instance();
387
388 sfz_sample->filename = NULL;
389
390 sfz_sample->audio_channels = 1;
391 sfz_sample->audio_channel_written = (gint64 *) malloc(sfz_sample->audio_channels * sizeof(gint64));
392
393 sfz_sample->audio_channel_written[0] = -1;
394
395 sfz_sample->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
396 sfz_sample->format = AGS_SOUNDCARD_DOUBLE;
397
398 sfz_sample->loop_start = 0;
399 sfz_sample->loop_end = 0;
400
401 sfz_sample->offset = 0;
402 sfz_sample->buffer_offset = 0;
403
404 sfz_sample->full_buffer = NULL;
405 sfz_sample->buffer = ags_stream_alloc(sfz_sample->audio_channels * sfz_sample->buffer_size,
406 sfz_sample->format);
407
408 sfz_sample->pointer = NULL;
409 sfz_sample->current = NULL;
410 sfz_sample->length = 0;
411
412 sfz_sample->info = NULL;
413 sfz_sample->file = NULL;
414
415 sfz_sample->group = NULL;
416 sfz_sample->region = NULL;
417 }
418
419 void
ags_sfz_sample_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)420 ags_sfz_sample_set_property(GObject *gobject,
421 guint prop_id,
422 const GValue *value,
423 GParamSpec *param_spec)
424 {
425 AgsSFZSample *sfz_sample;
426
427 GRecMutex *sfz_sample_mutex;
428
429 sfz_sample = AGS_SFZ_SAMPLE(gobject);
430
431 /* get sfz sample mutex */
432 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
433
434 switch(prop_id){
435 case PROP_AUDIO_CHANNELS:
436 {
437 guint audio_channels;
438 guint i;
439
440 audio_channels = g_value_get_uint(value);
441
442 g_rec_mutex_lock(sfz_sample_mutex);
443
444 if(audio_channels == sfz_sample->audio_channels){
445 g_rec_mutex_unlock(sfz_sample_mutex);
446
447 return;
448 }
449
450 ags_stream_free(sfz_sample->buffer);
451
452 if(audio_channels > 0){
453 sfz_sample->audio_channel_written = (gint64 *) realloc(sfz_sample->audio_channel_written,
454 audio_channels * sizeof(gint64));
455
456 for(i = sfz_sample->audio_channels; i < audio_channels; i++){
457 sfz_sample->audio_channel_written[i] = -1;
458 }
459 }else{
460 free(sfz_sample->audio_channel_written);
461 }
462
463 sfz_sample->audio_channels = audio_channels;
464
465 sfz_sample->buffer = ags_stream_alloc(sfz_sample->audio_channels * sfz_sample->buffer_size,
466 sfz_sample->format);
467
468 g_rec_mutex_unlock(sfz_sample_mutex);
469 }
470 break;
471 case PROP_FILENAME:
472 {
473 gchar *filename;
474
475 filename = g_value_get_string(value);
476
477 g_rec_mutex_lock(sfz_sample_mutex);
478
479 if(filename == sfz_sample->filename){
480 g_rec_mutex_unlock(sfz_sample_mutex);
481
482 return;
483 }
484
485 g_free(sfz_sample->filename);
486
487 sfz_sample->filename = g_strdup(filename);
488
489 g_rec_mutex_unlock(sfz_sample_mutex);
490 }
491 break;
492 case PROP_BUFFER_SIZE:
493 {
494 guint buffer_size;
495
496 buffer_size = g_value_get_uint(value);
497
498 g_rec_mutex_lock(sfz_sample_mutex);
499
500 if(buffer_size == sfz_sample->buffer_size){
501 g_rec_mutex_unlock(sfz_sample_mutex);
502
503 return;
504 }
505
506 ags_stream_free(sfz_sample->buffer);
507
508 sfz_sample->buffer_size = buffer_size;
509 sfz_sample->buffer = ags_stream_alloc(sfz_sample->audio_channels * sfz_sample->buffer_size,
510 sfz_sample->format);
511
512 g_rec_mutex_unlock(sfz_sample_mutex);
513 }
514 break;
515 case PROP_FORMAT:
516 {
517 guint format;
518
519 format = g_value_get_uint(value);
520
521 g_rec_mutex_lock(sfz_sample_mutex);
522
523 if(format == sfz_sample->format){
524 g_rec_mutex_unlock(sfz_sample_mutex);
525
526 return;
527 }
528
529 ags_stream_free(sfz_sample->buffer);
530
531 sfz_sample->format = format;
532 sfz_sample->buffer = ags_stream_alloc(sfz_sample->audio_channels * sfz_sample->buffer_size,
533 sfz_sample->format);
534
535 g_rec_mutex_unlock(sfz_sample_mutex);
536 }
537 break;
538 case PROP_LOOP_START:
539 {
540 gint loop_start;
541
542 loop_start = g_value_get_uint(value);
543
544 g_rec_mutex_lock(sfz_sample_mutex);
545
546 if(loop_start == sfz_sample->loop_start){
547 g_rec_mutex_unlock(sfz_sample_mutex);
548
549 return;
550 }
551
552 sfz_sample->loop_start = loop_start;
553
554 g_rec_mutex_unlock(sfz_sample_mutex);
555 }
556 break;
557 case PROP_LOOP_END:
558 {
559 gint loop_end;
560
561 loop_end = g_value_get_uint(value);
562
563 g_rec_mutex_lock(sfz_sample_mutex);
564
565 if(loop_end == sfz_sample->loop_end){
566 g_rec_mutex_unlock(sfz_sample_mutex);
567
568 return;
569 }
570
571 sfz_sample->loop_end = loop_end;
572
573 g_rec_mutex_unlock(sfz_sample_mutex);
574 }
575 break;
576 case PROP_GROUP:
577 {
578 GObject *group;
579
580 group = g_value_get_object(value);
581
582 g_rec_mutex_lock(sfz_sample_mutex);
583
584 if(group == sfz_sample->group){
585 g_rec_mutex_unlock(sfz_sample_mutex);
586
587 return;
588 }
589
590 if(sfz_sample->group != NULL){
591 g_object_unref(sfz_sample->group);
592 }
593
594 if(group != NULL){
595 g_object_ref(group);
596 }
597
598 sfz_sample->group = group;
599
600 g_rec_mutex_unlock(sfz_sample_mutex);
601 }
602 break;
603 case PROP_REGION:
604 {
605 GObject *region;
606
607 region = g_value_get_object(value);
608
609 g_rec_mutex_lock(sfz_sample_mutex);
610
611 if(region == sfz_sample->region){
612 g_rec_mutex_unlock(sfz_sample_mutex);
613
614 return;
615 }
616
617 if(sfz_sample->region != NULL){
618 g_object_unref(sfz_sample->region);
619 }
620
621 if(region != NULL){
622 g_object_ref(region);
623 }
624
625 sfz_sample->region = region;
626
627 g_rec_mutex_unlock(sfz_sample_mutex);
628 }
629 break;
630 default:
631 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
632 }
633 }
634
635 void
ags_sfz_sample_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)636 ags_sfz_sample_get_property(GObject *gobject,
637 guint prop_id,
638 GValue *value,
639 GParamSpec *param_spec)
640 {
641 AgsSFZSample *sfz_sample;
642
643 GRecMutex *sfz_sample_mutex;
644
645 sfz_sample = (AgsSFZSample *) gobject;
646
647 /* get sfz sample mutex */
648 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
649
650 switch(prop_id){
651 case PROP_AUDIO_CHANNELS:
652 {
653 g_rec_mutex_lock(sfz_sample_mutex);
654
655 g_value_set_uint(value, sfz_sample->audio_channels);
656
657 g_rec_mutex_unlock(sfz_sample_mutex);
658 }
659 break;
660 case PROP_FILENAME:
661 {
662 g_rec_mutex_lock(sfz_sample_mutex);
663
664 g_value_set_string(value, sfz_sample->filename);
665
666 g_rec_mutex_unlock(sfz_sample_mutex);
667 }
668 break;
669 case PROP_BUFFER_SIZE:
670 {
671 g_rec_mutex_lock(sfz_sample_mutex);
672
673 g_value_set_uint(value, sfz_sample->buffer_size);
674
675 g_rec_mutex_unlock(sfz_sample_mutex);
676 }
677 break;
678 case PROP_FORMAT:
679 {
680 g_rec_mutex_lock(sfz_sample_mutex);
681
682 g_value_set_uint(value, sfz_sample->format);
683
684 g_rec_mutex_unlock(sfz_sample_mutex);
685 }
686 break;
687 case PROP_LOOP_START:
688 {
689 g_rec_mutex_lock(sfz_sample_mutex);
690
691 g_value_set_uint(value, sfz_sample->loop_start);
692
693 g_rec_mutex_unlock(sfz_sample_mutex);
694 }
695 break;
696 case PROP_LOOP_END:
697 {
698 g_rec_mutex_lock(sfz_sample_mutex);
699
700 g_value_set_uint(value, sfz_sample->loop_end);
701
702 g_rec_mutex_unlock(sfz_sample_mutex);
703 }
704 break;
705 case PROP_GROUP:
706 {
707 g_rec_mutex_lock(sfz_sample_mutex);
708
709 g_value_set_object(value, sfz_sample->group);
710
711 g_rec_mutex_unlock(sfz_sample_mutex);
712 }
713 break;
714 case PROP_REGION:
715 {
716 g_rec_mutex_lock(sfz_sample_mutex);
717
718 g_value_set_object(value, sfz_sample->region);
719
720 g_rec_mutex_unlock(sfz_sample_mutex);
721 }
722 break;
723 default:
724 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
725 }
726 }
727
728 void
ags_sfz_sample_dispose(GObject * gobject)729 ags_sfz_sample_dispose(GObject *gobject)
730 {
731 AgsSFZSample *sfz_sample;
732
733 sfz_sample = AGS_SFZ_SAMPLE(gobject);
734
735 if(sfz_sample->region != NULL){
736 g_object_unref(sfz_sample->region);
737
738 sfz_sample->region = NULL;
739 }
740
741 if(sfz_sample->group != NULL){
742 g_object_unref(sfz_sample->group);
743
744 sfz_sample->group = NULL;
745 }
746
747 /* call parent */
748 G_OBJECT_CLASS(ags_sfz_sample_parent_class)->dispose(gobject);
749 }
750
751 void
ags_sfz_sample_finalize(GObject * gobject)752 ags_sfz_sample_finalize(GObject *gobject)
753 {
754 AgsSFZSample *sfz_sample;
755
756 sfz_sample = AGS_SFZ_SAMPLE(gobject);
757
758 g_free(sfz_sample->filename);
759
760 ags_stream_free(sfz_sample->buffer);
761
762 if(sfz_sample->region != NULL){
763 g_object_unref(sfz_sample->region);
764 }
765
766 if(sfz_sample->group != NULL){
767 g_object_unref(sfz_sample->group);
768 }
769
770 /* call parent */
771 G_OBJECT_CLASS(ags_sfz_sample_parent_class)->finalize(gobject);
772 }
773
774 AgsUUID*
ags_sfz_sample_get_uuid(AgsConnectable * connectable)775 ags_sfz_sample_get_uuid(AgsConnectable *connectable)
776 {
777 AgsSFZSample *sfz_sample;
778
779 AgsUUID *ptr;
780
781 GRecMutex *sfz_sample_mutex;
782
783 sfz_sample = AGS_SFZ_SAMPLE(connectable);
784
785 /* get audio file mutex */
786 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
787
788 /* get UUID */
789 g_rec_mutex_lock(sfz_sample_mutex);
790
791 ptr = sfz_sample->uuid;
792
793 g_rec_mutex_unlock(sfz_sample_mutex);
794
795 return(ptr);
796 }
797
798 gboolean
ags_sfz_sample_has_resource(AgsConnectable * connectable)799 ags_sfz_sample_has_resource(AgsConnectable *connectable)
800 {
801 return(TRUE);
802 }
803
804 gboolean
ags_sfz_sample_is_ready(AgsConnectable * connectable)805 ags_sfz_sample_is_ready(AgsConnectable *connectable)
806 {
807 AgsSFZSample *sfz_sample;
808
809 gboolean is_ready;
810
811 sfz_sample = AGS_SFZ_SAMPLE(connectable);
812
813 /* check is ready */
814 is_ready = ags_sfz_sample_test_flags(sfz_sample, AGS_SFZ_SAMPLE_ADDED_TO_REGISTRY);
815
816 return(is_ready);
817 }
818
819 void
ags_sfz_sample_add_to_registry(AgsConnectable * connectable)820 ags_sfz_sample_add_to_registry(AgsConnectable *connectable)
821 {
822 AgsSFZSample *sfz_sample;
823
824 AgsRegistry *registry;
825 AgsRegistryEntry *entry;
826
827 AgsApplicationContext *application_context;
828
829 if(ags_connectable_is_ready(connectable)){
830 return;
831 }
832
833 sfz_sample = AGS_SFZ_SAMPLE(connectable);
834
835 ags_sfz_sample_set_flags(sfz_sample, AGS_SFZ_SAMPLE_ADDED_TO_REGISTRY);
836
837 application_context = ags_application_context_get_instance();
838
839 registry = (AgsRegistry *) ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
840
841 if(registry != NULL){
842 entry = ags_registry_entry_alloc(registry);
843 g_value_set_object(entry->entry,
844 (gpointer) sfz_sample);
845 ags_registry_add_entry(registry,
846 entry);
847 }
848 }
849
850 void
ags_sfz_sample_remove_from_registry(AgsConnectable * connectable)851 ags_sfz_sample_remove_from_registry(AgsConnectable *connectable)
852 {
853 if(!ags_connectable_is_ready(connectable)){
854 return;
855 }
856
857 //TODO:JK: implement me
858 }
859
860 xmlNode*
ags_sfz_sample_list_resource(AgsConnectable * connectable)861 ags_sfz_sample_list_resource(AgsConnectable *connectable)
862 {
863 xmlNode *node;
864
865 node = NULL;
866
867 //TODO:JK: implement me
868
869 return(node);
870 }
871
872 xmlNode*
ags_sfz_sample_xml_compose(AgsConnectable * connectable)873 ags_sfz_sample_xml_compose(AgsConnectable *connectable)
874 {
875 xmlNode *node;
876
877 node = NULL;
878
879 //TODO:JK: implement me
880
881 return(node);
882 }
883
884 void
ags_sfz_sample_xml_parse(AgsConnectable * connectable,xmlNode * node)885 ags_sfz_sample_xml_parse(AgsConnectable *connectable,
886 xmlNode *node)
887 {
888 //TODO:JK: implement me
889 }
890
891 gboolean
ags_sfz_sample_is_connected(AgsConnectable * connectable)892 ags_sfz_sample_is_connected(AgsConnectable *connectable)
893 {
894 AgsSFZSample *sfz_sample;
895
896 gboolean is_connected;
897
898 sfz_sample = AGS_SFZ_SAMPLE(connectable);
899
900 /* check is connected */
901 is_connected = ags_sfz_sample_test_flags(sfz_sample, AGS_SFZ_SAMPLE_CONNECTED);
902
903 return(is_connected);
904 }
905
906 void
ags_sfz_sample_connect(AgsConnectable * connectable)907 ags_sfz_sample_connect(AgsConnectable *connectable)
908 {
909 AgsSFZSample *sfz_sample;
910
911 if(ags_connectable_is_connected(connectable)){
912 return;
913 }
914
915 sfz_sample = AGS_SFZ_SAMPLE(connectable);
916
917 ags_sfz_sample_set_flags(sfz_sample, AGS_SFZ_SAMPLE_CONNECTED);
918 }
919
920 void
ags_sfz_sample_disconnect(AgsConnectable * connectable)921 ags_sfz_sample_disconnect(AgsConnectable *connectable)
922 {
923 AgsSFZSample *sfz_sample;
924
925 if(!ags_connectable_is_connected(connectable)){
926 return;
927 }
928
929 sfz_sample = AGS_SFZ_SAMPLE(connectable);
930
931 ags_sfz_sample_unset_flags(sfz_sample, AGS_SFZ_SAMPLE_CONNECTED);
932 }
933
934 gboolean
ags_sfz_sample_open(AgsSoundResource * sound_resource,gchar * filename)935 ags_sfz_sample_open(AgsSoundResource *sound_resource,
936 gchar *filename)
937 {
938 AgsSFZSample *sfz_sample;
939
940 guint format;
941
942 GRecMutex *sfz_sample_mutex;
943
944 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
945
946 /* get sfz sample mutex */
947 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
948
949 /* info */
950 g_rec_mutex_lock(sfz_sample_mutex);
951
952 if(sfz_sample->info != NULL){
953 g_rec_mutex_unlock(sfz_sample_mutex);
954
955 return(FALSE);
956 }
957
958 sfz_sample->info = (SF_INFO *) malloc(sizeof(SF_INFO));
959 sfz_sample->info->format = 0;
960 sfz_sample->info->channels = 0;
961 sfz_sample->info->samplerate = 0;
962
963 if(filename != NULL){
964 sfz_sample->file = (SNDFILE *) sf_open(filename, SFM_READ, sfz_sample->info);
965 }
966
967 if(sfz_sample->file == NULL){
968 g_rec_mutex_unlock(sfz_sample_mutex);
969
970 return(FALSE);
971 }
972
973 format = AGS_SOUNDCARD_DOUBLE;
974
975 switch(((SF_FORMAT_PCM_S8 |
976 SF_FORMAT_PCM_16 |
977 SF_FORMAT_PCM_24 |
978 SF_FORMAT_PCM_32 |
979 SF_FORMAT_FLOAT |
980 SF_FORMAT_DOUBLE) & sfz_sample->info->format)){
981 case SF_FORMAT_PCM_S8:
982 {
983 //TODO:JK: implement me
984 //format = AGS_SOUNDCARD_SIGNED_8_BIT;
985 format = AGS_SOUNDCARD_DOUBLE;
986 }
987 break;
988 case SF_FORMAT_PCM_16:
989 {
990 format = AGS_SOUNDCARD_SIGNED_16_BIT;
991 }
992 break;
993 case SF_FORMAT_PCM_24:
994 {
995 //TODO:JK: implement me
996 //format = AGS_SOUNDCARD_SIGNED_24_BIT;
997 format = AGS_SOUNDCARD_DOUBLE;
998 }
999 break;
1000 case SF_FORMAT_PCM_32:
1001 {
1002 //TODO:JK: implement me
1003 //format = AGS_SOUNDCARD_SIGNED_32_BIT;
1004 format = AGS_SOUNDCARD_DOUBLE;
1005 }
1006 break;
1007 case SF_FORMAT_FLOAT:
1008 {
1009 format = AGS_SOUNDCARD_FLOAT;
1010 }
1011 break;
1012 case SF_FORMAT_DOUBLE:
1013 {
1014 format = AGS_SOUNDCARD_DOUBLE;
1015 }
1016 break;
1017 }
1018
1019 g_rec_mutex_unlock(sfz_sample_mutex);
1020
1021 g_object_set(sfz_sample,
1022 "filename", filename,
1023 "audio-channels", sfz_sample->info->channels,
1024 "format", format,
1025 NULL);
1026
1027 #ifdef AGS_DEBUG
1028 g_message("ags_sfz_sample_open(): channels %d frames %d", sfz_sample->info->channels, sfz_sample->info->frames);
1029 #endif
1030
1031 return(TRUE);
1032 }
1033
1034 gboolean
ags_sfz_sample_rw_open(AgsSoundResource * sound_resource,gchar * filename,guint audio_channels,guint samplerate,gboolean create)1035 ags_sfz_sample_rw_open(AgsSoundResource *sound_resource,
1036 gchar *filename,
1037 guint audio_channels, guint samplerate,
1038 gboolean create)
1039 {
1040 AgsSFZSample *sfz_sample;
1041
1042 guint major_format;
1043 gboolean success;
1044
1045 GRecMutex *sfz_sample_mutex;
1046
1047 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1048
1049 /* get sfz sample mutex */
1050 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1051
1052 /* info */
1053 g_rec_mutex_lock(sfz_sample_mutex);
1054
1055 if(sfz_sample->info != NULL){
1056 g_rec_mutex_unlock(sfz_sample_mutex);
1057
1058 return(FALSE);
1059 }
1060
1061 if(!create &&
1062 !g_file_test(filename,
1063 (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))){
1064 g_rec_mutex_unlock(sfz_sample_mutex);
1065
1066 return(FALSE);
1067 }
1068
1069 sfz_sample->info = (SF_INFO *) malloc(sizeof(SF_INFO));
1070 memset(sfz_sample->info, 0, sizeof(SF_INFO));
1071
1072 sfz_sample->info->samplerate = (int) samplerate;
1073 sfz_sample->info->channels = (int) audio_channels;
1074
1075 g_rec_mutex_unlock(sfz_sample_mutex);
1076
1077 if(g_str_has_suffix(filename, ".wav")){
1078 major_format = SF_FORMAT_WAV;
1079
1080 g_rec_mutex_lock(sfz_sample_mutex);
1081
1082 sfz_sample->info->format = major_format | SF_FORMAT_PCM_16;
1083
1084 g_rec_mutex_unlock(sfz_sample_mutex);
1085
1086 g_object_set(sfz_sample,
1087 "format", AGS_SOUNDCARD_SIGNED_16_BIT,
1088 NULL);
1089 }else if(g_str_has_suffix(filename, ".flac")){
1090 major_format = SF_FORMAT_FLAC;
1091
1092 g_rec_mutex_lock(sfz_sample_mutex);
1093
1094 sfz_sample->info->format = major_format | SF_FORMAT_PCM_16;
1095
1096 g_rec_mutex_unlock(sfz_sample_mutex);
1097
1098 g_object_set(sfz_sample,
1099 "format", AGS_SOUNDCARD_SIGNED_16_BIT,
1100 NULL);
1101 }else if(g_str_has_suffix(filename, ".aiff")){
1102 major_format = SF_FORMAT_AIFF;
1103
1104 g_rec_mutex_lock(sfz_sample_mutex);
1105
1106 sfz_sample->info->format = major_format | SF_FORMAT_PCM_16;
1107
1108 g_rec_mutex_unlock(sfz_sample_mutex);
1109
1110 g_object_set(sfz_sample,
1111 "format", AGS_SOUNDCARD_SIGNED_16_BIT,
1112 NULL);
1113 }else if(g_str_has_suffix(filename, ".ogg")){
1114 major_format = SF_FORMAT_OGG;
1115
1116 g_rec_mutex_lock(sfz_sample_mutex);
1117
1118 sfz_sample->info->format = major_format | SF_FORMAT_VORBIS;
1119
1120 g_rec_mutex_unlock(sfz_sample_mutex);
1121
1122 g_object_set(sfz_sample,
1123 "format", AGS_SOUNDCARD_DOUBLE,
1124 NULL);
1125 }else{
1126 major_format = SF_FORMAT_WAV;
1127
1128 g_rec_mutex_lock(sfz_sample_mutex);
1129
1130 sfz_sample->info->format = major_format | SF_FORMAT_PCM_16;
1131
1132 g_rec_mutex_unlock(sfz_sample_mutex);
1133
1134 g_object_set(sfz_sample,
1135 "format", AGS_SOUNDCARD_SIGNED_16_BIT,
1136 NULL);
1137 }
1138
1139 g_rec_mutex_lock(sfz_sample_mutex);
1140
1141 sfz_sample->info->frames = 0;
1142 sfz_sample->info->seekable = 0;
1143 sfz_sample->info->sections = 0;
1144
1145 if(!sf_format_check(sfz_sample->info)){
1146 g_warning("invalid format");
1147 }
1148
1149 if(filename != NULL){
1150 sfz_sample->file = (SNDFILE *) sf_open(filename, SFM_RDWR, sfz_sample->info);
1151 }
1152
1153 success = (sfz_sample->file != NULL) ? TRUE: FALSE;
1154
1155 g_rec_mutex_unlock(sfz_sample_mutex);
1156
1157 g_object_set(sfz_sample,
1158 "filename", filename,
1159 "audio-channels", audio_channels,
1160 NULL);
1161
1162 #ifdef AGS_DEBUG
1163 g_message("ags_sfz_sample_rw_open(): channels %d frames %d", sfz_sample->info->channels, sfz_sample->info->frames);
1164 #endif
1165
1166 return(success);
1167 }
1168
1169 gboolean
ags_sfz_sample_info(AgsSoundResource * sound_resource,guint * frame_count,guint * loop_start,guint * loop_end)1170 ags_sfz_sample_info(AgsSoundResource *sound_resource,
1171 guint *frame_count,
1172 guint *loop_start, guint *loop_end)
1173 {
1174 AgsSFZSample *sfz_sample;
1175
1176 guint sample_frame_count;
1177 guint sample_loop_start, sample_loop_end;
1178
1179 GRecMutex *sfz_sample_mutex;
1180
1181 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1182
1183 /* get sfz sample mutex */
1184 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1185
1186 /* info */
1187 sample_frame_count = 0;
1188
1189 sample_loop_start = 0;
1190 sample_loop_end = 0;
1191
1192 g_rec_mutex_lock(sfz_sample_mutex);
1193
1194 if(sfz_sample->info != NULL){
1195 sample_frame_count = sfz_sample->info->frames;
1196 }
1197
1198 g_rec_mutex_unlock(sfz_sample_mutex);
1199
1200 g_object_get(sfz_sample,
1201 "loop-start", &sample_loop_start,
1202 "loop-end", &sample_loop_end,
1203 NULL);
1204
1205 if(frame_count != NULL){
1206 frame_count[0] = sample_frame_count;
1207 }
1208
1209 if(loop_start != NULL){
1210 loop_start[0] = sample_loop_start;
1211 }
1212
1213 if(loop_end != NULL){
1214 loop_end[0] = sample_loop_end;
1215 }
1216
1217 return(TRUE);
1218 }
1219
1220 void
ags_sfz_sample_set_presets(AgsSoundResource * sound_resource,guint channels,guint samplerate,guint buffer_size,guint format)1221 ags_sfz_sample_set_presets(AgsSoundResource *sound_resource,
1222 guint channels,
1223 guint samplerate,
1224 guint buffer_size,
1225 guint format)
1226 {
1227 AgsSFZSample *sfz_sample;
1228
1229 gint sample_format;
1230
1231 GRecMutex *sfz_sample_mutex;
1232
1233 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1234
1235 /* get sfz sample mutex */
1236 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1237
1238 g_object_set(sfz_sample,
1239 "buffer-size", buffer_size,
1240 "format", format,
1241 NULL);
1242
1243 g_rec_mutex_lock(sfz_sample_mutex);
1244
1245 if(sfz_sample->info == NULL){
1246 g_rec_mutex_unlock(sfz_sample_mutex);
1247
1248 return;
1249 }
1250
1251 sfz_sample->info->channels = channels;
1252 sfz_sample->info->samplerate = samplerate;
1253 sfz_sample->info->format &= (~(SF_FORMAT_PCM_S8 |
1254 SF_FORMAT_PCM_16 |
1255 SF_FORMAT_PCM_24 |
1256 SF_FORMAT_PCM_32 |
1257 SF_FORMAT_FLOAT |
1258 SF_FORMAT_DOUBLE));
1259
1260 switch(format){
1261 case AGS_SOUNDCARD_SIGNED_8_BIT:
1262 {
1263 sfz_sample->info->format |= SF_FORMAT_PCM_S8;
1264 }
1265 break;
1266 case AGS_SOUNDCARD_SIGNED_16_BIT:
1267 {
1268 sfz_sample->info->format |= SF_FORMAT_PCM_16;
1269 }
1270 break;
1271 case AGS_SOUNDCARD_SIGNED_24_BIT:
1272 {
1273 sfz_sample->info->format |= SF_FORMAT_PCM_24;
1274 }
1275 break;
1276 case AGS_SOUNDCARD_SIGNED_32_BIT:
1277 {
1278 sfz_sample->info->format |= SF_FORMAT_PCM_32;
1279 }
1280 break;
1281 case AGS_SOUNDCARD_FLOAT:
1282 {
1283 sfz_sample->info->format |= SF_FORMAT_FLOAT;
1284 }
1285 break;
1286 case AGS_SOUNDCARD_DOUBLE:
1287 {
1288 sfz_sample->info->format |= SF_FORMAT_DOUBLE;
1289 }
1290 break;
1291 }
1292
1293 g_rec_mutex_unlock(sfz_sample_mutex);
1294 }
1295
1296 void
ags_sfz_sample_get_presets(AgsSoundResource * sound_resource,guint * channels,guint * samplerate,guint * buffer_size,guint * format)1297 ags_sfz_sample_get_presets(AgsSoundResource *sound_resource,
1298 guint *channels,
1299 guint *samplerate,
1300 guint *buffer_size,
1301 guint *format)
1302 {
1303 AgsSFZSample *sfz_sample;
1304
1305 GRecMutex *sfz_sample_mutex;
1306
1307 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1308
1309 /* get sfz sample mutex */
1310 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1311
1312 if(sfz_sample->info == NULL){
1313 if(channels != NULL){
1314 *channels = 0;
1315 }
1316
1317 if(samplerate != NULL){
1318 *samplerate = 0;
1319 }
1320
1321 if(buffer_size != NULL){
1322 *buffer_size = 0;
1323 }
1324
1325 if(format != NULL){
1326 *format = 0;
1327 }
1328
1329 return;
1330 }
1331
1332 g_rec_mutex_lock(sfz_sample_mutex);
1333
1334 if(channels != NULL){
1335 *channels = sfz_sample->info->channels;
1336 }
1337
1338 if(samplerate != NULL){
1339 *samplerate = sfz_sample->info->samplerate;
1340 }
1341
1342 if(buffer_size != NULL){
1343 *buffer_size = sfz_sample->buffer_size;
1344 }
1345
1346 if(format != NULL){
1347 switch(((SF_FORMAT_PCM_S8 |
1348 SF_FORMAT_PCM_16 |
1349 SF_FORMAT_PCM_24 |
1350 SF_FORMAT_PCM_32 |
1351 SF_FORMAT_FLOAT |
1352 SF_FORMAT_DOUBLE) & sfz_sample->info->format)){
1353 case SF_FORMAT_PCM_S8:
1354 {
1355 *format = AGS_SOUNDCARD_SIGNED_8_BIT;
1356 }
1357 break;
1358 case SF_FORMAT_PCM_16:
1359 {
1360 *format = AGS_SOUNDCARD_SIGNED_16_BIT;
1361 }
1362 break;
1363 case SF_FORMAT_PCM_24:
1364 {
1365 *format = AGS_SOUNDCARD_SIGNED_24_BIT;
1366 }
1367 break;
1368 case SF_FORMAT_PCM_32:
1369 {
1370 *format = AGS_SOUNDCARD_SIGNED_32_BIT;
1371 }
1372 break;
1373 case SF_FORMAT_FLOAT:
1374 {
1375 *format = AGS_SOUNDCARD_FLOAT;
1376 }
1377 break;
1378 case SF_FORMAT_DOUBLE:
1379 {
1380 *format = AGS_SOUNDCARD_DOUBLE;
1381 }
1382 break;
1383 }
1384 }
1385
1386 g_rec_mutex_unlock(sfz_sample_mutex);
1387 }
1388
1389 guint
ags_sfz_sample_read(AgsSoundResource * sound_resource,void * dbuffer,guint daudio_channels,guint audio_channel,guint frame_count,guint format)1390 ags_sfz_sample_read(AgsSoundResource *sound_resource,
1391 void *dbuffer, guint daudio_channels,
1392 guint audio_channel,
1393 guint frame_count, guint format)
1394 {
1395 AgsSFZSample *sfz_sample;
1396
1397 sf_count_t multi_frames;
1398 guint total_frame_count;
1399 guint read_count;
1400 guint copy_mode;
1401 gboolean use_cache;
1402 guint i;
1403
1404 GRecMutex *sfz_sample_mutex;
1405
1406 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1407
1408 /* get sfz_sample mutex */
1409 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1410
1411 ags_sound_resource_info(sound_resource,
1412 &total_frame_count,
1413 NULL, NULL);
1414
1415 g_rec_mutex_lock(sfz_sample_mutex);
1416
1417 if(sfz_sample->offset >= total_frame_count){
1418 g_rec_mutex_unlock(sfz_sample_mutex);
1419
1420 return(0);
1421 }
1422
1423 if(sfz_sample->offset + frame_count >= total_frame_count){
1424 if(total_frame_count > sfz_sample->offset){
1425 frame_count = total_frame_count - sfz_sample->offset;
1426 }else{
1427 g_rec_mutex_unlock(sfz_sample_mutex);
1428
1429 return(0);
1430 }
1431 }
1432
1433 #if 0
1434 use_cache = FALSE;
1435
1436 if(sfz_sample->buffer_offset == sfz_sample->offset &&
1437 frame_count <= sfz_sample->buffer_size){
1438 use_cache = TRUE;
1439 }
1440 #endif
1441
1442 sfz_sample->buffer_offset = sfz_sample->offset;
1443
1444 read_count = sfz_sample->buffer_size;
1445
1446 copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(format),
1447 ags_audio_buffer_util_format_from_soundcard(sfz_sample->format));
1448
1449 for(i = 0; i < frame_count && sfz_sample->offset + i < total_frame_count; ){
1450 sf_count_t retval;
1451
1452 if(sfz_sample->offset + frame_count > total_frame_count){
1453 read_count = total_frame_count - sfz_sample->offset;
1454 }
1455
1456 multi_frames = read_count * sfz_sample->info->channels;
1457
1458 retval = -1;
1459
1460 // if(!use_cache){
1461 // g_message("read %d %d", sfz_sample->offset, sfz_sample->buffer_size);
1462
1463 switch(sfz_sample->format){
1464 case AGS_SOUNDCARD_SIGNED_8_BIT:
1465 {
1466 //TODO:JK: implement me
1467 retval = 0;
1468 }
1469 break;
1470 case AGS_SOUNDCARD_SIGNED_16_BIT:
1471 {
1472 retval = sf_read_short(sfz_sample->file, sfz_sample->buffer, multi_frames);
1473 }
1474 break;
1475 case AGS_SOUNDCARD_SIGNED_24_BIT:
1476 {
1477 //TODO:JK: implement me
1478 retval = 0;
1479 }
1480 break;
1481 case AGS_SOUNDCARD_SIGNED_32_BIT:
1482 {
1483 //TODO:JK: implement me
1484 retval = 0;
1485 }
1486 break;
1487 case AGS_SOUNDCARD_FLOAT:
1488 {
1489 retval = sf_read_float(sfz_sample->file, sfz_sample->buffer, multi_frames);
1490 }
1491 break;
1492 case AGS_SOUNDCARD_DOUBLE:
1493 {
1494 retval = sf_read_double(sfz_sample->file, sfz_sample->buffer, multi_frames);
1495 }
1496 break;
1497 }
1498
1499 sfz_sample->offset += read_count;
1500
1501 if(retval == -1){
1502 g_warning("read failed");
1503 }
1504
1505 if(retval != multi_frames){
1506 break;
1507 }
1508 // }
1509
1510 ags_audio_buffer_util_copy_buffer_to_buffer(dbuffer, daudio_channels, (i * daudio_channels),
1511 sfz_sample->buffer, sfz_sample->info->channels, audio_channel,
1512 read_count, copy_mode);
1513 // g_message("[%d] %d", audio_channel, ags_synth_util_get_xcross_count_s16(dbuffer, read_count));
1514
1515 i += read_count;
1516 }
1517
1518 g_rec_mutex_unlock(sfz_sample_mutex);
1519
1520 return(frame_count);
1521 }
1522
1523 void
ags_sfz_sample_write(AgsSoundResource * sound_resource,void * sbuffer,guint saudio_channels,guint audio_channel,guint frame_count,guint format)1524 ags_sfz_sample_write(AgsSoundResource *sound_resource,
1525 void *sbuffer, guint saudio_channels,
1526 guint audio_channel,
1527 guint frame_count, guint format)
1528 {
1529 AgsSFZSample *sfz_sample;
1530
1531 guint copy_mode;
1532 sf_count_t multi_frames;
1533 guint i;
1534 gboolean do_write;
1535
1536 GRecMutex *sfz_sample_mutex;
1537
1538 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1539
1540 /* get sfz_sample mutex */
1541 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1542
1543 g_rec_mutex_lock(sfz_sample_mutex);
1544
1545 copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(sfz_sample->format),
1546 ags_audio_buffer_util_format_from_soundcard(format));
1547
1548 ags_audio_buffer_util_copy_buffer_to_buffer(sfz_sample->buffer, sfz_sample->info->channels, audio_channel,
1549 sbuffer, saudio_channels, audio_channel,
1550 frame_count, copy_mode);
1551
1552 sfz_sample->audio_channel_written[audio_channel] = frame_count;
1553 do_write = TRUE;
1554
1555 for(i = 0; i < sfz_sample->audio_channels; i++){
1556 if(sfz_sample->audio_channel_written[i] == -1){
1557 do_write = FALSE;
1558
1559 break;
1560 }
1561 }
1562
1563 if(do_write){
1564 multi_frames = frame_count * sfz_sample->info->channels;
1565
1566 switch(sfz_sample->format){
1567 case AGS_SOUNDCARD_SIGNED_8_BIT:
1568 {
1569 //TODO:JK: implement me
1570 }
1571 break;
1572 case AGS_SOUNDCARD_SIGNED_16_BIT:
1573 {
1574 sf_write_short(sfz_sample->file, sfz_sample->buffer, multi_frames);
1575 }
1576 break;
1577 case AGS_SOUNDCARD_SIGNED_24_BIT:
1578 {
1579 //TODO:JK: implement me
1580 }
1581 break;
1582 case AGS_SOUNDCARD_SIGNED_32_BIT:
1583 {
1584 //TODO:JK: implement me
1585 }
1586 break;
1587 case AGS_SOUNDCARD_FLOAT:
1588 {
1589 sf_write_float(sfz_sample->file, sfz_sample->buffer, multi_frames);
1590 }
1591 break;
1592 case AGS_SOUNDCARD_DOUBLE:
1593 {
1594 sf_write_double(sfz_sample->file, sfz_sample->buffer, multi_frames);
1595 }
1596 break;
1597 }
1598
1599 for(i = 0; i < sfz_sample->audio_channels; i++){
1600 sfz_sample->audio_channel_written[i] = -1;
1601 }
1602
1603 if(sfz_sample->format == AGS_SOUNDCARD_DOUBLE){
1604 ags_audio_buffer_util_clear_double(sfz_sample->buffer, sfz_sample->info->channels,
1605 frame_count);
1606 }else if(sfz_sample->format == AGS_SOUNDCARD_FLOAT){
1607 ags_audio_buffer_util_clear_float(sfz_sample->buffer, sfz_sample->info->channels,
1608 frame_count);
1609 }else{
1610 ags_audio_buffer_util_clear_buffer(sfz_sample->buffer, sfz_sample->info->channels,
1611 frame_count, ags_audio_buffer_util_format_from_soundcard(sfz_sample->format));
1612 }
1613
1614 sfz_sample->offset += frame_count;
1615 }
1616
1617 g_rec_mutex_unlock(sfz_sample_mutex);
1618 }
1619
1620 void
ags_sfz_sample_flush(AgsSoundResource * sound_resource)1621 ags_sfz_sample_flush(AgsSoundResource *sound_resource)
1622 {
1623 AgsSFZSample *sfz_sample;
1624
1625 GRecMutex *sfz_sample_mutex;
1626
1627 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1628
1629 /* get sfz sample mutex */
1630 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1631
1632 g_rec_mutex_lock(sfz_sample_mutex);
1633
1634 if(sfz_sample->file == NULL){
1635 g_rec_mutex_unlock(sfz_sample_mutex);
1636
1637 return;
1638 }
1639
1640 sf_write_sync(sfz_sample->file);
1641
1642 g_rec_mutex_unlock(sfz_sample_mutex);
1643 }
1644
1645 void
ags_sfz_sample_seek(AgsSoundResource * sound_resource,gint64 frame_count,gint whence)1646 ags_sfz_sample_seek(AgsSoundResource *sound_resource,
1647 gint64 frame_count, gint whence)
1648 {
1649 AgsSFZSample *sfz_sample;
1650
1651 guint total_frame_count;
1652 sf_count_t retval;
1653
1654 GRecMutex *sfz_sample_mutex;
1655
1656 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1657
1658 /* get sfz sample mutex */
1659 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1660
1661 ags_sound_resource_info(sound_resource,
1662 &total_frame_count,
1663 NULL, NULL);
1664
1665 g_rec_mutex_lock(sfz_sample_mutex);
1666
1667 if(whence == G_SEEK_CUR){
1668 if(frame_count >= 0){
1669 if(sfz_sample->offset + frame_count < total_frame_count){
1670 sfz_sample->offset += total_frame_count;
1671 }else{
1672 sfz_sample->offset = total_frame_count;
1673 }
1674 }else{
1675 if(sfz_sample->offset + frame_count >= 0){
1676 sfz_sample->offset += total_frame_count;
1677 }else{
1678 sfz_sample->offset = 0;
1679 }
1680 }
1681 }else if(whence == G_SEEK_SET){
1682 if(frame_count >= 0){
1683 if(frame_count < total_frame_count){
1684 sfz_sample->offset = frame_count;
1685 }else{
1686 sfz_sample->offset = total_frame_count;
1687 }
1688 }else{
1689 sfz_sample->offset = 0;
1690 }
1691 }else if(whence == G_SEEK_END){
1692 if(frame_count > 0){
1693 sfz_sample->offset = total_frame_count;
1694 }else{
1695 if(total_frame_count + frame_count > 0){
1696 sfz_sample->offset = total_frame_count + total_frame_count;
1697 }else{
1698 sfz_sample->offset = 0;
1699 }
1700 }
1701 }
1702
1703 retval = sf_seek(sfz_sample->file, sfz_sample->offset, SEEK_SET);
1704
1705 g_rec_mutex_unlock(sfz_sample_mutex);
1706
1707 if(retval == -1){
1708 g_warning("seek failed");
1709 }
1710 }
1711
1712 void
ags_sfz_sample_close(AgsSoundResource * sound_resource)1713 ags_sfz_sample_close(AgsSoundResource *sound_resource)
1714 {
1715 AgsSFZSample *sfz_sample;
1716
1717 GRecMutex *sfz_sample_mutex;
1718
1719 sfz_sample = AGS_SFZ_SAMPLE(sound_resource);
1720
1721 /* get sfz sample mutex */
1722 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1723
1724 g_rec_mutex_lock(sfz_sample_mutex);
1725
1726 if(sfz_sample->file == NULL){
1727 g_rec_mutex_unlock(sfz_sample_mutex);
1728
1729 return;
1730 }
1731
1732 sf_close(sfz_sample->file);
1733
1734 if(sfz_sample->info != NULL){
1735 free(sfz_sample->info);
1736 }
1737
1738 sfz_sample->file = NULL;
1739 sfz_sample->info = NULL;
1740
1741 g_rec_mutex_unlock(sfz_sample_mutex);
1742 }
1743
1744 /**
1745 * ags_sfz_sample_test_flags:
1746 * @sfz_sample: the #AgsSFZSample
1747 * @flags: the flags
1748 *
1749 * Test @flags to be set on @sfz_sample.
1750 *
1751 * Returns: %TRUE if flags are set, else %FALSE
1752 *
1753 * Since: 3.0.0
1754 */
1755 gboolean
ags_sfz_sample_test_flags(AgsSFZSample * sfz_sample,guint flags)1756 ags_sfz_sample_test_flags(AgsSFZSample *sfz_sample, guint flags)
1757 {
1758 gboolean retval;
1759
1760 GRecMutex *sfz_sample_mutex;
1761
1762 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
1763 return(FALSE);
1764 }
1765
1766 /* get sfz_sample mutex */
1767 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1768
1769 /* test */
1770 g_rec_mutex_lock(sfz_sample_mutex);
1771
1772 retval = (flags & (sfz_sample->flags)) ? TRUE: FALSE;
1773
1774 g_rec_mutex_unlock(sfz_sample_mutex);
1775
1776 return(retval);
1777 }
1778
1779 /**
1780 * ags_sfz_sample_set_flags:
1781 * @sfz_sample: the #AgsSFZSample
1782 * @flags: see #AgsSFZSampleFlags-enum
1783 *
1784 * Enable a feature of @sfz_sample.
1785 *
1786 * Since: 3.0.0
1787 */
1788 void
ags_sfz_sample_set_flags(AgsSFZSample * sfz_sample,guint flags)1789 ags_sfz_sample_set_flags(AgsSFZSample *sfz_sample, guint flags)
1790 {
1791 GRecMutex *sfz_sample_mutex;
1792
1793 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
1794 return;
1795 }
1796
1797 /* get sfz_sample mutex */
1798 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1799
1800 //TODO:JK: add more?
1801
1802 /* set flags */
1803 g_rec_mutex_lock(sfz_sample_mutex);
1804
1805 sfz_sample->flags |= flags;
1806
1807 g_rec_mutex_unlock(sfz_sample_mutex);
1808 }
1809
1810 /**
1811 * ags_sfz_sample_unset_flags:
1812 * @sfz_sample: the #AgsSFZSample
1813 * @flags: see #AgsSFZSampleFlags-enum
1814 *
1815 * Disable a feature of @sfz_sample.
1816 *
1817 * Since: 3.0.0
1818 */
1819 void
ags_sfz_sample_unset_flags(AgsSFZSample * sfz_sample,guint flags)1820 ags_sfz_sample_unset_flags(AgsSFZSample *sfz_sample, guint flags)
1821 {
1822 GRecMutex *sfz_sample_mutex;
1823
1824 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
1825 return;
1826 }
1827
1828 /* get sfz_sample mutex */
1829 sfz_sample_mutex = AGS_SFZ_SAMPLE_GET_OBJ_MUTEX(sfz_sample);
1830
1831 //TODO:JK: add more?
1832
1833 /* unset flags */
1834 g_rec_mutex_lock(sfz_sample_mutex);
1835
1836 sfz_sample->flags &= (~flags);
1837
1838 g_rec_mutex_unlock(sfz_sample_mutex);
1839 }
1840
1841 /**
1842 * ags_sfz_sample_get_key:
1843 * @sfz_sample: the #AgsSFZSample
1844 *
1845 * Get key of @sfz_sample.
1846 *
1847 * Returns: the key
1848 *
1849 * Since: 3.7.3
1850 */
1851 gint
ags_sfz_sample_get_key(AgsSFZSample * sfz_sample)1852 ags_sfz_sample_get_key(AgsSFZSample *sfz_sample)
1853 {
1854 gchar *group_key, *region_key;
1855
1856 gint midi_key;
1857
1858 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
1859 return(-1);
1860 }
1861
1862 midi_key = -1;
1863
1864 group_key = ags_sfz_group_lookup_control(sfz_sample->group,
1865 "key");
1866
1867 if(group_key != NULL){
1868 glong current_midi_key;
1869 int retval;
1870
1871 retval = sscanf(group_key, "%3ld", ¤t_midi_key);
1872
1873 if(retval > 0){
1874 midi_key = current_midi_key;
1875 }else{
1876 retval = ags_diatonic_scale_note_to_midi_key(group_key,
1877 ¤t_midi_key);
1878
1879 if(retval > 0){
1880 midi_key = current_midi_key;
1881 }
1882 }
1883
1884 g_free(group_key);
1885 }
1886
1887 region_key = ags_sfz_region_lookup_control(sfz_sample->region,
1888 "key");
1889
1890 if(region_key != NULL){
1891 glong current_midi_key;
1892 int retval;
1893
1894 retval = sscanf(region_key, "%3ld", ¤t_midi_key);
1895
1896 if(retval <= 0){
1897 retval = ags_diatonic_scale_note_to_midi_key(region_key,
1898 ¤t_midi_key);
1899
1900 if(retval > 0){
1901 midi_key = current_midi_key;
1902 }
1903 }
1904
1905 g_free(region_key);
1906 }
1907
1908 return(midi_key);
1909 }
1910
1911 /**
1912 * ags_sfz_sample_get_hikey:
1913 * @sfz_sample: the #AgsSFZSample
1914 *
1915 * Get high key of @sfz_sample.
1916 *
1917 * Returns: the key
1918 *
1919 * Since: 3.7.3
1920 */
1921 gint
ags_sfz_sample_get_hikey(AgsSFZSample * sfz_sample)1922 ags_sfz_sample_get_hikey(AgsSFZSample *sfz_sample)
1923 {
1924 gchar *group_key, *region_key;
1925
1926 gint hikey;
1927
1928 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
1929 return(-1);
1930 }
1931
1932 hikey = -1;
1933
1934 group_key = ags_sfz_group_lookup_control(sfz_sample->group,
1935 "hikey");
1936
1937 if(group_key != NULL){
1938 glong current_hikey;
1939 int retval;
1940
1941 retval = sscanf(group_key, "%3ld", ¤t_hikey);
1942
1943 if(retval > 0){
1944 hikey = current_hikey;
1945 }else{
1946 retval = ags_diatonic_scale_note_to_midi_key(group_key,
1947 ¤t_hikey);
1948
1949 if(retval > 0){
1950 hikey = current_hikey;
1951 }
1952 }
1953
1954 g_free(group_key);
1955 }
1956
1957 region_key = ags_sfz_region_lookup_control(sfz_sample->region,
1958 "hikey");
1959
1960 if(region_key != NULL){
1961 glong current_hikey;
1962 int retval;
1963
1964 retval = sscanf(region_key, "%3ld", ¤t_hikey);
1965
1966 if(retval > 0){
1967 hikey = current_hikey;
1968 }else{
1969 retval = ags_diatonic_scale_note_to_midi_key(region_key,
1970 ¤t_hikey);
1971
1972 if(retval > 0){
1973 hikey = current_hikey;
1974 }
1975 }
1976
1977 g_free(region_key);
1978 }
1979
1980 return(hikey);
1981 }
1982
1983 /**
1984 * ags_sfz_sample_get_lokey:
1985 * @sfz_sample: the #AgsSFZSample
1986 *
1987 * Get low key of @sfz_sample.
1988 *
1989 * Returns: the key
1990 *
1991 * Since: 3.7.3
1992 */
1993 gint
ags_sfz_sample_get_lokey(AgsSFZSample * sfz_sample)1994 ags_sfz_sample_get_lokey(AgsSFZSample *sfz_sample)
1995 {
1996 gchar *group_key, *region_key;
1997
1998 gint lokey;
1999
2000 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
2001 return(-1);
2002 }
2003
2004 lokey = -1;
2005
2006 group_key = ags_sfz_group_lookup_control(sfz_sample->group,
2007 "lokey");
2008
2009 if(group_key != NULL){
2010 glong current_lokey;
2011 int retval;
2012
2013 retval = sscanf(group_key, "%3ld", ¤t_lokey);
2014
2015 if(retval > 0){
2016 lokey = current_lokey;
2017 }else{
2018 retval = ags_diatonic_scale_note_to_midi_key(group_key,
2019 ¤t_lokey);
2020
2021 if(retval > 0){
2022 lokey = current_lokey;
2023 }
2024 }
2025
2026 g_free(group_key);
2027 }
2028
2029 region_key = ags_sfz_region_lookup_control(sfz_sample->region,
2030 "lokey");
2031
2032 if(region_key != NULL){
2033 glong current_lokey;
2034 int retval;
2035
2036 retval = sscanf(region_key, "%3ld", ¤t_lokey);
2037
2038 if(retval > 0){
2039 lokey = current_lokey;
2040 }else{
2041 retval = ags_diatonic_scale_note_to_midi_key(region_key,
2042 ¤t_lokey);
2043
2044 if(retval > 0){
2045 lokey = current_lokey;
2046 }
2047 }
2048
2049 g_free(region_key);
2050 }
2051
2052 return(lokey);
2053 }
2054
2055 /**
2056 * ags_sfz_sample_get_pitch_keycenter:
2057 * @sfz_sample: the #AgsSFZSample
2058 *
2059 * Get pitch key-center of @sfz_sample.
2060 *
2061 * Returns: the key
2062 *
2063 * Since: 3.7.3
2064 */
2065 gint
ags_sfz_sample_get_pitch_keycenter(AgsSFZSample * sfz_sample)2066 ags_sfz_sample_get_pitch_keycenter(AgsSFZSample *sfz_sample)
2067 {
2068 gchar *group_key, *region_key;
2069
2070 gint pitch_keycenter;
2071
2072 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
2073 return(-1);
2074 }
2075
2076 pitch_keycenter = -1;
2077
2078 group_key = ags_sfz_group_lookup_control(sfz_sample->group,
2079 "pitch_keycenter");
2080
2081 if(group_key != NULL){
2082 glong current_pitch_keycenter;
2083 int retval;
2084
2085 retval = sscanf(group_key, "%3ld", ¤t_pitch_keycenter);
2086
2087 if(retval > 0){
2088 pitch_keycenter = current_pitch_keycenter;
2089 }else{
2090 retval = ags_diatonic_scale_note_to_midi_key(group_key,
2091 ¤t_pitch_keycenter);
2092
2093 if(retval > 0){
2094 pitch_keycenter = current_pitch_keycenter;
2095 }
2096 }
2097
2098 g_free(group_key);
2099 }
2100
2101 region_key = ags_sfz_region_lookup_control(sfz_sample->region,
2102 "pitch_keycenter");
2103
2104 if(region_key != NULL){
2105 glong current_pitch_keycenter;
2106 int retval;
2107
2108 retval = sscanf(region_key, "%3ld", ¤t_pitch_keycenter);
2109
2110 if(retval > 0){
2111 pitch_keycenter = current_pitch_keycenter;
2112 }else{
2113 retval = ags_diatonic_scale_note_to_midi_key(region_key,
2114 ¤t_pitch_keycenter);
2115
2116 if(retval > 0){
2117 pitch_keycenter = current_pitch_keycenter;
2118 }
2119 }
2120
2121 g_free(region_key);
2122 }
2123
2124 return(pitch_keycenter);
2125 }
2126
2127 /**
2128 * ags_sfz_sample_get_loop_mode:
2129 * @sfz_sample: the #AgsSFZSample
2130 *
2131 * Get key of @sfz_sample.
2132 *
2133 * Returns: the key
2134 *
2135 * Since: 3.7.3
2136 */
2137 guint
ags_sfz_sample_get_loop_mode(AgsSFZSample * sfz_sample)2138 ags_sfz_sample_get_loop_mode(AgsSFZSample *sfz_sample)
2139 {
2140 gchar *group_key, *region_key;
2141
2142 guint loop_mode;
2143
2144 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
2145 return(-1);
2146 }
2147
2148 loop_mode = AGS_SFZ_SAMPLE_LOOP_ONE_SHOT;
2149
2150 group_key = ags_sfz_group_lookup_control(sfz_sample->group,
2151 "loop_mode");
2152
2153 if(group_key != NULL){
2154 guint current_loop_mode;
2155 int retval;
2156
2157 retval = sscanf(group_key, "%ul", ¤t_loop_mode);
2158
2159 if(retval > 0){
2160 loop_mode = current_loop_mode;
2161 }else{
2162 retval = ags_diatonic_scale_note_to_midi_key(group_key,
2163 ¤t_loop_mode);
2164
2165 if(retval > 0){
2166 loop_mode = current_loop_mode;
2167 }
2168 }
2169
2170 g_free(group_key);
2171 }
2172
2173 region_key = ags_sfz_region_lookup_control(sfz_sample->region,
2174 "loop_mode");
2175
2176 if(region_key != NULL){
2177 guint current_loop_mode;
2178 int retval;
2179
2180 retval = sscanf(region_key, "%ul", ¤t_loop_mode);
2181
2182 if(retval > 0){
2183 loop_mode = current_loop_mode;
2184 }else{
2185 retval = ags_diatonic_scale_note_to_midi_key(region_key,
2186 ¤t_loop_mode);
2187
2188 if(retval > 0){
2189 loop_mode = current_loop_mode;
2190 }
2191 }
2192
2193 g_free(region_key);
2194 }
2195
2196 return(loop_mode);
2197 }
2198
2199 /**
2200 * ags_sfz_sample_get_loop_start:
2201 * @sfz_sample: the #AgsSFZSample
2202 *
2203 * Get key of @sfz_sample.
2204 *
2205 * Returns: the key
2206 *
2207 * Since: 3.7.3
2208 */
2209 guint
ags_sfz_sample_get_loop_start(AgsSFZSample * sfz_sample)2210 ags_sfz_sample_get_loop_start(AgsSFZSample *sfz_sample)
2211 {
2212 gchar *group_key, *region_key;
2213
2214 guint loop_start;
2215
2216 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
2217 return(-1);
2218 }
2219
2220 loop_start = 0;
2221
2222 group_key = ags_sfz_group_lookup_control(sfz_sample->group,
2223 "loop_start");
2224
2225 if(group_key != NULL){
2226 guint current_loop_start;
2227 int retval;
2228
2229 retval = sscanf(group_key, "%ul", ¤t_loop_start);
2230
2231 if(retval > 0){
2232 loop_start = current_loop_start;
2233 }else{
2234 retval = ags_diatonic_scale_note_to_midi_key(group_key,
2235 ¤t_loop_start);
2236
2237 if(retval > 0){
2238 loop_start = current_loop_start;
2239 }
2240 }
2241
2242 g_free(group_key);
2243 }
2244
2245 region_key = ags_sfz_region_lookup_control(sfz_sample->region,
2246 "loop_start");
2247
2248 if(region_key != NULL){
2249 guint current_loop_start;
2250 int retval;
2251
2252 retval = sscanf(region_key, "%ul", ¤t_loop_start);
2253
2254 if(retval > 0){
2255 loop_start = current_loop_start;
2256 }else{
2257 retval = ags_diatonic_scale_note_to_midi_key(region_key,
2258 ¤t_loop_start);
2259
2260 if(retval > 0){
2261 loop_start = current_loop_start;
2262 }
2263 }
2264
2265 g_free(region_key);
2266 }
2267
2268 return(loop_start);
2269 }
2270
2271 /**
2272 * ags_sfz_sample_get_loop_end:
2273 * @sfz_sample: the #AgsSFZSample
2274 *
2275 * Get key of @sfz_sample.
2276 *
2277 * Returns: the key
2278 *
2279 * Since: 3.7.3
2280 */
2281 guint
ags_sfz_sample_get_loop_end(AgsSFZSample * sfz_sample)2282 ags_sfz_sample_get_loop_end(AgsSFZSample *sfz_sample)
2283 {
2284 gchar *group_key, *region_key;
2285
2286 guint loop_end;
2287
2288 if(!AGS_IS_SFZ_SAMPLE(sfz_sample)){
2289 return(-1);
2290 }
2291
2292 loop_end = 0;
2293
2294 group_key = ags_sfz_group_lookup_control(sfz_sample->group,
2295 "loop_end");
2296
2297 if(group_key != NULL){
2298 guint current_loop_end;
2299 int retval;
2300
2301 retval = sscanf(group_key, "%ul", ¤t_loop_end);
2302
2303 if(retval > 0){
2304 loop_end = current_loop_end;
2305 }else{
2306 retval = ags_diatonic_scale_note_to_midi_key(group_key,
2307 ¤t_loop_end);
2308
2309 if(retval > 0){
2310 loop_end = current_loop_end;
2311 }
2312 }
2313
2314 g_free(group_key);
2315 }
2316
2317 region_key = ags_sfz_region_lookup_control(sfz_sample->region,
2318 "loop_end");
2319
2320 if(region_key != NULL){
2321 guint current_loop_end;
2322 int retval;
2323
2324 retval = sscanf(region_key, "%ul", ¤t_loop_end);
2325
2326 if(retval > 0){
2327 loop_end = current_loop_end;
2328 }else{
2329 retval = ags_diatonic_scale_note_to_midi_key(region_key,
2330 ¤t_loop_end);
2331
2332 if(retval > 0){
2333 loop_end = current_loop_end;
2334 }
2335 }
2336
2337 g_free(region_key);
2338 }
2339
2340 return(loop_end);
2341 }
2342
2343 /**
2344 * ags_sfz_sample_new:
2345 *
2346 * Creates a new instance of #AgsSFZSample.
2347 *
2348 * Returns: the new #AgsSFZSample.
2349 *
2350 * Since: 3.0.0
2351 */
2352 AgsSFZSample*
ags_sfz_sample_new()2353 ags_sfz_sample_new()
2354 {
2355 AgsSFZSample *sfz_sample;
2356
2357 sfz_sample = (AgsSFZSample *) g_object_new(AGS_TYPE_SFZ_SAMPLE,
2358 NULL);
2359
2360 return(sfz_sample);
2361 }
2362