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", &current_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 						   &current_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", &current_midi_key);
1895 
1896     if(retval <= 0){
1897       retval = ags_diatonic_scale_note_to_midi_key(region_key,
1898 						   &current_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", &current_hikey);
1942 
1943     if(retval > 0){
1944       hikey = current_hikey;
1945     }else{
1946       retval = ags_diatonic_scale_note_to_midi_key(group_key,
1947 						   &current_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", &current_hikey);
1965 
1966     if(retval > 0){
1967       hikey = current_hikey;
1968     }else{
1969       retval = ags_diatonic_scale_note_to_midi_key(region_key,
1970 						   &current_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", &current_lokey);
2014 
2015     if(retval > 0){
2016       lokey = current_lokey;
2017     }else{
2018       retval = ags_diatonic_scale_note_to_midi_key(group_key,
2019 						   &current_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", &current_lokey);
2037 
2038     if(retval > 0){
2039       lokey = current_lokey;
2040     }else{
2041       retval = ags_diatonic_scale_note_to_midi_key(region_key,
2042 						   &current_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", &current_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 						   &current_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", &current_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 						   &current_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", &current_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 						   &current_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", &current_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 						   &current_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", &current_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 						   &current_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", &current_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 						   &current_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", &current_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 						   &current_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", &current_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 						   &current_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