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/ags_fifoout.h>
21 
22 #include <ags/audio/ags_sound_provider.h>
23 #include <ags/audio/ags_audio_buffer_util.h>
24 
25 #include <ags/audio/task/ags_tic_device.h>
26 #include <ags/audio/task/ags_clear_buffer.h>
27 #include <ags/audio/task/ags_switch_buffer_flag.h>
28 
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 
32 #ifndef AGS_W32API
33 #include <fcntl.h>
34 #include <sys/ioctl.h>
35 #endif
36 
37 #include <errno.h>
38 
39 #include <string.h>
40 #include <math.h>
41 
42 #include <time.h>
43 #include <signal.h>
44 #include <strings.h>
45 #include <unistd.h>
46 
47 #include <ags/config.h>
48 #include <ags/i18n.h>
49 
50 void ags_fifoout_class_init(AgsFifooutClass *fifoout);
51 void ags_fifoout_connectable_interface_init(AgsConnectableInterface *connectable);
52 void ags_fifoout_soundcard_interface_init(AgsSoundcardInterface *soundcard);
53 void ags_fifoout_init(AgsFifoout *fifoout);
54 void ags_fifoout_set_property(GObject *gobject,
55 			      guint prop_id,
56 			      const GValue *value,
57 			      GParamSpec *param_spec);
58 void ags_fifoout_get_property(GObject *gobject,
59 			      guint prop_id,
60 			      GValue *value,
61 			      GParamSpec *param_spec);
62 void ags_fifoout_dispose(GObject *gobject);
63 void ags_fifoout_finalize(GObject *gobject);
64 
65 AgsUUID* ags_fifoout_get_uuid(AgsConnectable *connectable);
66 gboolean ags_fifoout_has_resource(AgsConnectable *connectable);
67 gboolean ags_fifoout_is_ready(AgsConnectable *connectable);
68 void ags_fifoout_add_to_registry(AgsConnectable *connectable);
69 void ags_fifoout_remove_from_registry(AgsConnectable *connectable);
70 xmlNode* ags_fifoout_list_resource(AgsConnectable *connectable);
71 xmlNode* ags_fifoout_xml_compose(AgsConnectable *connectable);
72 void ags_fifoout_xml_parse(AgsConnectable *connectable,
73 			   xmlNode *node);
74 gboolean ags_fifoout_is_connected(AgsConnectable *connectable);
75 void ags_fifoout_connect(AgsConnectable *connectable);
76 void ags_fifoout_disconnect(AgsConnectable *connectable);
77 
78 void ags_fifoout_set_device(AgsSoundcard *soundcard,
79 			    gchar *device);
80 gchar* ags_fifoout_get_device(AgsSoundcard *soundcard);
81 
82 void ags_fifoout_set_presets(AgsSoundcard *soundcard,
83 			     guint channels,
84 			     guint rate,
85 			     guint buffer_size,
86 			     guint format);
87 void ags_fifoout_get_presets(AgsSoundcard *soundcard,
88 			     guint *channels,
89 			     guint *rate,
90 			     guint *buffer_size,
91 			     guint *format);
92 
93 void ags_fifoout_list_cards(AgsSoundcard *soundcard,
94 			    GList **card_id, GList **card_name);
95 void ags_fifoout_pcm_info(AgsSoundcard *soundcard, gchar *card_id,
96 			  guint *channels_min, guint *channels_max,
97 			  guint *rate_min, guint *rate_max,
98 			  guint *buffer_size_min, guint *buffer_size_max,
99 			  GError **error);
100 
101 gboolean ags_fifoout_is_available(AgsSoundcard *soundcard);
102 
103 gboolean ags_fifoout_is_starting(AgsSoundcard *soundcard);
104 gboolean ags_fifoout_is_playing(AgsSoundcard *soundcard);
105 
106 gchar* ags_fifoout_get_uptime(AgsSoundcard *soundcard);
107 
108 void ags_fifoout_fifo_init(AgsSoundcard *soundcard,
109 			   GError **error);
110 void ags_fifoout_fifo_play(AgsSoundcard *soundcard,
111 			   GError **error);
112 void ags_fifoout_fifo_free(AgsSoundcard *soundcard);
113 
114 void ags_fifoout_tic(AgsSoundcard *soundcard);
115 void ags_fifoout_offset_changed(AgsSoundcard *soundcard,
116 				guint note_offset);
117 
118 void ags_fifoout_set_bpm(AgsSoundcard *soundcard,
119 			 gdouble bpm);
120 gdouble ags_fifoout_get_bpm(AgsSoundcard *soundcard);
121 
122 void ags_fifoout_set_delay_factor(AgsSoundcard *soundcard,
123 				  gdouble delay_factor);
124 gdouble ags_fifoout_get_delay_factor(AgsSoundcard *soundcard);
125 
126 gdouble ags_fifoout_get_absolute_delay(AgsSoundcard *soundcard);
127 
128 gdouble ags_fifoout_get_delay(AgsSoundcard *soundcard);
129 guint ags_fifoout_get_attack(AgsSoundcard *soundcard);
130 
131 void* ags_fifoout_get_buffer(AgsSoundcard *soundcard);
132 void* ags_fifoout_get_next_buffer(AgsSoundcard *soundcard);
133 
134 guint ags_fifoout_get_delay_counter(AgsSoundcard *soundcard);
135 
136 void ags_fifoout_set_note_offset(AgsSoundcard *soundcard,
137 				 guint note_offset);
138 guint ags_fifoout_get_note_offset(AgsSoundcard *soundcard);
139 
140 void ags_fifoout_set_note_offset_absolute(AgsSoundcard *soundcard,
141 					  guint note_offset);
142 guint ags_fifoout_get_note_offset_absolute(AgsSoundcard *soundcard);
143 
144 void ags_fifoout_set_loop(AgsSoundcard *soundcard,
145 			  guint loop_left, guint loop_right,
146 			  gboolean do_loop);
147 void ags_fifoout_get_loop(AgsSoundcard *soundcard,
148 			  guint *loop_left, guint *loop_right,
149 			  gboolean *do_loop);
150 
151 guint ags_fifoout_get_loop_offset(AgsSoundcard *soundcard);
152 
153 /**
154  * SECTION:ags_fifoout
155  * @short_description: Output to pipe
156  * @title: AgsFifoout
157  * @section_id:
158  * @include: ags/audio/ags_fifoout.h
159  *
160  * #AgsFifoout represents a pipe and supports output.
161  */
162 
163 enum{
164   PROP_0,
165   PROP_DEVICE,
166   PROP_DSP_CHANNELS,
167   PROP_PCM_CHANNELS,
168   PROP_FORMAT,
169   PROP_BUFFER_SIZE,
170   PROP_SAMPLERATE,
171   PROP_BUFFER,
172   PROP_BPM,
173   PROP_DELAY_FACTOR,
174   PROP_ATTACK,
175 };
176 
177 static gpointer ags_fifoout_parent_class = NULL;
178 
179 GType
ags_fifoout_get_type(void)180 ags_fifoout_get_type (void)
181 {
182   static volatile gsize g_define_type_id__volatile = 0;
183 
184   if(g_once_init_enter (&g_define_type_id__volatile)){
185     GType ags_type_fifoout = 0;
186 
187     static const GTypeInfo ags_fifoout_info = {
188       sizeof(AgsFifooutClass),
189       NULL, /* base_init */
190       NULL, /* base_finalize */
191       (GClassInitFunc) ags_fifoout_class_init,
192       NULL, /* class_finalize */
193       NULL, /* class_data */
194       sizeof(AgsFifoout),
195       0,    /* n_preallocs */
196       (GInstanceInitFunc) ags_fifoout_init,
197     };
198 
199     static const GInterfaceInfo ags_connectable_interface_info = {
200       (GInterfaceInitFunc) ags_fifoout_connectable_interface_init,
201       NULL, /* interface_finalize */
202       NULL, /* interface_data */
203     };
204 
205     static const GInterfaceInfo ags_soundcard_interface_info = {
206       (GInterfaceInitFunc) ags_fifoout_soundcard_interface_init,
207       NULL, /* interface_finalize */
208       NULL, /* interface_data */
209     };
210 
211     ags_type_fifoout = g_type_register_static(G_TYPE_OBJECT,
212 					      "AgsFifoout",
213 					      &ags_fifoout_info,
214 					      0);
215 
216     g_type_add_interface_static(ags_type_fifoout,
217 				AGS_TYPE_CONNECTABLE,
218 				&ags_connectable_interface_info);
219 
220     g_type_add_interface_static(ags_type_fifoout,
221 				AGS_TYPE_SOUNDCARD,
222 				&ags_soundcard_interface_info);
223 
224     g_once_init_leave(&g_define_type_id__volatile, ags_type_fifoout);
225   }
226 
227   return g_define_type_id__volatile;
228 }
229 
230 GType
ags_fifoout_flags_get_type()231 ags_fifoout_flags_get_type()
232 {
233   static volatile gsize g_flags_type_id__volatile;
234 
235   if(g_once_init_enter (&g_flags_type_id__volatile)){
236     static const GFlagsValue values[] = {
237       { AGS_FIFOOUT_ADDED_TO_REGISTRY, "AGS_FIFOOUT_ADDED_TO_REGISTRY", "fifoout-added-to-registry" },
238       { AGS_FIFOOUT_CONNECTED, "AGS_FIFOOUT_CONNECTED", "fifoout-connected" },
239       { AGS_FIFOOUT_BUFFER0, "AGS_FIFOOUT_BUFFER0", "fifoout-buffer0" },
240       { AGS_FIFOOUT_BUFFER1, "AGS_FIFOOUT_BUFFER1", "fifoout-buffer1" },
241       { AGS_FIFOOUT_BUFFER2, "AGS_FIFOOUT_BUFFER2", "fifoout-buffer2" },
242       { AGS_FIFOOUT_BUFFER3, "AGS_FIFOOUT_BUFFER3", "fifoout-buffer3" },
243       { AGS_FIFOOUT_ATTACK_FIRST, "AGS_FIFOOUT_ATTACK_FIRST", "fifoout-attack-first" },
244       { AGS_FIFOOUT_PLAY, "AGS_FIFOOUT_PLAY", "fifoout-play" },
245       { AGS_FIFOOUT_SHUTDOWN, "AGS_FIFOOUT_SHUTDOWN", "fifoout-shutdown" },
246       { AGS_FIFOOUT_START_PLAY, "AGS_FIFOOUT_START_PLAY", "fifoout-start-play" },
247       { AGS_FIFOOUT_NONBLOCKING, "AGS_FIFOOUT_NONBLOCKING", "fifoout-nonblocking" },
248       { AGS_FIFOOUT_INITIALIZED, "AGS_FIFOOUT_INITIALIZED", "fifoout-initialized" },
249       { 0, NULL, NULL }
250     };
251 
252     GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsFifooutFlags"), values);
253 
254     g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
255   }
256 
257   return g_flags_type_id__volatile;
258 }
259 
260 void
ags_fifoout_class_init(AgsFifooutClass * fifoout)261 ags_fifoout_class_init(AgsFifooutClass *fifoout)
262 {
263   GObjectClass *gobject;
264 
265   GParamSpec *param_spec;
266 
267   ags_fifoout_parent_class = g_type_class_peek_parent(fifoout);
268 
269   /* GObjectClass */
270   gobject = (GObjectClass *) fifoout;
271 
272   gobject->set_property = ags_fifoout_set_property;
273   gobject->get_property = ags_fifoout_get_property;
274 
275   gobject->dispose = ags_fifoout_dispose;
276   gobject->finalize = ags_fifoout_finalize;
277 
278   /* properties */
279   /**
280    * AgsFifoout:device:
281    *
282    * The fifo soundcard indentifier
283    *
284    * Since: 3.0.0
285    */
286   param_spec = g_param_spec_string("device",
287 				   i18n_pspec("the device identifier"),
288 				   i18n_pspec("The device to perform output to"),
289 				   AGS_FIFOOUT_DEFAULT_DEVICE,
290 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
291   g_object_class_install_property(gobject,
292 				  PROP_DEVICE,
293 				  param_spec);
294 
295   /**
296    * AgsFifoout:dsp-channels:
297    *
298    * The dsp channel count
299    *
300    * Since: 3.0.0
301    */
302   param_spec = g_param_spec_uint("dsp-channels",
303 				 i18n_pspec("count of DSP channels"),
304 				 i18n_pspec("The count of DSP channels to use"),
305 				 AGS_SOUNDCARD_MIN_DSP_CHANNELS,
306 				 AGS_SOUNDCARD_MAX_DSP_CHANNELS,
307 				 AGS_SOUNDCARD_DEFAULT_DSP_CHANNELS,
308 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
309   g_object_class_install_property(gobject,
310 				  PROP_DSP_CHANNELS,
311 				  param_spec);
312 
313   /**
314    * AgsFifoout:pcm-channels:
315    *
316    * The pcm channel count
317    *
318    * Since: 3.0.0
319    */
320   param_spec = g_param_spec_uint("pcm-channels",
321 				 i18n_pspec("count of PCM channels"),
322 				 i18n_pspec("The count of PCM channels to use"),
323 				 AGS_SOUNDCARD_MIN_PCM_CHANNELS,
324 				 AGS_SOUNDCARD_MAX_PCM_CHANNELS,
325 				 AGS_SOUNDCARD_DEFAULT_PCM_CHANNELS,
326 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
327   g_object_class_install_property(gobject,
328 				  PROP_PCM_CHANNELS,
329 				  param_spec);
330 
331   /**
332    * AgsFifoout:format:
333    *
334    * The precision of the buffer
335    *
336    * Since: 3.0.0
337    */
338   param_spec = g_param_spec_uint("format",
339 				 i18n_pspec("precision of buffer"),
340 				 i18n_pspec("The precision to use for a frame"),
341 				 0,
342 				 G_MAXUINT32,
343 				 AGS_SOUNDCARD_DEFAULT_FORMAT,
344 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
345   g_object_class_install_property(gobject,
346 				  PROP_FORMAT,
347 				  param_spec);
348 
349   /**
350    * AgsFifoout:buffer-size:
351    *
352    * The buffer size
353    *
354    * Since: 3.0.0
355    */
356   param_spec = g_param_spec_uint("buffer-size",
357 				 i18n_pspec("frame count of a buffer"),
358 				 i18n_pspec("The count of frames a buffer contains"),
359 				 AGS_SOUNDCARD_MIN_BUFFER_SIZE,
360 				 AGS_SOUNDCARD_MAX_BUFFER_SIZE,
361 				 AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE,
362 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
363   g_object_class_install_property(gobject,
364 				  PROP_BUFFER_SIZE,
365 				  param_spec);
366 
367   /**
368    * AgsFifoout:samplerate:
369    *
370    * The samplerate
371    *
372    * Since: 3.0.0
373    */
374   param_spec = g_param_spec_uint("samplerate",
375 				 i18n_pspec("frames per second"),
376 				 i18n_pspec("The frames count played during a second"),
377 				 AGS_SOUNDCARD_MIN_SAMPLERATE,
378 				 AGS_SOUNDCARD_MAX_SAMPLERATE,
379 				 AGS_SOUNDCARD_DEFAULT_SAMPLERATE,
380 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
381   g_object_class_install_property(gobject,
382 				  PROP_SAMPLERATE,
383 				  param_spec);
384 
385   /**
386    * AgsFifoout:buffer:
387    *
388    * The buffer
389    *
390    * Since: 3.0.0
391    */
392   param_spec = g_param_spec_pointer("buffer",
393 				    i18n_pspec("the buffer"),
394 				    i18n_pspec("The buffer to play"),
395 				    G_PARAM_READABLE);
396   g_object_class_install_property(gobject,
397 				  PROP_BUFFER,
398 				  param_spec);
399 
400   /**
401    * AgsFifoout:bpm:
402    *
403    * Beats per minute
404    *
405    * Since: 3.0.0
406    */
407   param_spec = g_param_spec_double("bpm",
408 				   i18n_pspec("beats per minute"),
409 				   i18n_pspec("Beats per minute to use"),
410 				   1.0,
411 				   240.0,
412 				   AGS_SOUNDCARD_DEFAULT_BPM,
413 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
414   g_object_class_install_property(gobject,
415 				  PROP_BPM,
416 				  param_spec);
417 
418   /**
419    * AgsFifoout:delay-factor:
420    *
421    * tact
422    *
423    * Since: 3.0.0
424    */
425   param_spec = g_param_spec_double("delay-factor",
426 				   i18n_pspec("delay factor"),
427 				   i18n_pspec("The delay factor"),
428 				   0.0,
429 				   16.0,
430 				   1.0,
431 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
432   g_object_class_install_property(gobject,
433 				  PROP_DELAY_FACTOR,
434 				  param_spec);
435 
436   /**
437    * AgsFifoout:attack:
438    *
439    * Attack of the buffer
440    *
441    * Since: 3.0.0
442    */
443   param_spec = g_param_spec_pointer("attack",
444 				    i18n_pspec("attack of buffer"),
445 				    i18n_pspec("The attack to use for the buffer"),
446 				    G_PARAM_READABLE);
447   g_object_class_install_property(gobject,
448 				  PROP_ATTACK,
449 				  param_spec);
450 
451   /* AgsFifooutClass */
452 }
453 
454 GQuark
ags_fifoout_error_quark()455 ags_fifoout_error_quark()
456 {
457   return(g_quark_from_static_string("ags-fifoout-error-quark"));
458 }
459 
460 void
ags_fifoout_connectable_interface_init(AgsConnectableInterface * connectable)461 ags_fifoout_connectable_interface_init(AgsConnectableInterface *connectable)
462 {
463   connectable->get_uuid = ags_fifoout_get_uuid;
464   connectable->has_resource = ags_fifoout_has_resource;
465 
466   connectable->is_ready = ags_fifoout_is_ready;
467   connectable->add_to_registry = ags_fifoout_add_to_registry;
468   connectable->remove_from_registry = ags_fifoout_remove_from_registry;
469 
470   connectable->list_resource = ags_fifoout_list_resource;
471   connectable->xml_compose = ags_fifoout_xml_compose;
472   connectable->xml_parse = ags_fifoout_xml_parse;
473 
474   connectable->is_connected = ags_fifoout_is_connected;
475   connectable->connect = ags_fifoout_connect;
476   connectable->disconnect = ags_fifoout_disconnect;
477 
478   connectable->connect_connection = NULL;
479   connectable->disconnect_connection = NULL;
480 }
481 
482 void
ags_fifoout_soundcard_interface_init(AgsSoundcardInterface * soundcard)483 ags_fifoout_soundcard_interface_init(AgsSoundcardInterface *soundcard)
484 {
485   soundcard->set_device = ags_fifoout_set_device;
486   soundcard->get_device = ags_fifoout_get_device;
487 
488   soundcard->set_presets = ags_fifoout_set_presets;
489   soundcard->get_presets = ags_fifoout_get_presets;
490 
491   soundcard->list_cards = ags_fifoout_list_cards;
492   soundcard->pcm_info = ags_fifoout_pcm_info;
493   soundcard->get_capability = NULL;
494 
495   soundcard->is_available = ags_fifoout_is_available;
496 
497   soundcard->is_starting =  ags_fifoout_is_starting;
498   soundcard->is_playing = ags_fifoout_is_playing;
499   soundcard->is_recording = NULL;
500 
501   soundcard->get_uptime = ags_fifoout_get_uptime;
502 
503   soundcard->play_init = ags_fifoout_fifo_init;
504   soundcard->play = ags_fifoout_fifo_play;
505 
506   soundcard->record_init = NULL;
507   soundcard->record = NULL;
508 
509   soundcard->stop = ags_fifoout_fifo_free;
510 
511   soundcard->tic = ags_fifoout_tic;
512   soundcard->offset_changed = ags_fifoout_offset_changed;
513 
514   soundcard->set_bpm = ags_fifoout_set_bpm;
515   soundcard->get_bpm = ags_fifoout_get_bpm;
516 
517   soundcard->set_delay_factor = ags_fifoout_set_delay_factor;
518   soundcard->get_delay_factor = ags_fifoout_get_delay_factor;
519 
520   soundcard->get_absolute_delay = ags_fifoout_get_absolute_delay;
521 
522   soundcard->get_delay = ags_fifoout_get_delay;
523   soundcard->get_attack = ags_fifoout_get_attack;
524 
525   soundcard->get_buffer = ags_fifoout_get_buffer;
526   soundcard->get_next_buffer = ags_fifoout_get_next_buffer;
527 
528   soundcard->get_delay_counter = ags_fifoout_get_delay_counter;
529 
530   soundcard->set_note_offset = ags_fifoout_set_note_offset;
531   soundcard->get_note_offset = ags_fifoout_get_note_offset;
532 
533   soundcard->set_note_offset_absolute = ags_fifoout_set_note_offset_absolute;
534   soundcard->get_note_offset_absolute = ags_fifoout_get_note_offset_absolute;
535 
536   soundcard->set_loop = ags_fifoout_set_loop;
537   soundcard->get_loop = ags_fifoout_get_loop;
538 
539   soundcard->get_loop_offset = ags_fifoout_get_loop_offset;
540 }
541 
542 void
ags_fifoout_init(AgsFifoout * fifoout)543 ags_fifoout_init(AgsFifoout *fifoout)
544 {
545   AgsConfig *config;
546 
547   gchar *str;
548   gchar *segmentation;
549 
550   guint denumerator, numerator;
551 
552   fifoout->flags = 0;
553 
554   /* insert fifoout mutex */
555   g_rec_mutex_init(&(fifoout->obj_mutex));
556 
557   /* uuid */
558   fifoout->uuid = ags_uuid_alloc();
559   ags_uuid_generate(fifoout->uuid);
560 
561   /* flags */
562   config = ags_config_get_instance();
563 
564   /* presets */
565   fifoout->dsp_channels = ags_soundcard_helper_config_get_dsp_channels(config);
566   fifoout->pcm_channels = ags_soundcard_helper_config_get_pcm_channels(config);
567 
568   fifoout->samplerate = ags_soundcard_helper_config_get_samplerate(config);
569   fifoout->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
570   fifoout->format = ags_soundcard_helper_config_get_format(config);
571 
572   /*  */
573   fifoout->device = AGS_FIFOOUT_DEFAULT_DEVICE;
574   fifoout->fifo_fd = -1;
575 
576   /* buffer */
577   fifoout->buffer = (void **) malloc(4 * sizeof(void*));
578 
579   fifoout->buffer[0] = NULL;
580   fifoout->buffer[1] = NULL;
581   fifoout->buffer[2] = NULL;
582   fifoout->buffer[3] = NULL;
583 
584   g_atomic_int_set(&(fifoout->available),
585 		   FALSE);
586 
587   fifoout->ring_buffer_size = AGS_FIFOOUT_DEFAULT_RING_BUFFER_SIZE;
588   fifoout->nth_ring_buffer = 0;
589 
590   fifoout->ring_buffer = NULL;
591 
592   ags_fifoout_realloc_buffer(fifoout);
593 
594   /* bpm */
595   fifoout->bpm = AGS_SOUNDCARD_DEFAULT_BPM;
596 
597   /* delay factor */
598   fifoout->delay_factor = AGS_SOUNDCARD_DEFAULT_DELAY_FACTOR;
599 
600   /* segmentation */
601   segmentation = ags_config_get_value(config,
602 				      AGS_CONFIG_GENERIC,
603 				      "segmentation");
604 
605   if(segmentation != NULL){
606     sscanf(segmentation, "%d/%d",
607 	   &denumerator,
608 	   &numerator);
609 
610     fifoout->delay_factor = 1.0 / numerator * (numerator / denumerator);
611 
612     g_free(segmentation);
613   }
614 
615   /* delay and attack */
616   fifoout->delay = (gdouble *) malloc((int) 2 * AGS_SOUNDCARD_DEFAULT_PERIOD *
617 				      sizeof(gdouble));
618 
619   fifoout->attack = (guint *) malloc((int) 2 * AGS_SOUNDCARD_DEFAULT_PERIOD *
620 				     sizeof(guint));
621 
622   ags_fifoout_adjust_delay_and_attack(fifoout);
623 
624   /* counters */
625   fifoout->tact_counter = 0.0;
626   fifoout->delay_counter = 0;
627   fifoout->tic_counter = 0;
628 
629   fifoout->note_offset = 0;
630   fifoout->note_offset_absolute = 0;
631 
632   fifoout->loop_left = AGS_SOUNDCARD_DEFAULT_LOOP_LEFT;
633   fifoout->loop_right = AGS_SOUNDCARD_DEFAULT_LOOP_RIGHT;
634 
635   fifoout->do_loop = FALSE;
636 
637   fifoout->loop_offset = 0;
638 }
639 
640 void
ags_fifoout_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)641 ags_fifoout_set_property(GObject *gobject,
642 			 guint prop_id,
643 			 const GValue *value,
644 			 GParamSpec *param_spec)
645 {
646   AgsFifoout *fifoout;
647 
648   GRecMutex *fifoout_mutex;
649 
650   fifoout = AGS_FIFOOUT(gobject);
651 
652   /* get fifoout mutex */
653   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
654 
655   switch(prop_id){
656   case PROP_DEVICE:
657     {
658       char *device;
659 
660       device = (char *) g_value_get_string(value);
661 
662       g_rec_mutex_lock(fifoout_mutex);
663 
664       fifoout->device = g_strdup(device);
665 
666       g_rec_mutex_unlock(fifoout_mutex);
667     }
668     break;
669   case PROP_DSP_CHANNELS:
670     {
671       guint dsp_channels;
672 
673       dsp_channels = g_value_get_uint(value);
674 
675       g_rec_mutex_lock(fifoout_mutex);
676 
677       if(dsp_channels == fifoout->dsp_channels){
678 	g_rec_mutex_unlock(fifoout_mutex);
679 
680 	return;
681       }
682 
683       fifoout->dsp_channels = dsp_channels;
684 
685       g_rec_mutex_unlock(fifoout_mutex);
686     }
687     break;
688   case PROP_PCM_CHANNELS:
689     {
690       guint pcm_channels;
691 
692       pcm_channels = g_value_get_uint(value);
693 
694       g_rec_mutex_lock(fifoout_mutex);
695 
696       if(pcm_channels == fifoout->pcm_channels){
697 	g_rec_mutex_unlock(fifoout_mutex);
698 
699 	return;
700       }
701 
702       fifoout->pcm_channels = pcm_channels;
703 
704       g_rec_mutex_unlock(fifoout_mutex);
705 
706       ags_fifoout_realloc_buffer(fifoout);
707     }
708     break;
709   case PROP_FORMAT:
710     {
711       guint format;
712 
713       format = g_value_get_uint(value);
714 
715       g_rec_mutex_lock(fifoout_mutex);
716 
717       if(format == fifoout->format){
718 	g_rec_mutex_unlock(fifoout_mutex);
719 
720 	return;
721       }
722 
723       fifoout->format = format;
724 
725       g_rec_mutex_unlock(fifoout_mutex);
726 
727       ags_fifoout_realloc_buffer(fifoout);
728     }
729     break;
730   case PROP_BUFFER_SIZE:
731     {
732       guint buffer_size;
733 
734       buffer_size = g_value_get_uint(value);
735 
736       g_rec_mutex_lock(fifoout_mutex);
737 
738       if(buffer_size == fifoout->buffer_size){
739 	g_rec_mutex_unlock(fifoout_mutex);
740 
741 	return;
742       }
743 
744       fifoout->buffer_size = buffer_size;
745 
746       g_rec_mutex_unlock(fifoout_mutex);
747 
748       ags_fifoout_realloc_buffer(fifoout);
749       ags_fifoout_adjust_delay_and_attack(fifoout);
750     }
751     break;
752   case PROP_SAMPLERATE:
753     {
754       guint samplerate;
755 
756       samplerate = g_value_get_uint(value);
757 
758       g_rec_mutex_lock(fifoout_mutex);
759 
760       if(samplerate == fifoout->samplerate){
761 	g_rec_mutex_unlock(fifoout_mutex);
762 
763 	return;
764       }
765 
766       fifoout->samplerate = samplerate;
767 
768       g_rec_mutex_unlock(fifoout_mutex);
769 
770       ags_fifoout_adjust_delay_and_attack(fifoout);
771     }
772     break;
773   case PROP_BUFFER:
774     {
775       //TODO:JK: implement me
776     }
777     break;
778   case PROP_BPM:
779     {
780       gdouble bpm;
781 
782       bpm = g_value_get_double(value);
783 
784       g_rec_mutex_lock(fifoout_mutex);
785 
786       if(bpm == fifoout->bpm){
787 	g_rec_mutex_unlock(fifoout_mutex);
788 
789 	return;
790       }
791 
792       fifoout->bpm = bpm;
793 
794       g_rec_mutex_unlock(fifoout_mutex);
795 
796       ags_fifoout_adjust_delay_and_attack(fifoout);
797     }
798     break;
799   case PROP_DELAY_FACTOR:
800     {
801       gdouble delay_factor;
802 
803       delay_factor = g_value_get_double(value);
804 
805       g_rec_mutex_lock(fifoout_mutex);
806 
807       if(delay_factor == fifoout->delay_factor){
808 	g_rec_mutex_unlock(fifoout_mutex);
809 
810 	return;
811       }
812 
813       fifoout->delay_factor = delay_factor;
814 
815       g_rec_mutex_unlock(fifoout_mutex);
816 
817       ags_fifoout_adjust_delay_and_attack(fifoout);
818     }
819     break;
820   default:
821     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
822     break;
823   }
824 }
825 
826 void
ags_fifoout_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)827 ags_fifoout_get_property(GObject *gobject,
828 			 guint prop_id,
829 			 GValue *value,
830 			 GParamSpec *param_spec)
831 {
832   AgsFifoout *fifoout;
833 
834   GRecMutex *fifoout_mutex;
835 
836   fifoout = AGS_FIFOOUT(gobject);
837 
838   /* get fifoout mutex */
839   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
840 
841   switch(prop_id){
842   case PROP_DEVICE:
843     {
844       g_rec_mutex_lock(fifoout_mutex);
845 
846       g_value_set_string(value, fifoout->device);
847 
848       g_rec_mutex_unlock(fifoout_mutex);
849     }
850     break;
851   case PROP_DSP_CHANNELS:
852     {
853       g_rec_mutex_lock(fifoout_mutex);
854 
855       g_value_set_uint(value, fifoout->dsp_channels);
856 
857       g_rec_mutex_unlock(fifoout_mutex);
858     }
859     break;
860   case PROP_PCM_CHANNELS:
861     {
862       g_rec_mutex_lock(fifoout_mutex);
863 
864       g_value_set_uint(value, fifoout->pcm_channels);
865 
866       g_rec_mutex_unlock(fifoout_mutex);
867     }
868     break;
869   case PROP_FORMAT:
870     {
871       g_rec_mutex_lock(fifoout_mutex);
872 
873       g_value_set_uint(value, fifoout->format);
874 
875       g_rec_mutex_unlock(fifoout_mutex);
876     }
877     break;
878   case PROP_BUFFER_SIZE:
879     {
880       g_rec_mutex_lock(fifoout_mutex);
881 
882       g_value_set_uint(value, fifoout->buffer_size);
883 
884       g_rec_mutex_unlock(fifoout_mutex);
885     }
886     break;
887   case PROP_SAMPLERATE:
888     {
889       g_rec_mutex_lock(fifoout_mutex);
890 
891       g_value_set_uint(value, fifoout->samplerate);
892 
893       g_rec_mutex_unlock(fifoout_mutex);
894     }
895     break;
896   case PROP_BUFFER:
897     {
898       g_rec_mutex_lock(fifoout_mutex);
899 
900       g_value_set_pointer(value, fifoout->buffer);
901 
902       g_rec_mutex_unlock(fifoout_mutex);
903     }
904     break;
905   case PROP_BPM:
906     {
907       g_rec_mutex_lock(fifoout_mutex);
908 
909       g_value_set_double(value, fifoout->bpm);
910 
911       g_rec_mutex_unlock(fifoout_mutex);
912     }
913     break;
914   case PROP_DELAY_FACTOR:
915     {
916       g_rec_mutex_lock(fifoout_mutex);
917 
918       g_value_set_double(value, fifoout->delay_factor);
919 
920       g_rec_mutex_unlock(fifoout_mutex);
921     }
922     break;
923   case PROP_ATTACK:
924     {
925       g_rec_mutex_lock(fifoout_mutex);
926 
927       g_value_set_pointer(value, fifoout->attack);
928 
929       g_rec_mutex_unlock(fifoout_mutex);
930     }
931     break;
932   default:
933     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
934     break;
935   }
936 }
937 
938 void
ags_fifoout_dispose(GObject * gobject)939 ags_fifoout_dispose(GObject *gobject)
940 {
941   AgsFifoout *fifoout;
942 
943   fifoout = AGS_FIFOOUT(gobject);
944 
945   /* call parent */
946   G_OBJECT_CLASS(ags_fifoout_parent_class)->dispose(gobject);
947 }
948 
949 void
ags_fifoout_finalize(GObject * gobject)950 ags_fifoout_finalize(GObject *gobject)
951 {
952   AgsFifoout *fifoout;
953 
954   fifoout = AGS_FIFOOUT(gobject);
955 
956   /* free output buffer */
957   free(fifoout->buffer[0]);
958   free(fifoout->buffer[1]);
959   free(fifoout->buffer[2]);
960   free(fifoout->buffer[3]);
961 
962   /* free buffer array */
963   free(fifoout->buffer);
964 
965   /* free AgsAttack */
966   free(fifoout->attack);
967 
968   /* call parent */
969   G_OBJECT_CLASS(ags_fifoout_parent_class)->finalize(gobject);
970 }
971 
972 AgsUUID*
ags_fifoout_get_uuid(AgsConnectable * connectable)973 ags_fifoout_get_uuid(AgsConnectable *connectable)
974 {
975   AgsFifoout *fifoout;
976 
977   AgsUUID *ptr;
978 
979   GRecMutex *fifoout_mutex;
980 
981   fifoout = AGS_FIFOOUT(connectable);
982 
983   /* get fifoout signal mutex */
984   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
985 
986   /* get UUID */
987   g_rec_mutex_lock(fifoout_mutex);
988 
989   ptr = fifoout->uuid;
990 
991   g_rec_mutex_unlock(fifoout_mutex);
992 
993   return(ptr);
994 }
995 
996 gboolean
ags_fifoout_has_resource(AgsConnectable * connectable)997 ags_fifoout_has_resource(AgsConnectable *connectable)
998 {
999   return(FALSE);
1000 }
1001 
1002 gboolean
ags_fifoout_is_ready(AgsConnectable * connectable)1003 ags_fifoout_is_ready(AgsConnectable *connectable)
1004 {
1005   AgsFifoout *fifoout;
1006 
1007   gboolean is_ready;
1008 
1009   fifoout = AGS_FIFOOUT(connectable);
1010 
1011   /* check is added */
1012   is_ready = ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_ADDED_TO_REGISTRY);
1013 
1014   return(is_ready);
1015 }
1016 
1017 void
ags_fifoout_add_to_registry(AgsConnectable * connectable)1018 ags_fifoout_add_to_registry(AgsConnectable *connectable)
1019 {
1020   AgsFifoout *fifoout;
1021 
1022   if(ags_connectable_is_ready(connectable)){
1023     return;
1024   }
1025 
1026   fifoout = AGS_FIFOOUT(connectable);
1027 
1028   ags_fifoout_set_flags(fifoout, AGS_FIFOOUT_ADDED_TO_REGISTRY);
1029 }
1030 
1031 void
ags_fifoout_remove_from_registry(AgsConnectable * connectable)1032 ags_fifoout_remove_from_registry(AgsConnectable *connectable)
1033 {
1034   AgsFifoout *fifoout;
1035 
1036   if(!ags_connectable_is_ready(connectable)){
1037     return;
1038   }
1039 
1040   fifoout = AGS_FIFOOUT(connectable);
1041 
1042   ags_fifoout_unset_flags(fifoout, AGS_FIFOOUT_ADDED_TO_REGISTRY);
1043 }
1044 
1045 xmlNode*
ags_fifoout_list_resource(AgsConnectable * connectable)1046 ags_fifoout_list_resource(AgsConnectable *connectable)
1047 {
1048   xmlNode *node;
1049 
1050   node = NULL;
1051 
1052   //TODO:JK: implement me
1053 
1054   return(node);
1055 }
1056 
1057 xmlNode*
ags_fifoout_xml_compose(AgsConnectable * connectable)1058 ags_fifoout_xml_compose(AgsConnectable *connectable)
1059 {
1060   xmlNode *node;
1061 
1062   node = NULL;
1063 
1064   //TODO:JK: implement me
1065 
1066   return(node);
1067 }
1068 
1069 void
ags_fifoout_xml_parse(AgsConnectable * connectable,xmlNode * node)1070 ags_fifoout_xml_parse(AgsConnectable *connectable,
1071 		      xmlNode *node)
1072 {
1073   //TODO:JK: implement me
1074 }
1075 
1076 gboolean
ags_fifoout_is_connected(AgsConnectable * connectable)1077 ags_fifoout_is_connected(AgsConnectable *connectable)
1078 {
1079   AgsFifoout *fifoout;
1080 
1081   gboolean is_connected;
1082 
1083   fifoout = AGS_FIFOOUT(connectable);
1084 
1085   /* check is connected */
1086   is_connected = ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_CONNECTED);
1087 
1088   return(is_connected);
1089 }
1090 
1091 void
ags_fifoout_connect(AgsConnectable * connectable)1092 ags_fifoout_connect(AgsConnectable *connectable)
1093 {
1094   AgsFifoout *fifoout;
1095 
1096   if(ags_connectable_is_connected(connectable)){
1097     return;
1098   }
1099 
1100   fifoout = AGS_FIFOOUT(connectable);
1101 
1102   ags_fifoout_set_flags(fifoout, AGS_FIFOOUT_CONNECTED);
1103 }
1104 
1105 void
ags_fifoout_disconnect(AgsConnectable * connectable)1106 ags_fifoout_disconnect(AgsConnectable *connectable)
1107 {
1108 
1109   AgsFifoout *fifoout;
1110 
1111   if(!ags_connectable_is_connected(connectable)){
1112     return;
1113   }
1114 
1115   fifoout = AGS_FIFOOUT(connectable);
1116 
1117   ags_fifoout_unset_flags(fifoout, AGS_FIFOOUT_CONNECTED);
1118 }
1119 
1120 /**
1121  * ags_fifoout_test_flags:
1122  * @fifoout: the #AgsFifoout
1123  * @flags: the flags
1124  *
1125  * Test @flags to be set on @fifoout.
1126  *
1127  * Returns: %TRUE if flags are set, else %FALSE
1128  *
1129  * Since: 3.0.0
1130  */
1131 gboolean
ags_fifoout_test_flags(AgsFifoout * fifoout,guint flags)1132 ags_fifoout_test_flags(AgsFifoout *fifoout, guint flags)
1133 {
1134   gboolean retval;
1135 
1136   GRecMutex *fifoout_mutex;
1137 
1138   if(!AGS_IS_FIFOOUT(fifoout)){
1139     return(FALSE);
1140   }
1141 
1142   /* get fifoout mutex */
1143   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1144 
1145   /* test */
1146   g_rec_mutex_lock(fifoout_mutex);
1147 
1148   retval = (flags & (fifoout->flags)) ? TRUE: FALSE;
1149 
1150   g_rec_mutex_unlock(fifoout_mutex);
1151 
1152   return(retval);
1153 }
1154 
1155 /**
1156  * ags_fifoout_set_flags:
1157  * @fifoout: the #AgsFifoout
1158  * @flags: see #AgsFifooutFlags-enum
1159  *
1160  * Enable a feature of @fifoout.
1161  *
1162  * Since: 3.0.0
1163  */
1164 void
ags_fifoout_set_flags(AgsFifoout * fifoout,guint flags)1165 ags_fifoout_set_flags(AgsFifoout *fifoout, guint flags)
1166 {
1167   GRecMutex *fifoout_mutex;
1168 
1169   if(!AGS_IS_FIFOOUT(fifoout)){
1170     return;
1171   }
1172 
1173   /* get fifoout mutex */
1174   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1175 
1176   //TODO:JK: add more?
1177 
1178   /* set flags */
1179   g_rec_mutex_lock(fifoout_mutex);
1180 
1181   fifoout->flags |= flags;
1182 
1183   g_rec_mutex_unlock(fifoout_mutex);
1184 }
1185 
1186 /**
1187  * ags_fifoout_unset_flags:
1188  * @fifoout: the #AgsFifoout
1189  * @flags: see #AgsFifooutFlags-enum
1190  *
1191  * Disable a feature of @fifoout.
1192  *
1193  * Since: 3.0.0
1194  */
1195 void
ags_fifoout_unset_flags(AgsFifoout * fifoout,guint flags)1196 ags_fifoout_unset_flags(AgsFifoout *fifoout, guint flags)
1197 {
1198   GRecMutex *fifoout_mutex;
1199 
1200   if(!AGS_IS_FIFOOUT(fifoout)){
1201     return;
1202   }
1203 
1204   /* get fifoout mutex */
1205   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1206 
1207   //TODO:JK: add more?
1208 
1209   /* unset flags */
1210   g_rec_mutex_lock(fifoout_mutex);
1211 
1212   fifoout->flags &= (~flags);
1213 
1214   g_rec_mutex_unlock(fifoout_mutex);
1215 }
1216 
1217 
1218 void
ags_fifoout_set_device(AgsSoundcard * soundcard,gchar * device)1219 ags_fifoout_set_device(AgsSoundcard *soundcard,
1220 		       gchar *device)
1221 {
1222   AgsFifoout *fifoout;
1223 
1224   GRecMutex *fifoout_mutex;
1225 
1226   fifoout = AGS_FIFOOUT(soundcard);
1227 
1228   /* get fifoout mutex */
1229   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1230 
1231   /* set device */
1232   g_rec_mutex_lock(fifoout_mutex);
1233 
1234   fifoout->device = g_strdup(device);
1235 
1236   g_rec_mutex_unlock(fifoout_mutex);
1237 }
1238 
1239 gchar*
ags_fifoout_get_device(AgsSoundcard * soundcard)1240 ags_fifoout_get_device(AgsSoundcard *soundcard)
1241 {
1242   AgsFifoout *fifoout;
1243 
1244   gchar *device;
1245 
1246   GRecMutex *fifoout_mutex;
1247 
1248   fifoout = AGS_FIFOOUT(soundcard);
1249 
1250   /* get fifoout mutex */
1251   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1252 
1253   /* get device */
1254   g_rec_mutex_lock(fifoout_mutex);
1255 
1256   device = fifoout->device;
1257 
1258   g_rec_mutex_unlock(fifoout_mutex);
1259 
1260   return(device);
1261 }
1262 
1263 void
ags_fifoout_set_presets(AgsSoundcard * soundcard,guint channels,guint rate,guint buffer_size,guint format)1264 ags_fifoout_set_presets(AgsSoundcard *soundcard,
1265 			guint channels,
1266 			guint rate,
1267 			guint buffer_size,
1268 			guint format)
1269 {
1270   AgsFifoout *fifoout;
1271 
1272   fifoout = AGS_FIFOOUT(soundcard);
1273 
1274   g_object_set(fifoout,
1275 	       "pcm-channels", channels,
1276 	       "samplerate", rate,
1277 	       "buffer-size", buffer_size,
1278 	       "format", format,
1279 	       NULL);
1280 }
1281 
1282 void
ags_fifoout_get_presets(AgsSoundcard * soundcard,guint * channels,guint * rate,guint * buffer_size,guint * format)1283 ags_fifoout_get_presets(AgsSoundcard *soundcard,
1284 			guint *channels,
1285 			guint *rate,
1286 			guint *buffer_size,
1287 			guint *format)
1288 {
1289   AgsFifoout *fifoout;
1290 
1291   GRecMutex *fifoout_mutex;
1292 
1293   fifoout = AGS_FIFOOUT(soundcard);
1294 
1295 
1296   /* get fifoout mutex */
1297   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1298 
1299   /* get presets */
1300   g_rec_mutex_lock(fifoout_mutex);
1301 
1302   if(channels != NULL){
1303     *channels = fifoout->pcm_channels;
1304   }
1305 
1306   if(rate != NULL){
1307     *rate = fifoout->samplerate;
1308   }
1309 
1310   if(buffer_size != NULL){
1311     *buffer_size = fifoout->buffer_size;
1312   }
1313 
1314   if(format != NULL){
1315     *format = fifoout->format;
1316   }
1317 
1318   g_rec_mutex_unlock(fifoout_mutex);
1319 }
1320 
1321 void
ags_fifoout_list_cards(AgsSoundcard * soundcard,GList ** card_id,GList ** card_name)1322 ags_fifoout_list_cards(AgsSoundcard *soundcard,
1323 		       GList **card_id, GList **card_name)
1324 {
1325   AgsFifoout *fifoout;
1326 
1327   fifoout = AGS_FIFOOUT(soundcard);
1328 
1329   if(card_id != NULL){
1330     *card_id = NULL;
1331   }
1332 
1333   if(card_name != NULL){
1334     *card_name = NULL;
1335   }
1336 
1337   //TODO:JK: implement me
1338 
1339   if(card_id != NULL){
1340     *card_id = g_list_reverse(*card_id);
1341   }
1342 
1343   if(card_name != NULL){
1344     *card_name = g_list_reverse(*card_name);
1345   }
1346 }
1347 
1348 void
ags_fifoout_pcm_info(AgsSoundcard * soundcard,char * card_id,guint * channels_min,guint * channels_max,guint * rate_min,guint * rate_max,guint * buffer_size_min,guint * buffer_size_max,GError ** error)1349 ags_fifoout_pcm_info(AgsSoundcard *soundcard,
1350 		     char *card_id,
1351 		     guint *channels_min, guint *channels_max,
1352 		     guint *rate_min, guint *rate_max,
1353 		     guint *buffer_size_min, guint *buffer_size_max,
1354 		     GError **error)
1355 {
1356   AgsFifoout *fifoout;
1357 
1358   fifoout = AGS_FIFOOUT(soundcard);
1359 
1360   //TODO:JK: implement me
1361 }
1362 
1363 gboolean
ags_fifoout_is_available(AgsSoundcard * soundcard)1364 ags_fifoout_is_available(AgsSoundcard *soundcard)
1365 {
1366   AgsFifoout *fifoout;
1367 
1368   //TODO:JK: implement me
1369 
1370   return(TRUE);
1371 }
1372 
1373 gboolean
ags_fifoout_is_starting(AgsSoundcard * soundcard)1374 ags_fifoout_is_starting(AgsSoundcard *soundcard)
1375 {
1376   AgsFifoout *fifoout;
1377 
1378   gboolean is_starting;
1379 
1380   GRecMutex *fifoout_mutex;
1381 
1382   fifoout = AGS_FIFOOUT(soundcard);
1383 
1384   /* get fifoout mutex */
1385   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1386 
1387   /* check is starting */
1388   g_rec_mutex_lock(fifoout_mutex);
1389 
1390   is_starting = ((AGS_FIFOOUT_START_PLAY & (fifoout->flags)) != 0) ? TRUE: FALSE;
1391 
1392   g_rec_mutex_unlock(fifoout_mutex);
1393 
1394   return(is_starting);
1395 }
1396 
1397 gboolean
ags_fifoout_is_playing(AgsSoundcard * soundcard)1398 ags_fifoout_is_playing(AgsSoundcard *soundcard)
1399 {
1400   AgsFifoout *fifoout;
1401 
1402   gboolean is_playing;
1403 
1404   GRecMutex *fifoout_mutex;
1405 
1406   fifoout = AGS_FIFOOUT(soundcard);
1407 
1408   /* get fifoout mutex */
1409   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1410 
1411   /* check is starting */
1412   g_rec_mutex_lock(fifoout_mutex);
1413 
1414   is_playing = ((AGS_FIFOOUT_PLAY & (fifoout->flags)) != 0) ? TRUE: FALSE;
1415 
1416   g_rec_mutex_unlock(fifoout_mutex);
1417 
1418   return(is_playing);
1419 }
1420 
1421 gchar*
ags_fifoout_get_uptime(AgsSoundcard * soundcard)1422 ags_fifoout_get_uptime(AgsSoundcard *soundcard)
1423 {
1424   gchar *uptime;
1425 
1426   if(ags_soundcard_is_playing(soundcard)){
1427     guint samplerate;
1428     guint buffer_size;
1429 
1430     guint note_offset;
1431     gdouble bpm;
1432     gdouble delay_factor;
1433 
1434     gdouble delay;
1435 
1436     ags_soundcard_get_presets(soundcard,
1437 			      NULL,
1438 			      &samplerate,
1439 			      &buffer_size,
1440 			      NULL);
1441 
1442     note_offset = ags_soundcard_get_note_offset(soundcard);
1443 
1444     bpm = ags_soundcard_get_bpm(soundcard);
1445     delay_factor = ags_soundcard_get_delay_factor(soundcard);
1446 
1447     /* calculate delays */
1448     delay = ((gdouble) samplerate / (gdouble) buffer_size) * (gdouble)(60.0 / bpm) * delay_factor;
1449 
1450     uptime = ags_time_get_uptime_from_offset(note_offset,
1451 					     bpm,
1452 					     delay,
1453 					     delay_factor);
1454   }else{
1455     uptime = g_strdup(AGS_TIME_ZERO);
1456   }
1457 
1458   return(uptime);
1459 }
1460 
1461 void
ags_fifoout_fifo_init(AgsSoundcard * soundcard,GError ** error)1462 ags_fifoout_fifo_init(AgsSoundcard *soundcard,
1463 		      GError **error)
1464 {
1465   //TODO:JK: implement me
1466 }
1467 
1468 void
ags_fifoout_fifo_play(AgsSoundcard * soundcard,GError ** error)1469 ags_fifoout_fifo_play(AgsSoundcard *soundcard,
1470 		      GError **error)
1471 {
1472   //TODO:JK: implement me
1473 }
1474 
1475 void
ags_fifoout_fifo_free(AgsSoundcard * soundcard)1476 ags_fifoout_fifo_free(AgsSoundcard *soundcard)
1477 {
1478   //TODO:JK: implement me
1479 }
1480 
1481 void
ags_fifoout_tic(AgsSoundcard * soundcard)1482 ags_fifoout_tic(AgsSoundcard *soundcard)
1483 {
1484   AgsFifoout *fifoout;
1485 
1486   gdouble delay;
1487   gdouble delay_counter;
1488   guint note_offset_absolute;
1489   guint note_offset;
1490   guint loop_left, loop_right;
1491   gboolean do_loop;
1492 
1493   GRecMutex *fifoout_mutex;
1494 
1495   fifoout = AGS_FIFOOUT(soundcard);
1496 
1497   /* get fifoout mutex */
1498   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1499 
1500   /* determine if attack should be switched */
1501   g_rec_mutex_lock(fifoout_mutex);
1502 
1503   delay = fifoout->delay[fifoout->tic_counter];
1504   delay_counter = fifoout->delay_counter;
1505 
1506   note_offset = fifoout->note_offset;
1507   note_offset_absolute = fifoout->note_offset_absolute;
1508 
1509   loop_left = fifoout->loop_left;
1510   loop_right = fifoout->loop_right;
1511 
1512   do_loop = fifoout->do_loop;
1513 
1514   g_rec_mutex_unlock(fifoout_mutex);
1515 
1516   if((guint) delay_counter + 1 >= (guint) delay){
1517     if(do_loop &&
1518        note_offset + 1 == loop_right){
1519       ags_soundcard_set_note_offset(soundcard,
1520 				    loop_left);
1521     }else{
1522       ags_soundcard_set_note_offset(soundcard,
1523 				    note_offset + 1);
1524     }
1525 
1526     ags_soundcard_set_note_offset_absolute(soundcard,
1527 					   note_offset_absolute + 1);
1528 
1529     /* delay */
1530     ags_soundcard_offset_changed(soundcard,
1531 				 note_offset);
1532 
1533     /* reset - delay counter */
1534     g_rec_mutex_lock(fifoout_mutex);
1535 
1536     fifoout->delay_counter = 0.0;
1537     fifoout->tact_counter += 1.0;
1538 
1539     g_rec_mutex_unlock(fifoout_mutex);
1540   }else{
1541     g_rec_mutex_lock(fifoout_mutex);
1542 
1543     fifoout->delay_counter += 1.0;
1544 
1545     g_rec_mutex_unlock(fifoout_mutex);
1546   }
1547 }
1548 
1549 void
ags_fifoout_offset_changed(AgsSoundcard * soundcard,guint note_offset)1550 ags_fifoout_offset_changed(AgsSoundcard *soundcard,
1551 			   guint note_offset)
1552 {
1553   AgsFifoout *fifoout;
1554 
1555   GRecMutex *fifoout_mutex;
1556 
1557   fifoout = AGS_FIFOOUT(soundcard);
1558 
1559   /* get fifoout mutex */
1560   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1561 
1562   /* offset changed */
1563   g_rec_mutex_lock(fifoout_mutex);
1564 
1565   fifoout->tic_counter += 1;
1566 
1567   if(fifoout->tic_counter == AGS_SOUNDCARD_DEFAULT_PERIOD){
1568     /* reset - tic counter i.e. modified delay index within period */
1569     fifoout->tic_counter = 0;
1570   }
1571 
1572   g_rec_mutex_unlock(fifoout_mutex);
1573 }
1574 
1575 void
ags_fifoout_set_bpm(AgsSoundcard * soundcard,gdouble bpm)1576 ags_fifoout_set_bpm(AgsSoundcard *soundcard,
1577 		    gdouble bpm)
1578 {
1579   AgsFifoout *fifoout;
1580 
1581   GRecMutex *fifoout_mutex;
1582 
1583   fifoout = AGS_FIFOOUT(soundcard);
1584 
1585   /* get fifoout mutex */
1586   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1587 
1588   /* set bpm */
1589   g_rec_mutex_lock(fifoout_mutex);
1590 
1591   fifoout->bpm = bpm;
1592 
1593   g_rec_mutex_unlock(fifoout_mutex);
1594 
1595   ags_fifoout_adjust_delay_and_attack(fifoout);
1596 }
1597 
1598 gdouble
ags_fifoout_get_bpm(AgsSoundcard * soundcard)1599 ags_fifoout_get_bpm(AgsSoundcard *soundcard)
1600 {
1601   AgsFifoout *fifoout;
1602 
1603   gdouble bpm;
1604 
1605   GRecMutex *fifoout_mutex;
1606 
1607   fifoout = AGS_FIFOOUT(soundcard);
1608 
1609   /* get fifoout mutex */
1610   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1611 
1612   /* get bpm */
1613   g_rec_mutex_lock(fifoout_mutex);
1614 
1615   bpm = fifoout->bpm;
1616 
1617   g_rec_mutex_unlock(fifoout_mutex);
1618 
1619   return(bpm);
1620 }
1621 
1622 void
ags_fifoout_set_delay_factor(AgsSoundcard * soundcard,gdouble delay_factor)1623 ags_fifoout_set_delay_factor(AgsSoundcard *soundcard,
1624 			     gdouble delay_factor)
1625 {
1626   AgsFifoout *fifoout;
1627 
1628   GRecMutex *fifoout_mutex;
1629 
1630   fifoout = AGS_FIFOOUT(soundcard);
1631 
1632   /* get fifoout mutex */
1633   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1634 
1635   /* set delay factor */
1636   g_rec_mutex_lock(fifoout_mutex);
1637 
1638   fifoout->delay_factor = delay_factor;
1639 
1640   g_rec_mutex_unlock(fifoout_mutex);
1641 
1642   ags_fifoout_adjust_delay_and_attack(fifoout);
1643 }
1644 
1645 gdouble
ags_fifoout_get_delay_factor(AgsSoundcard * soundcard)1646 ags_fifoout_get_delay_factor(AgsSoundcard *soundcard)
1647 {
1648   AgsFifoout *fifoout;
1649 
1650   gdouble delay_factor;
1651 
1652   GRecMutex *fifoout_mutex;
1653 
1654   fifoout = AGS_FIFOOUT(soundcard);
1655 
1656   /* get fifoout mutex */
1657   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1658 
1659   /* get delay factor */
1660   g_rec_mutex_lock(fifoout_mutex);
1661 
1662   delay_factor = fifoout->delay_factor;
1663 
1664   g_rec_mutex_unlock(fifoout_mutex);
1665 
1666   return(delay_factor);
1667 }
1668 
1669 gdouble
ags_fifoout_get_delay(AgsSoundcard * soundcard)1670 ags_fifoout_get_delay(AgsSoundcard *soundcard)
1671 {
1672   AgsFifoout *fifoout;
1673 
1674   guint index;
1675   gdouble delay;
1676 
1677   GRecMutex *fifoout_mutex;
1678 
1679   fifoout = AGS_FIFOOUT(soundcard);
1680 
1681   /* get fifoout mutex */
1682   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1683 
1684   /* get delay */
1685   g_rec_mutex_lock(fifoout_mutex);
1686 
1687   index = fifoout->tic_counter;
1688 
1689   delay = fifoout->delay[index];
1690 
1691   g_rec_mutex_unlock(fifoout_mutex);
1692 
1693   return(delay);
1694 }
1695 
1696 gdouble
ags_fifoout_get_absolute_delay(AgsSoundcard * soundcard)1697 ags_fifoout_get_absolute_delay(AgsSoundcard *soundcard)
1698 {
1699   AgsFifoout *fifoout;
1700 
1701   gdouble absolute_delay;
1702 
1703   GRecMutex *fifoout_mutex;
1704 
1705   fifoout = AGS_FIFOOUT(soundcard);
1706 
1707   /* get fifoout mutex */
1708   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1709 
1710   /* get absolute delay */
1711   g_rec_mutex_lock(fifoout_mutex);
1712 
1713   absolute_delay = (60.0 * (((gdouble) fifoout->samplerate / (gdouble) fifoout->buffer_size) / (gdouble) fifoout->bpm) * ((1.0 / 16.0) * (1.0 / (gdouble) fifoout->delay_factor)));
1714 
1715   g_rec_mutex_unlock(fifoout_mutex);
1716 
1717   return(absolute_delay);
1718 }
1719 
1720 guint
ags_fifoout_get_attack(AgsSoundcard * soundcard)1721 ags_fifoout_get_attack(AgsSoundcard *soundcard)
1722 {
1723   AgsFifoout *fifoout;
1724 
1725   guint index;
1726   guint attack;
1727 
1728   GRecMutex *fifoout_mutex;
1729 
1730   fifoout = AGS_FIFOOUT(soundcard);
1731 
1732   /* get fifoout mutex */
1733   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1734 
1735   /* get attack */
1736   g_rec_mutex_lock(fifoout_mutex);
1737 
1738   index = fifoout->tic_counter;
1739 
1740   attack = fifoout->attack[index];
1741 
1742   g_rec_mutex_unlock(fifoout_mutex);
1743 
1744   return(attack);
1745 }
1746 
1747 void*
ags_fifoout_get_buffer(AgsSoundcard * soundcard)1748 ags_fifoout_get_buffer(AgsSoundcard *soundcard)
1749 {
1750   AgsFifoout *fifoout;
1751 
1752   void *buffer;
1753 
1754   fifoout = AGS_FIFOOUT(soundcard);
1755 
1756   if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER0)){
1757     buffer = fifoout->buffer[0];
1758   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER1)){
1759     buffer = fifoout->buffer[1];
1760   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER2)){
1761     buffer = fifoout->buffer[2];
1762   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER3)){
1763     buffer = fifoout->buffer[3];
1764   }else{
1765     buffer = NULL;
1766   }
1767 
1768   return(buffer);
1769 }
1770 
1771 void*
ags_fifoout_get_next_buffer(AgsSoundcard * soundcard)1772 ags_fifoout_get_next_buffer(AgsSoundcard *soundcard)
1773 {
1774   AgsFifoout *fifoout;
1775 
1776   void *buffer;
1777 
1778   fifoout = AGS_FIFOOUT(soundcard);
1779 
1780   //  g_message("next - 0x%0x", ((AGS_FIFOOUT_BUFFER0 |
1781   //				AGS_FIFOOUT_BUFFER1 |
1782   //				AGS_FIFOOUT_BUFFER2 |
1783   //				AGS_FIFOOUT_BUFFER3) & (fifoout->flags)));
1784 
1785   if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER0)){
1786     buffer = fifoout->buffer[1];
1787   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER1)){
1788     buffer = fifoout->buffer[2];
1789   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER2)){
1790     buffer = fifoout->buffer[3];
1791   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER3)){
1792     buffer = fifoout->buffer[0];
1793   }else{
1794     buffer = NULL;
1795   }
1796 
1797   return(buffer);
1798 }
1799 
1800 void*
ags_fifoout_get_prev_buffer(AgsSoundcard * soundcard)1801 ags_fifoout_get_prev_buffer(AgsSoundcard *soundcard)
1802 {
1803   AgsFifoout *fifoout;
1804 
1805   void *buffer;
1806 
1807   fifoout = AGS_FIFOOUT(soundcard);
1808 
1809   if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER0)){
1810     buffer = fifoout->buffer[3];
1811   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER1)){
1812     buffer = fifoout->buffer[0];
1813   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER2)){
1814     buffer = fifoout->buffer[1];
1815   }else if(ags_fifoout_test_flags(fifoout, AGS_FIFOOUT_BUFFER3)){
1816     buffer = fifoout->buffer[2];
1817   }else{
1818     buffer = NULL;
1819   }
1820 
1821   return(buffer);
1822 }
1823 
1824 guint
ags_fifoout_get_delay_counter(AgsSoundcard * soundcard)1825 ags_fifoout_get_delay_counter(AgsSoundcard *soundcard)
1826 {
1827   AgsFifoout *fifoout;
1828 
1829   guint delay_counter;
1830 
1831   GRecMutex *fifoout_mutex;
1832 
1833   fifoout = AGS_FIFOOUT(soundcard);
1834 
1835   /* get fifoout mutex */
1836   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1837 
1838   /* delay counter */
1839   g_rec_mutex_lock(fifoout_mutex);
1840 
1841   delay_counter = fifoout->delay_counter;
1842 
1843   g_rec_mutex_unlock(fifoout_mutex);
1844 
1845   return(delay_counter);
1846 }
1847 
1848 void
ags_fifoout_set_note_offset(AgsSoundcard * soundcard,guint note_offset)1849 ags_fifoout_set_note_offset(AgsSoundcard *soundcard,
1850 			    guint note_offset)
1851 {
1852   AgsFifoout *fifoout;
1853 
1854   GRecMutex *fifoout_mutex;
1855 
1856   fifoout = AGS_FIFOOUT(soundcard);
1857 
1858   /* get fifoout mutex */
1859   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1860 
1861   /* set note offset */
1862   g_rec_mutex_lock(fifoout_mutex);
1863 
1864   fifoout->note_offset = note_offset;
1865 
1866   g_rec_mutex_unlock(fifoout_mutex);
1867 }
1868 
1869 guint
ags_fifoout_get_note_offset(AgsSoundcard * soundcard)1870 ags_fifoout_get_note_offset(AgsSoundcard *soundcard)
1871 {
1872   AgsFifoout *fifoout;
1873 
1874   guint note_offset;
1875 
1876   GRecMutex *fifoout_mutex;
1877 
1878   fifoout = AGS_FIFOOUT(soundcard);
1879 
1880   /* get fifoout mutex */
1881   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1882 
1883   /* set note offset */
1884   g_rec_mutex_lock(fifoout_mutex);
1885 
1886   note_offset = fifoout->note_offset;
1887 
1888   g_rec_mutex_unlock(fifoout_mutex);
1889 
1890   return(note_offset);
1891 }
1892 
1893 void
ags_fifoout_set_note_offset_absolute(AgsSoundcard * soundcard,guint note_offset_absolute)1894 ags_fifoout_set_note_offset_absolute(AgsSoundcard *soundcard,
1895 				     guint note_offset_absolute)
1896 {
1897   AgsFifoout *fifoout;
1898 
1899   GRecMutex *fifoout_mutex;
1900 
1901   fifoout = AGS_FIFOOUT(soundcard);
1902 
1903   /* get fifoout mutex */
1904   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1905 
1906   /* set note offset */
1907   g_rec_mutex_lock(fifoout_mutex);
1908 
1909   fifoout->note_offset_absolute = note_offset_absolute;
1910 
1911   g_rec_mutex_unlock(fifoout_mutex);
1912 }
1913 
1914 guint
ags_fifoout_get_note_offset_absolute(AgsSoundcard * soundcard)1915 ags_fifoout_get_note_offset_absolute(AgsSoundcard *soundcard)
1916 {
1917   AgsFifoout *fifoout;
1918 
1919   guint note_offset_absolute;
1920 
1921   GRecMutex *fifoout_mutex;
1922 
1923   fifoout = AGS_FIFOOUT(soundcard);
1924 
1925   /* get fifoout mutex */
1926   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1927 
1928   /* set note offset */
1929   g_rec_mutex_lock(fifoout_mutex);
1930 
1931   note_offset_absolute = fifoout->note_offset_absolute;
1932 
1933   g_rec_mutex_unlock(fifoout_mutex);
1934 
1935   return(note_offset_absolute);
1936 }
1937 
1938 void
ags_fifoout_set_loop(AgsSoundcard * soundcard,guint loop_left,guint loop_right,gboolean do_loop)1939 ags_fifoout_set_loop(AgsSoundcard *soundcard,
1940 		     guint loop_left, guint loop_right,
1941 		     gboolean do_loop)
1942 {
1943   AgsFifoout *fifoout;
1944 
1945   GRecMutex *fifoout_mutex;
1946 
1947   fifoout = AGS_FIFOOUT(soundcard);
1948 
1949   /* get fifoout mutex */
1950   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1951 
1952   /* set loop */
1953   g_rec_mutex_lock(fifoout_mutex);
1954 
1955   fifoout->loop_left = loop_left;
1956   fifoout->loop_right = loop_right;
1957   fifoout->do_loop = do_loop;
1958 
1959   if(do_loop){
1960     fifoout->loop_offset = fifoout->note_offset;
1961   }
1962 
1963   g_rec_mutex_unlock(fifoout_mutex);
1964 }
1965 
1966 void
ags_fifoout_get_loop(AgsSoundcard * soundcard,guint * loop_left,guint * loop_right,gboolean * do_loop)1967 ags_fifoout_get_loop(AgsSoundcard *soundcard,
1968 		     guint *loop_left, guint *loop_right,
1969 		     gboolean *do_loop)
1970 {
1971   AgsFifoout *fifoout;
1972 
1973   GRecMutex *fifoout_mutex;
1974 
1975   fifoout = AGS_FIFOOUT(soundcard);
1976 
1977   /* get fifoout mutex */
1978   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
1979 
1980   /* get loop */
1981   g_rec_mutex_lock(fifoout_mutex);
1982 
1983   if(loop_left != NULL){
1984     *loop_left = fifoout->loop_left;
1985   }
1986 
1987   if(loop_right != NULL){
1988     *loop_right = fifoout->loop_right;
1989   }
1990 
1991   if(do_loop != NULL){
1992     *do_loop = fifoout->do_loop;
1993   }
1994 
1995   g_rec_mutex_unlock(fifoout_mutex);
1996 }
1997 
1998 guint
ags_fifoout_get_loop_offset(AgsSoundcard * soundcard)1999 ags_fifoout_get_loop_offset(AgsSoundcard *soundcard)
2000 {
2001   AgsFifoout *fifoout;
2002 
2003   guint loop_offset;
2004 
2005   GRecMutex *fifoout_mutex;
2006 
2007   fifoout = AGS_FIFOOUT(soundcard);
2008 
2009   /* get fifoout mutex */
2010   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
2011 
2012   /* get loop offset */
2013   g_rec_mutex_lock(fifoout_mutex);
2014 
2015   loop_offset = fifoout->loop_offset;
2016 
2017   g_rec_mutex_unlock(fifoout_mutex);
2018 
2019   return(loop_offset);
2020 }
2021 
2022 /**
2023  * ags_fifoout_switch_buffer_flag:
2024  * @fifoout: the #AgsFifoout
2025  *
2026  * The buffer flag indicates the currently played buffer.
2027  *
2028  * Since: 3.0.0
2029  */
2030 void
ags_fifoout_switch_buffer_flag(AgsFifoout * fifoout)2031 ags_fifoout_switch_buffer_flag(AgsFifoout *fifoout)
2032 {
2033   GRecMutex *fifoout_mutex;
2034 
2035   if(!AGS_IS_FIFOOUT(fifoout)){
2036     return;
2037   }
2038 
2039   /* get fifoout mutex */
2040   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
2041 
2042   /* switch buffer flag */
2043   g_rec_mutex_lock(fifoout_mutex);
2044 
2045   if((AGS_FIFOOUT_BUFFER0 & (fifoout->flags)) != 0){
2046     fifoout->flags &= (~AGS_FIFOOUT_BUFFER0);
2047     fifoout->flags |= AGS_FIFOOUT_BUFFER1;
2048   }else if((AGS_FIFOOUT_BUFFER1 & (fifoout->flags)) != 0){
2049     fifoout->flags &= (~AGS_FIFOOUT_BUFFER1);
2050     fifoout->flags |= AGS_FIFOOUT_BUFFER2;
2051   }else if((AGS_FIFOOUT_BUFFER2 & (fifoout->flags)) != 0){
2052     fifoout->flags &= (~AGS_FIFOOUT_BUFFER2);
2053     fifoout->flags |= AGS_FIFOOUT_BUFFER3;
2054   }else if((AGS_FIFOOUT_BUFFER3 & (fifoout->flags)) != 0){
2055     fifoout->flags &= (~AGS_FIFOOUT_BUFFER3);
2056     fifoout->flags |= AGS_FIFOOUT_BUFFER0;
2057   }
2058 
2059   g_rec_mutex_unlock(fifoout_mutex);
2060 }
2061 
2062 /**
2063  * ags_fifoout_adjust_delay_and_attack:
2064  * @fifoout: the #AgsFifoout
2065  *
2066  * Calculate delay and attack and reset it.
2067  *
2068  * Since: 3.0.0
2069  */
2070 void
ags_fifoout_adjust_delay_and_attack(AgsFifoout * fifoout)2071 ags_fifoout_adjust_delay_and_attack(AgsFifoout *fifoout)
2072 {
2073   gdouble delay;
2074   guint default_tact_frames;
2075   guint default_period;
2076   guint i;
2077 
2078   GRecMutex *fifoout_mutex;
2079 
2080   if(!AGS_IS_FIFOOUT(fifoout)){
2081     return;
2082   }
2083 
2084   /* get fifoout mutex */
2085   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
2086 
2087   /* get some initial values */
2088   delay = (60.0 * (((gdouble) fifoout->samplerate / (gdouble) fifoout->buffer_size) / (gdouble) fifoout->bpm) * ((1.0 / 16.0) * (1.0 / (gdouble) fifoout->delay_factor)));
2089 
2090 #ifdef AGS_DEBUG
2091   g_message("delay : %f", delay);
2092 #endif
2093 
2094   g_rec_mutex_lock(fifoout_mutex);
2095 
2096   default_tact_frames = (guint) (delay * fifoout->buffer_size);
2097   default_period = (1.0 / AGS_SOUNDCARD_DEFAULT_PERIOD) * (default_tact_frames);
2098 
2099   fifoout->attack[0] = 0;
2100   fifoout->delay[0] = delay;
2101 
2102   for(i = 1; i < (int)  2.0 * AGS_SOUNDCARD_DEFAULT_PERIOD; i++){
2103     fifoout->attack[i] = (guint) ((i * default_tact_frames + fifoout->attack[i - 1]) / (AGS_SOUNDCARD_DEFAULT_PERIOD / (delay * i))) % (guint) (fifoout->buffer_size);
2104 
2105 #ifdef AGS_DEBUG
2106     g_message("%d", fifoout->attack[i]);
2107 #endif
2108   }
2109 
2110   for(i = 1; i < (int) 2.0 * AGS_SOUNDCARD_DEFAULT_PERIOD; i++){
2111     fifoout->delay[i] = ((gdouble) (default_tact_frames + fifoout->attack[i])) / (gdouble) fifoout->buffer_size;
2112 
2113 #ifdef AGS_DEBUG
2114     g_message("%f", fifoout->delay[i]);
2115 #endif
2116   }
2117 
2118   g_rec_mutex_unlock(fifoout_mutex);
2119 }
2120 
2121 /**
2122  * ags_fifoout_realloc_buffer:
2123  * @fifoout: the #AgsFifoout
2124  *
2125  * Reallocate the internal audio buffer.
2126  *
2127  * Since: 3.0.0
2128  */
2129 void
ags_fifoout_realloc_buffer(AgsFifoout * fifoout)2130 ags_fifoout_realloc_buffer(AgsFifoout *fifoout)
2131 {
2132   guint pcm_channels;
2133   guint buffer_size;
2134   guint word_size;
2135 
2136   GRecMutex *fifoout_mutex;
2137 
2138   if(!AGS_IS_FIFOOUT(fifoout)){
2139     return;
2140   }
2141 
2142   /* get fifoout mutex */
2143   fifoout_mutex = AGS_FIFOOUT_GET_OBJ_MUTEX(fifoout);
2144 
2145   /* get word size */
2146   g_rec_mutex_lock(fifoout_mutex);
2147 
2148   pcm_channels = fifoout->pcm_channels;
2149   buffer_size = fifoout->buffer_size;
2150 
2151   switch(fifoout->format){
2152   case AGS_SOUNDCARD_SIGNED_8_BIT:
2153     {
2154       word_size = sizeof(gint8);
2155     }
2156     break;
2157   case AGS_SOUNDCARD_SIGNED_16_BIT:
2158     {
2159       word_size = sizeof(gint16);
2160     }
2161     break;
2162   case AGS_SOUNDCARD_SIGNED_24_BIT:
2163     {
2164       word_size = sizeof(gint32);
2165     }
2166     break;
2167   case AGS_SOUNDCARD_SIGNED_32_BIT:
2168     {
2169       word_size = sizeof(gint32);
2170     }
2171     break;
2172   case AGS_SOUNDCARD_SIGNED_64_BIT:
2173     {
2174       word_size = sizeof(gint64);
2175     }
2176     break;
2177   default:
2178     g_warning("ags_fifoout_realloc_buffer(): unsupported word size");
2179     return;
2180   }
2181 
2182   g_rec_mutex_unlock(fifoout_mutex);
2183 
2184   //NOTE:JK: there is no lock applicable to buffer
2185 
2186   /* AGS_FIFOOUT_BUFFER_0 */
2187   if(fifoout->buffer[0] != NULL){
2188     free(fifoout->buffer[0]);
2189   }
2190 
2191   fifoout->buffer[0] = (void *) malloc(pcm_channels * buffer_size * word_size);
2192 
2193   /* AGS_FIFOOUT_BUFFER_1 */
2194   if(fifoout->buffer[1] != NULL){
2195     free(fifoout->buffer[1]);
2196   }
2197 
2198   fifoout->buffer[1] = (void *) malloc(pcm_channels * buffer_size * word_size);
2199 
2200   /* AGS_FIFOOUT_BUFFER_2 */
2201   if(fifoout->buffer[2] != NULL){
2202     free(fifoout->buffer[2]);
2203   }
2204 
2205   fifoout->buffer[2] = (void *) malloc(pcm_channels * buffer_size * word_size);
2206 
2207   /* AGS_FIFOOUT_BUFFER_3 */
2208   if(fifoout->buffer[3] != NULL){
2209     free(fifoout->buffer[3]);
2210   }
2211 
2212   fifoout->buffer[3] = (void *) malloc(pcm_channels * buffer_size * word_size);
2213 }
2214 
2215 /**
2216  * ags_fifoout_new:
2217  *
2218  * Creates a new instance of #AgsFifoout.
2219  *
2220  * Returns: the new #AgsFifoout
2221  *
2222  * Since: 3.0.0
2223  */
2224 AgsFifoout*
ags_fifoout_new()2225 ags_fifoout_new()
2226 {
2227   AgsFifoout *fifoout;
2228 
2229   fifoout = (AgsFifoout *) g_object_new(AGS_TYPE_FIFOOUT,
2230 					NULL);
2231 
2232   return(fifoout);
2233 }
2234