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/wasapi/ags_wasapi_devout.h>
21 
22 #include <ags/audio/ags_sound_provider.h>
23 #include <ags/audio/ags_soundcard_util.h>
24 #include <ags/audio/ags_audio_buffer_util.h>
25 
26 #include <ags/audio/task/ags_tic_device.h>
27 #include <ags/audio/task/ags_clear_buffer.h>
28 #include <ags/audio/task/ags_switch_buffer_flag.h>
29 
30 #include <ags/audio/thread/ags_audio_loop.h>
31 #include <ags/audio/thread/ags_soundcard_thread.h>
32 
33 #include <string.h>
34 #include <math.h>
35 #include <time.h>
36 
37 #ifdef AGS_WITH_WASAPI
38 #include <windows.h>
39 #include <ole2.h>
40 #include <ksmedia.h>
41 #include <wchar.h>
42 #endif
43 
44 #include <ags/config.h>
45 #include <ags/i18n.h>
46 
47 void ags_wasapi_devout_class_init(AgsWasapiDevoutClass *wasapi_devout);
48 void ags_wasapi_devout_connectable_interface_init(AgsConnectableInterface *connectable);
49 void ags_wasapi_devout_soundcard_interface_init(AgsSoundcardInterface *soundcard);
50 void ags_wasapi_devout_init(AgsWasapiDevout *wasapi_devout);
51 void ags_wasapi_devout_set_property(GObject *gobject,
52 				    guint prop_id,
53 				    const GValue *value,
54 				    GParamSpec *param_spec);
55 void ags_wasapi_devout_get_property(GObject *gobject,
56 				    guint prop_id,
57 				    GValue *value,
58 				    GParamSpec *param_spec);
59 void ags_wasapi_devout_dispose(GObject *gobject);
60 void ags_wasapi_devout_finalize(GObject *gobject);
61 
62 AgsUUID* ags_wasapi_devout_get_uuid(AgsConnectable *connectable);
63 gboolean ags_wasapi_devout_has_resource(AgsConnectable *connectable);
64 gboolean ags_wasapi_devout_is_ready(AgsConnectable *connectable);
65 void ags_wasapi_devout_add_to_registry(AgsConnectable *connectable);
66 void ags_wasapi_devout_remove_from_registry(AgsConnectable *connectable);
67 xmlNode* ags_wasapi_devout_list_resource(AgsConnectable *connectable);
68 xmlNode* ags_wasapi_devout_xml_compose(AgsConnectable *connectable);
69 void ags_wasapi_devout_xml_parse(AgsConnectable *connectable,
70 				 xmlNode *node);
71 gboolean ags_wasapi_devout_is_connected(AgsConnectable *connectable);
72 void ags_wasapi_devout_connect(AgsConnectable *connectable);
73 void ags_wasapi_devout_disconnect(AgsConnectable *connectable);
74 
75 void ags_wasapi_devout_set_device(AgsSoundcard *soundcard,
76 				  gchar *device);
77 gchar* ags_wasapi_devout_get_device(AgsSoundcard *soundcard);
78 
79 void ags_wasapi_devout_set_presets(AgsSoundcard *soundcard,
80 				   guint channels,
81 				   guint rate,
82 				   guint buffer_size,
83 				   guint format);
84 void ags_wasapi_devout_get_presets(AgsSoundcard *soundcard,
85 				   guint *channels,
86 				   guint *rate,
87 				   guint *buffer_size,
88 				   guint *format);
89 
90 void ags_wasapi_devout_list_cards(AgsSoundcard *soundcard,
91 				  GList **card_id, GList **card_name);
92 void ags_wasapi_devout_pcm_info(AgsSoundcard *soundcard, gchar *card_id,
93 				guint *channels_min, guint *channels_max,
94 				guint *rate_min, guint *rate_max,
95 				guint *buffer_size_min, guint *buffer_size_max,
96 				GError **error);
97 guint ags_wasapi_devout_get_capability(AgsSoundcard *soundcard);
98 
99 gboolean ags_wasapi_devout_is_starting(AgsSoundcard *soundcard);
100 gboolean ags_wasapi_devout_is_playing(AgsSoundcard *soundcard);
101 
102 gchar* ags_wasapi_devout_get_uptime(AgsSoundcard *soundcard);
103 
104 void ags_wasapi_devout_client_init(AgsSoundcard *soundcard,
105 				   GError **error);
106 void ags_wasapi_devout_client_play(AgsSoundcard *soundcard,
107 				   GError **error);
108 void ags_wasapi_devout_client_free(AgsSoundcard *soundcard);
109 
110 void ags_wasapi_devout_tic(AgsSoundcard *soundcard);
111 void ags_wasapi_devout_offset_changed(AgsSoundcard *soundcard,
112 				      guint note_offset);
113 
114 void ags_wasapi_devout_set_bpm(AgsSoundcard *soundcard,
115 			       gdouble bpm);
116 gdouble ags_wasapi_devout_get_bpm(AgsSoundcard *soundcard);
117 
118 void ags_wasapi_devout_set_delay_factor(AgsSoundcard *soundcard,
119 					gdouble delay_factor);
120 gdouble ags_wasapi_devout_get_delay_factor(AgsSoundcard *soundcard);
121 
122 gdouble ags_wasapi_devout_get_absolute_delay(AgsSoundcard *soundcard);
123 
124 gdouble ags_wasapi_devout_get_delay(AgsSoundcard *soundcard);
125 guint ags_wasapi_devout_get_attack(AgsSoundcard *soundcard);
126 
127 void* ags_wasapi_devout_get_buffer(AgsSoundcard *soundcard);
128 void* ags_wasapi_devout_get_next_buffer(AgsSoundcard *soundcard);
129 void* ags_wasapi_devout_get_prev_buffer(AgsSoundcard *soundcard);
130 
131 void ags_wasapi_devout_lock_buffer(AgsSoundcard *soundcard,
132 				   void *buffer);
133 void ags_wasapi_devout_unlock_buffer(AgsSoundcard *soundcard,
134 				     void *buffer);
135 
136 guint ags_wasapi_devout_get_delay_counter(AgsSoundcard *soundcard);
137 
138 void ags_wasapi_devout_set_start_note_offset(AgsSoundcard *soundcard,
139 					     guint start_note_offset);
140 guint ags_wasapi_devout_get_start_note_offset(AgsSoundcard *soundcard);
141 
142 void ags_wasapi_devout_set_note_offset(AgsSoundcard *soundcard,
143 				       guint note_offset);
144 guint ags_wasapi_devout_get_note_offset(AgsSoundcard *soundcard);
145 
146 void ags_wasapi_devout_set_note_offset_absolute(AgsSoundcard *soundcard,
147 						guint note_offset);
148 guint ags_wasapi_devout_get_note_offset_absolute(AgsSoundcard *soundcard);
149 
150 void ags_wasapi_devout_set_loop(AgsSoundcard *soundcard,
151 				guint loop_left, guint loop_right,
152 				gboolean do_loop);
153 void ags_wasapi_devout_get_loop(AgsSoundcard *soundcard,
154 				guint *loop_left, guint *loop_right,
155 				gboolean *do_loop);
156 
157 guint ags_wasapi_devout_get_loop_offset(AgsSoundcard *soundcard);
158 
159 guint ags_wasapi_devout_get_sub_block_count(AgsSoundcard *soundcard);
160 
161 gboolean ags_wasapi_devout_trylock_sub_block(AgsSoundcard *soundcard,
162 					     void *buffer, guint sub_block);
163 void ags_wasapi_devout_unlock_sub_block(AgsSoundcard *soundcard,
164 					void *buffer, guint sub_block);
165 
166 /**
167  * SECTION:ags_wasapi_devout
168  * @short_description: Output to soundcard
169  * @title: AgsWasapiDevout
170  * @section_id:
171  * @include: ags/audio/wasapi/ags_wasapi_devout.h
172  *
173  * #AgsWasapiDevout represents a soundcard and supports output.
174  */
175 
176 enum{
177   PROP_0,
178   PROP_DEVICE,
179   PROP_DSP_CHANNELS,
180   PROP_PCM_CHANNELS,
181   PROP_FORMAT,
182   PROP_BUFFER_SIZE,
183   PROP_SAMPLERATE,
184   PROP_BUFFER,
185   PROP_BPM,
186   PROP_DELAY_FACTOR,
187   PROP_ATTACK,
188   PROP_CHANNEL,
189 };
190 
191 static gpointer ags_wasapi_devout_parent_class = NULL;
192 
193 #ifdef AGS_W32API
194 static const GUID ags_wasapi_clsid_mm_device_enumerator_guid = {0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E};
195 static const GUID ags_wasapi_iid_mm_device_enumerator_guid = {0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6};
196 static const GUID ags_wasapi_iid_audio_client_guid = {0x1CB9AD4C, 0xDBFA, 0x4c32, 0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2};
197 static const GUID ags_wasapi_iid_audio_render_client_guid = {0xF294ACFC, 0x3146, 0x4483, 0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2};
198 static const GUID ags_wasapi_pcm_subformat_guid = {0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71};
199 static const GUID ags_wasapi_pkey_device_friendly_name_guid = {0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0};
200 
201 struct _PROPERTYKEY{
202   GUID fmtid;
203   DWORD id;
204 };
205 
206 static struct _PROPERTYKEY ags_wasapi_pkey_device_friendly_name_key = {ags_wasapi_pkey_device_friendly_name_guid,
207 								       14};
208 #endif
209 
210 GType
ags_wasapi_devout_get_type(void)211 ags_wasapi_devout_get_type (void)
212 {
213   static volatile gsize g_define_type_id__volatile = 0;
214 
215   if(g_once_init_enter (&g_define_type_id__volatile)){
216     GType ags_type_wasapi_devout = 0;
217 
218     static const GTypeInfo ags_wasapi_devout_info = {
219       sizeof(AgsWasapiDevoutClass),
220       NULL, /* base_init */
221       NULL, /* base_finalize */
222       (GClassInitFunc) ags_wasapi_devout_class_init,
223       NULL, /* class_finalize */
224       NULL, /* class_data */
225       sizeof(AgsWasapiDevout),
226       0,    /* n_preallocs */
227       (GInstanceInitFunc) ags_wasapi_devout_init,
228     };
229 
230     static const GInterfaceInfo ags_connectable_interface_info = {
231       (GInterfaceInitFunc) ags_wasapi_devout_connectable_interface_init,
232       NULL, /* interface_finalize */
233       NULL, /* interface_data */
234     };
235 
236     static const GInterfaceInfo ags_soundcard_interface_info = {
237       (GInterfaceInitFunc) ags_wasapi_devout_soundcard_interface_init,
238       NULL, /* interface_finalize */
239       NULL, /* interface_data */
240     };
241 
242     ags_type_wasapi_devout = g_type_register_static(G_TYPE_OBJECT,
243 						    "AgsWasapiDevout",
244 						    &ags_wasapi_devout_info,
245 						    0);
246 
247     g_type_add_interface_static(ags_type_wasapi_devout,
248 				AGS_TYPE_CONNECTABLE,
249 				&ags_connectable_interface_info);
250 
251     g_type_add_interface_static(ags_type_wasapi_devout,
252 				AGS_TYPE_SOUNDCARD,
253 				&ags_soundcard_interface_info);
254 
255     g_once_init_leave(&g_define_type_id__volatile, ags_type_wasapi_devout);
256   }
257 
258   return g_define_type_id__volatile;
259 }
260 
261 void
ags_wasapi_devout_class_init(AgsWasapiDevoutClass * wasapi_devout)262 ags_wasapi_devout_class_init(AgsWasapiDevoutClass *wasapi_devout)
263 {
264   GObjectClass *gobject;
265   GParamSpec *param_spec;
266 
267   ags_wasapi_devout_parent_class = g_type_class_peek_parent(wasapi_devout);
268 
269   /* GObjectClass */
270   gobject = (GObjectClass *) wasapi_devout;
271 
272   gobject->set_property = ags_wasapi_devout_set_property;
273   gobject->get_property = ags_wasapi_devout_get_property;
274 
275   gobject->dispose = ags_wasapi_devout_dispose;
276   gobject->finalize = ags_wasapi_devout_finalize;
277 
278   /* properties */
279   /**
280    * AgsWasapiDevout:device:
281    *
282    * The core audio 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-wasapi-devout-0",
290 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
291   g_object_class_install_property(gobject,
292 				  PROP_DEVICE,
293 				  param_spec);
294 
295   /**
296    * AgsWasapiDevout: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 				 1,
306 				 64,
307 				 2,
308 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
309   g_object_class_install_property(gobject,
310 				  PROP_DSP_CHANNELS,
311 				  param_spec);
312 
313   /**
314    * AgsWasapiDevout: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 				 1,
324 				 64,
325 				 2,
326 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
327   g_object_class_install_property(gobject,
328 				  PROP_PCM_CHANNELS,
329 				  param_spec);
330 
331   /**
332    * AgsWasapiDevout: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 				 1,
342 				 64,
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    * AgsWasapiDevout: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 				 1,
360 				 44100,
361 				 940,
362 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
363   g_object_class_install_property(gobject,
364 				  PROP_BUFFER_SIZE,
365 				  param_spec);
366 
367   /**
368    * AgsWasapiDevout: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 				 8000,
378 				 96000,
379 				 44100,
380 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
381   g_object_class_install_property(gobject,
382 				  PROP_SAMPLERATE,
383 				  param_spec);
384 
385   /**
386    * AgsWasapiDevout: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    * AgsWasapiDevout: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 				   120.0,
413 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
414   g_object_class_install_property(gobject,
415 				  PROP_BPM,
416 				  param_spec);
417 
418   /**
419    * AgsWasapiDevout: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    * AgsWasapiDevout: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 
452 GQuark
ags_wasapi_devout_error_quark()453 ags_wasapi_devout_error_quark()
454 {
455   return(g_quark_from_static_string("ags-wasapi_devout-error-quark"));
456 }
457 
458 void
ags_wasapi_devout_connectable_interface_init(AgsConnectableInterface * connectable)459 ags_wasapi_devout_connectable_interface_init(AgsConnectableInterface *connectable)
460 {
461   connectable->get_uuid = ags_wasapi_devout_get_uuid;
462   connectable->has_resource = ags_wasapi_devout_has_resource;
463 
464   connectable->is_ready = ags_wasapi_devout_is_ready;
465   connectable->add_to_registry = ags_wasapi_devout_add_to_registry;
466   connectable->remove_from_registry = ags_wasapi_devout_remove_from_registry;
467 
468   connectable->list_resource = ags_wasapi_devout_list_resource;
469   connectable->xml_compose = ags_wasapi_devout_xml_compose;
470   connectable->xml_parse = ags_wasapi_devout_xml_parse;
471 
472   connectable->is_connected = ags_wasapi_devout_is_connected;
473   connectable->connect = ags_wasapi_devout_connect;
474   connectable->disconnect = ags_wasapi_devout_disconnect;
475 
476   connectable->connect_connection = NULL;
477   connectable->disconnect_connection = NULL;
478 }
479 
480 void
ags_wasapi_devout_soundcard_interface_init(AgsSoundcardInterface * soundcard)481 ags_wasapi_devout_soundcard_interface_init(AgsSoundcardInterface *soundcard)
482 {
483   soundcard->set_device = ags_wasapi_devout_set_device;
484   soundcard->get_device = ags_wasapi_devout_get_device;
485 
486   soundcard->set_presets = ags_wasapi_devout_set_presets;
487   soundcard->get_presets = ags_wasapi_devout_get_presets;
488 
489   soundcard->list_cards = ags_wasapi_devout_list_cards;
490   soundcard->pcm_info = ags_wasapi_devout_pcm_info;
491   soundcard->get_capability = ags_wasapi_devout_get_capability;
492 
493   soundcard->is_available = NULL;
494 
495   soundcard->is_starting =  ags_wasapi_devout_is_starting;
496   soundcard->is_playing = ags_wasapi_devout_is_playing;
497   soundcard->is_recording = NULL;
498 
499   soundcard->get_uptime = ags_wasapi_devout_get_uptime;
500 
501   soundcard->play_init = ags_wasapi_devout_client_init;
502   soundcard->play = ags_wasapi_devout_client_play;
503 
504   soundcard->record_init = NULL;
505   soundcard->record = NULL;
506 
507   soundcard->stop = ags_wasapi_devout_client_free;
508 
509   soundcard->tic = ags_wasapi_devout_tic;
510   soundcard->offset_changed = ags_wasapi_devout_offset_changed;
511 
512   soundcard->set_bpm = ags_wasapi_devout_set_bpm;
513   soundcard->get_bpm = ags_wasapi_devout_get_bpm;
514 
515   soundcard->set_delay_factor = ags_wasapi_devout_set_delay_factor;
516   soundcard->get_delay_factor = ags_wasapi_devout_get_delay_factor;
517 
518   soundcard->get_absolute_delay = ags_wasapi_devout_get_absolute_delay;
519 
520   soundcard->get_delay = ags_wasapi_devout_get_delay;
521   soundcard->get_attack = ags_wasapi_devout_get_attack;
522 
523   soundcard->get_buffer = ags_wasapi_devout_get_buffer;
524   soundcard->get_next_buffer = ags_wasapi_devout_get_next_buffer;
525   soundcard->get_prev_buffer = ags_wasapi_devout_get_prev_buffer;
526 
527   soundcard->lock_buffer = ags_wasapi_devout_lock_buffer;
528   soundcard->unlock_buffer = ags_wasapi_devout_unlock_buffer;
529 
530   soundcard->get_delay_counter = ags_wasapi_devout_get_delay_counter;
531 
532   soundcard->set_start_note_offset = ags_wasapi_devout_set_start_note_offset;
533   soundcard->get_start_note_offset = ags_wasapi_devout_get_start_note_offset;
534 
535   soundcard->set_note_offset = ags_wasapi_devout_set_note_offset;
536   soundcard->get_note_offset = ags_wasapi_devout_get_note_offset;
537 
538   soundcard->set_note_offset_absolute = ags_wasapi_devout_set_note_offset_absolute;
539   soundcard->get_note_offset_absolute = ags_wasapi_devout_get_note_offset_absolute;
540 
541   soundcard->set_loop = ags_wasapi_devout_set_loop;
542   soundcard->get_loop = ags_wasapi_devout_get_loop;
543 
544   soundcard->get_loop_offset = ags_wasapi_devout_get_loop_offset;
545 
546   soundcard->get_sub_block_count = ags_wasapi_devout_get_sub_block_count;
547 
548   soundcard->trylock_sub_block = ags_wasapi_devout_trylock_sub_block;
549   soundcard->unlock_sub_block = ags_wasapi_devout_unlock_sub_block;
550 }
551 
552 void
ags_wasapi_devout_init(AgsWasapiDevout * wasapi_devout)553 ags_wasapi_devout_init(AgsWasapiDevout *wasapi_devout)
554 {
555   AgsConfig *config;
556 
557   gchar *str;
558   gchar *segmentation;
559 
560   guint denumerator, numerator;
561   guint i;
562 
563   /* flags */
564   wasapi_devout->flags = 0;
565 
566   /* devout mutex */
567   g_rec_mutex_init(&(wasapi_devout->obj_mutex));
568 
569   /* uuid */
570   wasapi_devout->uuid = ags_uuid_alloc();
571   ags_uuid_generate(wasapi_devout->uuid);
572 
573   /* presets */
574   config = ags_config_get_instance();
575 
576   wasapi_devout->dsp_channels = ags_soundcard_helper_config_get_dsp_channels(config);
577   wasapi_devout->pcm_channels = ags_soundcard_helper_config_get_pcm_channels(config);
578 
579   wasapi_devout->samplerate = ags_soundcard_helper_config_get_samplerate(config);
580   wasapi_devout->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
581   wasapi_devout->format = ags_soundcard_helper_config_get_format(config);
582 
583   str = ags_config_get_value(config,
584 			     AGS_CONFIG_SOUNDCARD,
585 			     "wasapi-buffer-size");
586 
587   if(str == NULL){
588     str = ags_config_get_value(config,
589 			       AGS_CONFIG_SOUNDCARD_0,
590 			       "wasapi-buffer-size");
591   }
592 
593   if(str != NULL){
594     wasapi_devout->wasapi_buffer_size = g_ascii_strtoull(str,
595 							 NULL,
596 							 10);
597   }else{
598     wasapi_devout->wasapi_buffer_size = AGS_WASAPI_DEVOUT_DEFAULT_WASAPI_BUFFER_SIZE;
599   }
600 
601   g_free(str);
602 
603   str = ags_config_get_value(config,
604 			     AGS_CONFIG_SOUNDCARD,
605 			     "wasapi-share-mode");
606 
607   if(str == NULL){
608     str = ags_config_get_value(config,
609 			       AGS_CONFIG_SOUNDCARD_0,
610 			       "wasapi-share-mode");
611   }
612 
613   if(str != NULL &&
614      !g_ascii_strncasecmp(str,
615 			  "exclusive",
616 			  10)){
617     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_SHARE_MODE_EXCLUSIVE;
618   }
619 
620   g_free(str);
621 
622   /* device */
623   wasapi_devout->device = NULL;
624 
625   /* buffer */
626   wasapi_devout->buffer_mutex = (GRecMutex **) malloc(8 * sizeof(GRecMutex *));
627 
628   for(i = 0; i < 8; i++){
629     wasapi_devout->buffer_mutex[i] = (GRecMutex *) malloc(sizeof(GRecMutex));
630 
631     g_rec_mutex_init(wasapi_devout->buffer_mutex[i]);
632   }
633 
634   wasapi_devout->sub_block_count = AGS_SOUNDCARD_DEFAULT_SUB_BLOCK_COUNT;
635   wasapi_devout->sub_block_mutex = (GRecMutex **) malloc(8 * wasapi_devout->sub_block_count * wasapi_devout->pcm_channels * sizeof(GRecMutex *));
636 
637   for(i = 0; i < 8 * wasapi_devout->sub_block_count * wasapi_devout->pcm_channels; i++){
638     wasapi_devout->sub_block_mutex[i] = (GRecMutex *) malloc(sizeof(GRecMutex));
639 
640     g_rec_mutex_init(wasapi_devout->sub_block_mutex[i]);
641   }
642 
643   wasapi_devout->buffer = (void **) malloc(8 * sizeof(void*));
644 
645   wasapi_devout->buffer[0] = NULL;
646   wasapi_devout->buffer[1] = NULL;
647   wasapi_devout->buffer[2] = NULL;
648   wasapi_devout->buffer[3] = NULL;
649   wasapi_devout->buffer[4] = NULL;
650   wasapi_devout->buffer[5] = NULL;
651   wasapi_devout->buffer[6] = NULL;
652   wasapi_devout->buffer[7] = NULL;
653 
654   ags_wasapi_devout_realloc_buffer(wasapi_devout);
655 
656   /* bpm */
657   wasapi_devout->bpm = AGS_SOUNDCARD_DEFAULT_BPM;
658 
659   /* delay factor */
660   wasapi_devout->delay_factor = AGS_SOUNDCARD_DEFAULT_DELAY_FACTOR;
661 
662   /* segmentation */
663   segmentation = ags_config_get_value(config,
664 				      AGS_CONFIG_GENERIC,
665 				      "segmentation");
666 
667   if(segmentation != NULL){
668     sscanf(segmentation, "%d/%d",
669 	   &denumerator,
670 	   &numerator);
671 
672     wasapi_devout->delay_factor = 1.0 / numerator * (numerator / denumerator);
673 
674     g_free(segmentation);
675   }
676 
677   /* delay and attack */
678   wasapi_devout->delay = (gdouble *) malloc((int) 2 * AGS_SOUNDCARD_DEFAULT_PERIOD *
679 					    sizeof(gdouble));
680 
681   wasapi_devout->attack = (guint *) malloc((int) 2 * AGS_SOUNDCARD_DEFAULT_PERIOD *
682 					   sizeof(guint));
683 
684   ags_wasapi_devout_adjust_delay_and_attack(wasapi_devout);
685 
686   /* counters */
687   wasapi_devout->tact_counter = 0.0;
688   wasapi_devout->delay_counter = 0.0;
689   wasapi_devout->tic_counter = 0;
690 
691   wasapi_devout->start_note_offset = 0;
692   wasapi_devout->note_offset = 0;
693   wasapi_devout->note_offset_absolute = 0;
694 
695   wasapi_devout->loop_left = AGS_SOUNDCARD_DEFAULT_LOOP_LEFT;
696   wasapi_devout->loop_right = AGS_SOUNDCARD_DEFAULT_LOOP_RIGHT;
697 
698   wasapi_devout->do_loop = FALSE;
699 
700   wasapi_devout->loop_offset = 0;
701 
702   /* callback mutex */
703   g_mutex_init(&(wasapi_devout->callback_mutex));
704 
705   g_cond_init(&(wasapi_devout->callback_cond));
706 
707   /* callback finish mutex */
708   g_mutex_init(&(wasapi_devout->callback_finish_mutex));
709 
710   g_cond_init(&(wasapi_devout->callback_finish_cond));
711 }
712 
713 void
ags_wasapi_devout_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)714 ags_wasapi_devout_set_property(GObject *gobject,
715 			       guint prop_id,
716 			       const GValue *value,
717 			       GParamSpec *param_spec)
718 {
719   AgsWasapiDevout *wasapi_devout;
720 
721   GRecMutex *wasapi_devout_mutex;
722 
723   wasapi_devout = AGS_WASAPI_DEVOUT(gobject);
724 
725   /* get wasapi devout mutex */
726   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
727 
728   switch(prop_id){
729   case PROP_DEVICE:
730   {
731     char *device;
732 
733     device = (char *) g_value_get_string(value);
734 
735     g_rec_mutex_lock(wasapi_devout_mutex);
736 
737     wasapi_devout->device = g_strdup(device);
738 
739     g_rec_mutex_unlock(wasapi_devout_mutex);
740   }
741   break;
742   case PROP_DSP_CHANNELS:
743   {
744     guint dsp_channels;
745 
746     dsp_channels = g_value_get_uint(value);
747 
748     g_rec_mutex_lock(wasapi_devout_mutex);
749 
750     if(dsp_channels == wasapi_devout->dsp_channels){
751       g_rec_mutex_unlock(wasapi_devout_mutex);
752 
753       return;
754     }
755 
756     wasapi_devout->dsp_channels = dsp_channels;
757 
758     g_rec_mutex_unlock(wasapi_devout_mutex);
759   }
760   break;
761   case PROP_PCM_CHANNELS:
762   {
763     guint pcm_channels, old_pcm_channels;
764     guint i;
765 
766     pcm_channels = g_value_get_uint(value);
767 
768     g_rec_mutex_lock(wasapi_devout_mutex);
769 
770     if(pcm_channels == wasapi_devout->pcm_channels){
771       g_rec_mutex_unlock(wasapi_devout_mutex);
772 
773       return;
774     }
775 
776     old_pcm_channels = wasapi_devout->pcm_channels;
777 
778     /* destroy if less pcm-channels */
779     for(i = 8 * wasapi_devout->sub_block_count * pcm_channels; i < 8 * wasapi_devout->sub_block_count * old_pcm_channels; i++){
780       g_rec_mutex_clear(wasapi_devout->sub_block_mutex[i]);
781 
782       free(wasapi_devout->sub_block_mutex[i]);
783     }
784 
785     wasapi_devout->sub_block_mutex = (GRecMutex **) realloc(wasapi_devout->sub_block_mutex,
786 								  8 * wasapi_devout->sub_block_count * pcm_channels * sizeof(GRecMutex *));
787 
788     /* create if more pcm-channels */
789     for(i = 8 * wasapi_devout->sub_block_count * old_pcm_channels; i < 8 * wasapi_devout->sub_block_count * pcm_channels; i++){
790       wasapi_devout->sub_block_mutex[i] = (GRecMutex *) malloc(sizeof(GRecMutex));
791 
792       g_rec_mutex_init(wasapi_devout->sub_block_mutex[i]);
793     }
794 
795     wasapi_devout->pcm_channels = pcm_channels;
796 
797     g_rec_mutex_unlock(wasapi_devout_mutex);
798 
799     ags_wasapi_devout_realloc_buffer(wasapi_devout);
800   }
801   break;
802   case PROP_FORMAT:
803   {
804     guint format;
805 
806     format = g_value_get_uint(value);
807 
808     g_rec_mutex_lock(wasapi_devout_mutex);
809 
810     if(format == wasapi_devout->format){
811       g_rec_mutex_unlock(wasapi_devout_mutex);
812 
813       return;
814     }
815 
816     wasapi_devout->format = format;
817 
818     g_rec_mutex_unlock(wasapi_devout_mutex);
819 
820     ags_wasapi_devout_realloc_buffer(wasapi_devout);
821   }
822   break;
823   case PROP_BUFFER_SIZE:
824   {
825     guint buffer_size;
826 
827     buffer_size = g_value_get_uint(value);
828 
829     g_rec_mutex_lock(wasapi_devout_mutex);
830 
831     if(buffer_size == wasapi_devout->buffer_size){
832       g_rec_mutex_unlock(wasapi_devout_mutex);
833 
834       return;
835     }
836 
837     wasapi_devout->buffer_size = buffer_size;
838 
839     g_rec_mutex_unlock(wasapi_devout_mutex);
840 
841     ags_wasapi_devout_realloc_buffer(wasapi_devout);
842     ags_wasapi_devout_adjust_delay_and_attack(wasapi_devout);
843   }
844   break;
845   case PROP_SAMPLERATE:
846   {
847     guint samplerate;
848 
849     samplerate = g_value_get_uint(value);
850 
851     g_rec_mutex_lock(wasapi_devout_mutex);
852 
853     if(samplerate == wasapi_devout->samplerate){
854       g_rec_mutex_unlock(wasapi_devout_mutex);
855 
856       return;
857     }
858 
859     wasapi_devout->samplerate = samplerate;
860 
861     g_rec_mutex_unlock(wasapi_devout_mutex);
862 
863     ags_wasapi_devout_realloc_buffer(wasapi_devout);
864     ags_wasapi_devout_adjust_delay_and_attack(wasapi_devout);
865   }
866   break;
867   case PROP_BUFFER:
868   {
869     //TODO:JK: implement me
870   }
871   break;
872   case PROP_BPM:
873   {
874     gdouble bpm;
875 
876     bpm = g_value_get_double(value);
877 
878     g_rec_mutex_lock(wasapi_devout_mutex);
879 
880     wasapi_devout->bpm = bpm;
881 
882     g_rec_mutex_unlock(wasapi_devout_mutex);
883 
884     ags_wasapi_devout_adjust_delay_and_attack(wasapi_devout);
885   }
886   break;
887   case PROP_DELAY_FACTOR:
888   {
889     gdouble delay_factor;
890 
891     delay_factor = g_value_get_double(value);
892 
893     g_rec_mutex_lock(wasapi_devout_mutex);
894 
895     wasapi_devout->delay_factor = delay_factor;
896 
897     g_rec_mutex_unlock(wasapi_devout_mutex);
898 
899     ags_wasapi_devout_adjust_delay_and_attack(wasapi_devout);
900   }
901   break;
902   default:
903     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
904     break;
905   }
906 }
907 
908 void
ags_wasapi_devout_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)909 ags_wasapi_devout_get_property(GObject *gobject,
910 			       guint prop_id,
911 			       GValue *value,
912 			       GParamSpec *param_spec)
913 {
914   AgsWasapiDevout *wasapi_devout;
915 
916   GRecMutex *wasapi_devout_mutex;
917 
918   wasapi_devout = AGS_WASAPI_DEVOUT(gobject);
919 
920   /* get wasapi devout mutex */
921   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
922 
923   switch(prop_id){
924   case PROP_DEVICE:
925   {
926     g_rec_mutex_lock(wasapi_devout_mutex);
927 
928     g_value_set_string(value, wasapi_devout->device);
929 
930     g_rec_mutex_unlock(wasapi_devout_mutex);
931   }
932   break;
933   case PROP_DSP_CHANNELS:
934   {
935     g_rec_mutex_lock(wasapi_devout_mutex);
936 
937     g_value_set_uint(value, wasapi_devout->dsp_channels);
938 
939     g_rec_mutex_unlock(wasapi_devout_mutex);
940   }
941   break;
942   case PROP_PCM_CHANNELS:
943   {
944     g_rec_mutex_lock(wasapi_devout_mutex);
945 
946     g_value_set_uint(value, wasapi_devout->pcm_channels);
947 
948     g_rec_mutex_unlock(wasapi_devout_mutex);
949   }
950   break;
951   case PROP_FORMAT:
952   {
953     g_rec_mutex_lock(wasapi_devout_mutex);
954 
955     g_value_set_uint(value, wasapi_devout->format);
956 
957     g_rec_mutex_unlock(wasapi_devout_mutex);
958   }
959   break;
960   case PROP_BUFFER_SIZE:
961   {
962     g_rec_mutex_lock(wasapi_devout_mutex);
963 
964     g_value_set_uint(value, wasapi_devout->buffer_size);
965 
966     g_rec_mutex_unlock(wasapi_devout_mutex);
967   }
968   break;
969   case PROP_SAMPLERATE:
970   {
971     g_rec_mutex_lock(wasapi_devout_mutex);
972 
973     g_value_set_uint(value, wasapi_devout->samplerate);
974 
975     g_rec_mutex_unlock(wasapi_devout_mutex);
976   }
977   break;
978   case PROP_BUFFER:
979   {
980     g_rec_mutex_lock(wasapi_devout_mutex);
981 
982     g_value_set_pointer(value, wasapi_devout->buffer);
983 
984     g_rec_mutex_unlock(wasapi_devout_mutex);
985   }
986   break;
987   case PROP_BPM:
988   {
989     g_rec_mutex_lock(wasapi_devout_mutex);
990 
991     g_value_set_double(value, wasapi_devout->bpm);
992 
993     g_rec_mutex_unlock(wasapi_devout_mutex);
994   }
995   break;
996   case PROP_DELAY_FACTOR:
997   {
998     g_rec_mutex_lock(wasapi_devout_mutex);
999 
1000     g_value_set_double(value, wasapi_devout->delay_factor);
1001 
1002     g_rec_mutex_unlock(wasapi_devout_mutex);
1003   }
1004   break;
1005   case PROP_ATTACK:
1006   {
1007     g_rec_mutex_lock(wasapi_devout_mutex);
1008 
1009     g_value_set_pointer(value, wasapi_devout->attack);
1010 
1011     g_rec_mutex_unlock(wasapi_devout_mutex);
1012   }
1013   break;
1014   default:
1015     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
1016     break;
1017   }
1018 }
1019 
1020 void
ags_wasapi_devout_dispose(GObject * gobject)1021 ags_wasapi_devout_dispose(GObject *gobject)
1022 {
1023   AgsWasapiDevout *wasapi_devout;
1024 
1025   GList *list;
1026 
1027   wasapi_devout = AGS_WASAPI_DEVOUT(gobject);
1028 
1029   /* call parent */
1030   G_OBJECT_CLASS(ags_wasapi_devout_parent_class)->dispose(gobject);
1031 }
1032 
1033 void
ags_wasapi_devout_finalize(GObject * gobject)1034 ags_wasapi_devout_finalize(GObject *gobject)
1035 {
1036   AgsWasapiDevout *wasapi_devout;
1037 
1038   wasapi_devout = AGS_WASAPI_DEVOUT(gobject);
1039 
1040   /* free output buffer */
1041   free(wasapi_devout->buffer[0]);
1042   free(wasapi_devout->buffer[1]);
1043   free(wasapi_devout->buffer[2]);
1044   free(wasapi_devout->buffer[3]);
1045   free(wasapi_devout->buffer[4]);
1046   free(wasapi_devout->buffer[5]);
1047   free(wasapi_devout->buffer[6]);
1048   free(wasapi_devout->buffer[7]);
1049 
1050   /* free buffer array */
1051   free(wasapi_devout->buffer);
1052 
1053   /* free AgsAttack */
1054   free(wasapi_devout->attack);
1055 
1056   /* call parent */
1057   G_OBJECT_CLASS(ags_wasapi_devout_parent_class)->finalize(gobject);
1058 }
1059 
1060 AgsUUID*
ags_wasapi_devout_get_uuid(AgsConnectable * connectable)1061 ags_wasapi_devout_get_uuid(AgsConnectable *connectable)
1062 {
1063   AgsWasapiDevout *wasapi_devout;
1064 
1065   AgsUUID *ptr;
1066 
1067   GRecMutex *wasapi_devout_mutex;
1068 
1069   wasapi_devout = AGS_WASAPI_DEVOUT(connectable);
1070 
1071   /* get wasapi devout signal mutex */
1072   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1073 
1074   /* get UUID */
1075   g_rec_mutex_lock(wasapi_devout_mutex);
1076 
1077   ptr = wasapi_devout->uuid;
1078 
1079   g_rec_mutex_unlock(wasapi_devout_mutex);
1080 
1081   return(ptr);
1082 }
1083 
1084 gboolean
ags_wasapi_devout_has_resource(AgsConnectable * connectable)1085 ags_wasapi_devout_has_resource(AgsConnectable *connectable)
1086 {
1087   return(FALSE);
1088 }
1089 
1090 gboolean
ags_wasapi_devout_is_ready(AgsConnectable * connectable)1091 ags_wasapi_devout_is_ready(AgsConnectable *connectable)
1092 {
1093   AgsWasapiDevout *wasapi_devout;
1094 
1095   gboolean is_ready;
1096 
1097   wasapi_devout = AGS_WASAPI_DEVOUT(connectable);
1098 
1099   /* check is added */
1100   is_ready = ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_ADDED_TO_REGISTRY);
1101 
1102   return(is_ready);
1103 }
1104 
1105 void
ags_wasapi_devout_add_to_registry(AgsConnectable * connectable)1106 ags_wasapi_devout_add_to_registry(AgsConnectable *connectable)
1107 {
1108   AgsWasapiDevout *wasapi_devout;
1109 
1110   if(ags_connectable_is_ready(connectable)){
1111     return;
1112   }
1113 
1114   wasapi_devout = AGS_WASAPI_DEVOUT(connectable);
1115 
1116   ags_wasapi_devout_set_flags(wasapi_devout, AGS_WASAPI_DEVOUT_ADDED_TO_REGISTRY);
1117 }
1118 
1119 void
ags_wasapi_devout_remove_from_registry(AgsConnectable * connectable)1120 ags_wasapi_devout_remove_from_registry(AgsConnectable *connectable)
1121 {
1122   AgsWasapiDevout *wasapi_devout;
1123 
1124   if(!ags_connectable_is_ready(connectable)){
1125     return;
1126   }
1127 
1128   wasapi_devout = AGS_WASAPI_DEVOUT(connectable);
1129 
1130   ags_wasapi_devout_unset_flags(wasapi_devout, AGS_WASAPI_DEVOUT_ADDED_TO_REGISTRY);
1131 }
1132 
1133 xmlNode*
ags_wasapi_devout_list_resource(AgsConnectable * connectable)1134 ags_wasapi_devout_list_resource(AgsConnectable *connectable)
1135 {
1136   xmlNode *node;
1137 
1138   node = NULL;
1139 
1140   //TODO:JK: implement me
1141 
1142   return(node);
1143 }
1144 
1145 xmlNode*
ags_wasapi_devout_xml_compose(AgsConnectable * connectable)1146 ags_wasapi_devout_xml_compose(AgsConnectable *connectable)
1147 {
1148   xmlNode *node;
1149 
1150   node = NULL;
1151 
1152   //TODO:JK: implement me
1153 
1154   return(node);
1155 }
1156 
1157 void
ags_wasapi_devout_xml_parse(AgsConnectable * connectable,xmlNode * node)1158 ags_wasapi_devout_xml_parse(AgsConnectable *connectable,
1159 			    xmlNode *node)
1160 {
1161   //TODO:JK: implement me
1162 }
1163 
1164 gboolean
ags_wasapi_devout_is_connected(AgsConnectable * connectable)1165 ags_wasapi_devout_is_connected(AgsConnectable *connectable)
1166 {
1167   AgsWasapiDevout *wasapi_devout;
1168 
1169   gboolean is_connected;
1170 
1171   wasapi_devout = AGS_WASAPI_DEVOUT(connectable);
1172 
1173   /* check is connected */
1174   is_connected = ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_CONNECTED);
1175 
1176   return(is_connected);
1177 }
1178 
1179 void
ags_wasapi_devout_connect(AgsConnectable * connectable)1180 ags_wasapi_devout_connect(AgsConnectable *connectable)
1181 {
1182   AgsWasapiDevout *wasapi_devout;
1183 
1184   if(ags_connectable_is_connected(connectable)){
1185     return;
1186   }
1187 
1188   wasapi_devout = AGS_WASAPI_DEVOUT(connectable);
1189 
1190   ags_wasapi_devout_set_flags(wasapi_devout, AGS_WASAPI_DEVOUT_CONNECTED);
1191 }
1192 
1193 void
ags_wasapi_devout_disconnect(AgsConnectable * connectable)1194 ags_wasapi_devout_disconnect(AgsConnectable *connectable)
1195 {
1196 
1197   AgsWasapiDevout *wasapi_devout;
1198 
1199   if(!ags_connectable_is_connected(connectable)){
1200     return;
1201   }
1202 
1203   wasapi_devout = AGS_WASAPI_DEVOUT(connectable);
1204 
1205   ags_wasapi_devout_unset_flags(wasapi_devout, AGS_WASAPI_DEVOUT_CONNECTED);
1206 }
1207 
1208 /**
1209  * ags_wasapi_devout_test_flags:
1210  * @wasapi_devout: the #AgsWasapiDevout
1211  * @flags: the flags
1212  *
1213  * Test @flags to be set on @wasapi_devout.
1214  *
1215  * Returns: %TRUE if flags are set, else %FALSE
1216  *
1217  * Since: 3.0.0
1218  */
1219 gboolean
ags_wasapi_devout_test_flags(AgsWasapiDevout * wasapi_devout,guint flags)1220 ags_wasapi_devout_test_flags(AgsWasapiDevout *wasapi_devout, guint flags)
1221 {
1222   gboolean retval;
1223 
1224   GRecMutex *wasapi_devout_mutex;
1225 
1226   if(!AGS_IS_WASAPI_DEVOUT(wasapi_devout)){
1227     return(FALSE);
1228   }
1229 
1230   /* get wasapi devout mutex */
1231   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1232 
1233   /* test */
1234   g_rec_mutex_lock(wasapi_devout_mutex);
1235 
1236   retval = (flags & (wasapi_devout->flags)) ? TRUE: FALSE;
1237 
1238   g_rec_mutex_unlock(wasapi_devout_mutex);
1239 
1240   return(retval);
1241 }
1242 
1243 /**
1244  * ags_wasapi_devout_set_flags:
1245  * @wasapi_devout: the #AgsWasapiDevout
1246  * @flags: see #AgsWasapiDevoutFlags-enum
1247  *
1248  * Enable a feature of @wasapi_devout.
1249  *
1250  * Since: 3.0.0
1251  */
1252 void
ags_wasapi_devout_set_flags(AgsWasapiDevout * wasapi_devout,guint flags)1253 ags_wasapi_devout_set_flags(AgsWasapiDevout *wasapi_devout, guint flags)
1254 {
1255   GRecMutex *wasapi_devout_mutex;
1256 
1257   if(!AGS_IS_WASAPI_DEVOUT(wasapi_devout)){
1258     return;
1259   }
1260 
1261   /* get wasapi devout mutex */
1262   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1263 
1264   //TODO:JK: add more?
1265 
1266   /* set flags */
1267   g_rec_mutex_lock(wasapi_devout_mutex);
1268 
1269   wasapi_devout->flags |= flags;
1270 
1271   g_rec_mutex_unlock(wasapi_devout_mutex);
1272 }
1273 
1274 /**
1275  * ags_wasapi_devout_unset_flags:
1276  * @wasapi_devout: the #AgsWasapiDevout
1277  * @flags: see #AgsWasapiDevoutFlags-enum
1278  *
1279  * Disable a feature of @wasapi_devout.
1280  *
1281  * Since: 3.0.0
1282  */
1283 void
ags_wasapi_devout_unset_flags(AgsWasapiDevout * wasapi_devout,guint flags)1284 ags_wasapi_devout_unset_flags(AgsWasapiDevout *wasapi_devout, guint flags)
1285 {
1286   GRecMutex *wasapi_devout_mutex;
1287 
1288   if(!AGS_IS_WASAPI_DEVOUT(wasapi_devout)){
1289     return;
1290   }
1291 
1292   /* get wasapi devout mutex */
1293   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1294 
1295   //TODO:JK: add more?
1296 
1297   /* unset flags */
1298   g_rec_mutex_lock(wasapi_devout_mutex);
1299 
1300   wasapi_devout->flags &= (~flags);
1301 
1302   g_rec_mutex_unlock(wasapi_devout_mutex);
1303 }
1304 
1305 void
ags_wasapi_devout_set_device(AgsSoundcard * soundcard,gchar * device)1306 ags_wasapi_devout_set_device(AgsSoundcard *soundcard,
1307 			     gchar *device)
1308 {
1309   AgsWasapiDevout *wasapi_devout;
1310 
1311   GList *card_id, *card_id_start, *card_name, *card_name_start;
1312 
1313   GRecMutex *wasapi_devout_mutex;
1314 
1315   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1316 
1317   /* get wasapi_devout mutex */
1318   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1319 
1320   /* list cards */
1321   card_id = NULL;
1322   card_name = NULL;
1323 
1324   ags_soundcard_list_cards(soundcard,
1325 			   &card_id, &card_name);
1326 
1327   card_id_start = card_id;
1328   card_name_start = card_name;
1329 
1330   /* check card */
1331   g_rec_mutex_lock(wasapi_devout_mutex);
1332 
1333   while(card_id != NULL){
1334     if(!g_ascii_strncasecmp(card_id->data,
1335 			    device,
1336 			    strlen(card_id->data))){
1337       wasapi_devout->device = g_strdup(device);
1338 
1339       break;
1340     }
1341 
1342     card_id = card_id->next;
1343   }
1344 
1345   g_rec_mutex_unlock(wasapi_devout_mutex);
1346 
1347   /* free card id and name */
1348   g_list_free_full(card_id_start,
1349 		   g_free);
1350   g_list_free_full(card_name_start,
1351 		   g_free);
1352 }
1353 
1354 gchar*
ags_wasapi_devout_get_device(AgsSoundcard * soundcard)1355 ags_wasapi_devout_get_device(AgsSoundcard *soundcard)
1356 {
1357   AgsWasapiDevout *wasapi_devout;
1358 
1359   gchar *device;
1360 
1361   GRecMutex *wasapi_devout_mutex;
1362 
1363   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1364 
1365   /* get wasapi devout mutex */
1366   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1367 
1368   device = NULL;
1369 
1370   /* get device */
1371   g_rec_mutex_lock(wasapi_devout_mutex);
1372 
1373   device = g_strdup(wasapi_devout->device);
1374 
1375   g_rec_mutex_unlock(wasapi_devout_mutex);
1376 
1377   return(device);
1378 }
1379 
1380 void
ags_wasapi_devout_set_presets(AgsSoundcard * soundcard,guint channels,guint rate,guint buffer_size,guint format)1381 ags_wasapi_devout_set_presets(AgsSoundcard *soundcard,
1382 			      guint channels,
1383 			      guint rate,
1384 			      guint buffer_size,
1385 			      guint format)
1386 {
1387   AgsWasapiDevout *wasapi_devout;
1388 
1389   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1390 
1391   g_object_set(wasapi_devout,
1392 	       "pcm-channels", channels,
1393 	       "samplerate", rate,
1394 	       "buffer-size", buffer_size,
1395 	       "format", format,
1396 	       NULL);
1397 }
1398 
1399 void
ags_wasapi_devout_get_presets(AgsSoundcard * soundcard,guint * channels,guint * rate,guint * buffer_size,guint * format)1400 ags_wasapi_devout_get_presets(AgsSoundcard *soundcard,
1401 			      guint *channels,
1402 			      guint *rate,
1403 			      guint *buffer_size,
1404 			      guint *format)
1405 {
1406   AgsWasapiDevout *wasapi_devout;
1407 
1408   GRecMutex *wasapi_devout_mutex;
1409 
1410   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1411 
1412   /* get wasapi devout mutex */
1413   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1414 
1415   /* get presets */
1416   g_rec_mutex_lock(wasapi_devout_mutex);
1417 
1418   if(channels != NULL){
1419     *channels = wasapi_devout->pcm_channels;
1420   }
1421 
1422   if(rate != NULL){
1423     *rate = wasapi_devout->samplerate;
1424   }
1425 
1426   if(buffer_size != NULL){
1427     *buffer_size = wasapi_devout->buffer_size;
1428   }
1429 
1430   if(format != NULL){
1431     *format = wasapi_devout->format;
1432   }
1433 
1434   g_rec_mutex_unlock(wasapi_devout_mutex);
1435 }
1436 
1437 void
ags_wasapi_devout_list_cards(AgsSoundcard * soundcard,GList ** card_id,GList ** card_name)1438 ags_wasapi_devout_list_cards(AgsSoundcard *soundcard,
1439 			     GList **card_id, GList **card_name)
1440 {
1441   AgsWasapiDevout *wasapi_devout;
1442 
1443   AgsApplicationContext *application_context;
1444 
1445 #ifdef AGS_WITH_WASAPI
1446   IMMDeviceEnumerator *dev_enumerator;
1447   IMMDeviceCollection *dev_collection;
1448 
1449   UINT i, i_stop;
1450 #endif
1451 
1452   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1453 
1454   application_context = ags_application_context_get_instance();
1455 
1456   if(card_id != NULL){
1457     *card_id = NULL;
1458   }
1459 
1460   if(card_name != NULL){
1461     *card_name = NULL;
1462   }
1463 
1464 #ifdef AGS_WITH_WASAPI
1465   CoInitialize(0);
1466 
1467   CoCreateInstance(&ags_wasapi_clsid_mm_device_enumerator_guid, 0, CLSCTX_ALL, &ags_wasapi_iid_mm_device_enumerator_guid, &dev_enumerator);
1468 
1469   dev_enumerator->lpVtbl->EnumAudioEndpoints(dev_enumerator, eRender, DEVICE_STATE_ACTIVE, &dev_collection);
1470 
1471   dev_collection->lpVtbl->GetCount(dev_collection,
1472 				   &i_stop);
1473 
1474   for(i = 0; i < i_stop; i++){
1475     IMMDevice *device;
1476 
1477     IPropertyStore *prop_store;
1478 
1479     LPWSTR dev_id = NULL;
1480     PROPVARIANT var_name;
1481     gchar *str;
1482 
1483     dev_collection->lpVtbl->Item(dev_collection, i, &device);
1484 
1485     device->lpVtbl->GetId(device, &dev_id);
1486 
1487     device->lpVtbl->OpenPropertyStore(device, STGM_READ, &prop_store);
1488 
1489     PropVariantInit(&var_name);
1490 
1491     prop_store->lpVtbl->GetValue(prop_store, &ags_wasapi_pkey_device_friendly_name_key, &var_name);
1492 
1493     g_message("%S %S", dev_id, var_name.pwszVal);
1494 
1495     if(card_id != NULL){
1496       str = g_strdup_printf("%S", dev_id);
1497 
1498       *card_id = g_list_prepend(*card_id,
1499 				str);
1500     }
1501 
1502     if(card_name != NULL){
1503       str = g_strdup_printf("%S", var_name.pwszVal);
1504 
1505       *card_name = g_list_prepend(*card_name,
1506 				  str);
1507     }
1508 
1509     CoTaskMemFree(dev_id);
1510 
1511     PropVariantClear(&var_name);
1512 
1513     prop_store->lpVtbl->Release(prop_store);
1514 
1515     device->lpVtbl->Release(device);
1516   }
1517 
1518   dev_collection->lpVtbl->Release(dev_collection);
1519 
1520   dev_enumerator->lpVtbl->Release(dev_enumerator);
1521 
1522   CoUninitialize();
1523 #endif
1524 
1525   if(card_id != NULL && *card_id != NULL){
1526     *card_id = g_list_reverse(*card_id);
1527   }
1528 
1529   if(card_name != NULL && *card_name != NULL){
1530     *card_name = g_list_reverse(*card_name);
1531   }
1532 }
1533 
1534 void
ags_wasapi_devout_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)1535 ags_wasapi_devout_pcm_info(AgsSoundcard *soundcard,
1536 			   char *card_id,
1537 			   guint *channels_min, guint *channels_max,
1538 			   guint *rate_min, guint *rate_max,
1539 			   guint *buffer_size_min, guint *buffer_size_max,
1540 			   GError **error)
1541 {
1542   if(channels_min != NULL){
1543     *channels_min = 1;
1544   }
1545 
1546   if(channels_max != NULL){
1547     *channels_max = 1024;
1548   }
1549 
1550   if(rate_min != NULL){
1551     *rate_min = 8000;
1552   }
1553 
1554   if(rate_max != NULL){
1555     *rate_max = 192000;
1556   }
1557 
1558   if(buffer_size_min != NULL){
1559     *buffer_size_min = 64;
1560   }
1561 
1562   if(buffer_size_max != NULL){
1563     *buffer_size_max = 8192;
1564   }
1565 }
1566 
1567 guint
ags_wasapi_devout_get_capability(AgsSoundcard * soundcard)1568 ags_wasapi_devout_get_capability(AgsSoundcard *soundcard)
1569 {
1570   return(AGS_SOUNDCARD_CAPABILITY_PLAYBACK);
1571 }
1572 
1573 gboolean
ags_wasapi_devout_is_starting(AgsSoundcard * soundcard)1574 ags_wasapi_devout_is_starting(AgsSoundcard *soundcard)
1575 {
1576   AgsWasapiDevout *wasapi_devout;
1577 
1578   gboolean is_starting;
1579 
1580   GRecMutex *wasapi_devout_mutex;
1581 
1582   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1583 
1584   /* get wasapi devout mutex */
1585   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1586 
1587   /* check is starting */
1588   g_rec_mutex_lock(wasapi_devout_mutex);
1589 
1590   is_starting = ((AGS_WASAPI_DEVOUT_START_PLAY & (wasapi_devout->flags)) != 0) ? TRUE: FALSE;
1591 
1592   g_rec_mutex_unlock(wasapi_devout_mutex);
1593 
1594   return(is_starting);
1595 }
1596 
1597 gboolean
ags_wasapi_devout_is_playing(AgsSoundcard * soundcard)1598 ags_wasapi_devout_is_playing(AgsSoundcard *soundcard)
1599 {
1600   AgsWasapiDevout *wasapi_devout;
1601 
1602   gboolean is_playing;
1603 
1604   GRecMutex *wasapi_devout_mutex;
1605 
1606   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1607 
1608   /* get wasapi devout mutex */
1609   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1610 
1611   /* check is starting */
1612   g_rec_mutex_lock(wasapi_devout_mutex);
1613 
1614   is_playing = ((AGS_WASAPI_DEVOUT_PLAY & (wasapi_devout->flags)) != 0) ? TRUE: FALSE;
1615 
1616   g_rec_mutex_unlock(wasapi_devout_mutex);
1617 
1618   return(is_playing);
1619 }
1620 
1621 gchar*
ags_wasapi_devout_get_uptime(AgsSoundcard * soundcard)1622 ags_wasapi_devout_get_uptime(AgsSoundcard *soundcard)
1623 {
1624   gchar *uptime;
1625 
1626   if(ags_soundcard_is_playing(soundcard)){
1627     guint samplerate;
1628     guint buffer_size;
1629 
1630     guint note_offset;
1631     gdouble bpm;
1632     gdouble delay_factor;
1633 
1634     gdouble delay;
1635 
1636     ags_soundcard_get_presets(soundcard,
1637 			      NULL,
1638 			      &samplerate,
1639 			      &buffer_size,
1640 			      NULL);
1641 
1642     note_offset = ags_soundcard_get_note_offset_absolute(soundcard);
1643 
1644     bpm = ags_soundcard_get_bpm(soundcard);
1645     delay_factor = ags_soundcard_get_delay_factor(soundcard);
1646 
1647     /* calculate delays */
1648     delay = ags_soundcard_get_absolute_delay(soundcard);
1649 
1650     uptime = ags_time_get_uptime_from_offset(note_offset,
1651 					     bpm,
1652 					     delay,
1653 					     delay_factor);
1654   }else{
1655     uptime = g_strdup(AGS_TIME_ZERO);
1656   }
1657 
1658   return(uptime);
1659 }
1660 
1661 void
ags_wasapi_devout_client_init(AgsSoundcard * soundcard,GError ** error)1662 ags_wasapi_devout_client_init(AgsSoundcard *soundcard,
1663 			      GError **error)
1664 {
1665   AgsWasapiDevout *wasapi_devout;
1666 
1667   GRecMutex *wasapi_devout_mutex;
1668 
1669   if(ags_soundcard_is_playing(soundcard)){
1670     return;
1671   }
1672 
1673   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1674 
1675   /* get wasapi devout mutex */
1676   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1677 
1678   g_rec_mutex_lock(wasapi_devout_mutex);
1679 
1680   wasapi_devout->tact_counter = 0.0;
1681   wasapi_devout->delay_counter = floor(ags_soundcard_get_absolute_delay(AGS_SOUNDCARD(wasapi_devout)));
1682   wasapi_devout->tic_counter = 0;
1683 
1684 #ifdef AGS_WITH_WASAPI
1685   wasapi_devout->flags |= AGS_WASAPI_DEVOUT_INITIALIZED;
1686 #endif
1687   wasapi_devout->flags |= (AGS_WASAPI_DEVOUT_BUFFER0 |
1688 			   AGS_WASAPI_DEVOUT_START_PLAY |
1689 			   AGS_WASAPI_DEVOUT_PLAY |
1690 			   AGS_WASAPI_DEVOUT_NONBLOCKING);
1691   wasapi_devout->flags &= (~(AGS_WASAPI_DEVOUT_BUFFER1 |
1692 			     AGS_WASAPI_DEVOUT_BUFFER2 |
1693 			     AGS_WASAPI_DEVOUT_BUFFER3 |
1694 			     AGS_WASAPI_DEVOUT_BUFFER4 |
1695 			     AGS_WASAPI_DEVOUT_BUFFER5 |
1696 			     AGS_WASAPI_DEVOUT_BUFFER6 |
1697 			     AGS_WASAPI_DEVOUT_BUFFER7));
1698 
1699   g_rec_mutex_unlock(wasapi_devout_mutex);
1700 }
1701 
1702 void
ags_wasapi_devout_client_play(AgsSoundcard * soundcard,GError ** error)1703 ags_wasapi_devout_client_play(AgsSoundcard *soundcard,
1704 			      GError **error)
1705 {
1706   AgsWasapiDevout *wasapi_devout;
1707 
1708   AgsTicDevice *tic_device;
1709   AgsClearBuffer *clear_buffer;
1710   AgsSwitchBufferFlag *switch_buffer_flag;
1711 
1712   AgsTaskLauncher *task_launcher;
1713 
1714   AgsApplicationContext *application_context;
1715 
1716   GList *task;
1717   GList *list;
1718 
1719   gchar *str;
1720 
1721 #ifdef AGS_WITH_WASAPI
1722   IAudioClient *audio_client;
1723   IAudioRenderClient *audio_render_client;
1724 
1725   BYTE *data;
1726 
1727   UINT32 buffer_frame_count;
1728   UINT32 num_frames_available;
1729 #endif
1730 
1731   guint word_size;
1732   guint nth_buffer;
1733 
1734   GRecMutex *wasapi_devout_mutex;
1735 
1736   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
1737 
1738   application_context = ags_application_context_get_instance();
1739 
1740   /* get wasapi devout mutex */
1741   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
1742 
1743   /* lock */
1744   g_rec_mutex_lock(wasapi_devout_mutex);
1745 
1746   /* retrieve word size */
1747   switch(wasapi_devout->format){
1748   case AGS_SOUNDCARD_SIGNED_16_BIT:
1749   {
1750     word_size = sizeof(gint16);
1751   }
1752   break;
1753   case AGS_SOUNDCARD_SIGNED_24_BIT:
1754   {
1755     word_size = sizeof(gint32);
1756   }
1757   break;
1758   case AGS_SOUNDCARD_SIGNED_32_BIT:
1759   {
1760     word_size = sizeof(gint32);
1761   }
1762   break;
1763   default:
1764     g_rec_mutex_unlock(wasapi_devout_mutex);
1765 
1766     g_warning("ags_wasapi_devout_alsa_play(): unsupported word size");
1767 
1768     return;
1769   }
1770 
1771   /* do playback */
1772 #ifdef AGS_WITH_WASAPI
1773   if((AGS_WASAPI_DEVOUT_START_PLAY & (wasapi_devout->flags)) != 0){
1774     IMMDeviceEnumerator *dev_enumerator;
1775     IMMDevice *mm_device;
1776 
1777     WAVEFORMATEXTENSIBLE wave_format;
1778     WAVEFORMATEX *desired_format, *internal_format;
1779 
1780     wchar_t dev_id[1024];
1781 
1782     REFERENCE_TIME min_duration;
1783 
1784     register HRESULT hr;
1785 
1786     unsigned char bit_resolution;
1787 
1788     g_message("WASAPI initialize");
1789 
1790     CoInitialize(0);
1791 
1792     if(CoCreateInstance(&ags_wasapi_clsid_mm_device_enumerator_guid, 0, CLSCTX_ALL, &ags_wasapi_iid_mm_device_enumerator_guid, (void **) &dev_enumerator)){
1793       if(error != NULL){
1794 	g_set_error(error,
1795 		    AGS_WASAPI_DEVOUT_ERROR,
1796 		    AGS_WASAPI_DEVOUT_ERROR_LOCKED_SOUNDCARD,
1797 		    "unable to open pcm device: Can't get IMMDeviceEnumerator.");
1798       }
1799 
1800       CoUninitialize();
1801 
1802       g_rec_mutex_unlock(wasapi_devout_mutex);
1803 
1804       g_message("WASAPI failed - device enumerator");
1805 
1806       wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_START_PLAY);
1807 
1808       return;
1809     }
1810 
1811     if(wasapi_devout->device != NULL){
1812       memset(dev_id, 0, 1024 * sizeof(WCHAR));
1813       swprintf(dev_id, 1024, L"%S", wasapi_devout->device);
1814 
1815       if(dev_enumerator->lpVtbl->GetDevice(dev_enumerator, dev_id, &mm_device)){
1816 	if(error != NULL){
1817 	  g_set_error(error,
1818 		      AGS_WASAPI_DEVOUT_ERROR,
1819 		      AGS_WASAPI_DEVOUT_ERROR_LOCKED_SOUNDCARD,
1820 		      "unable to open pcm device: Can't get IAudioClient.");
1821 	}
1822 
1823 	dev_enumerator->lpVtbl->Release(dev_enumerator);
1824 	CoUninitialize();
1825 
1826 	wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_START_PLAY);
1827 
1828 	g_rec_mutex_unlock(wasapi_devout_mutex);
1829 
1830 	g_message("WASAPI failed - get device");
1831 
1832 	return;
1833       }
1834     }else{
1835       if(dev_enumerator->lpVtbl->GetDefaultAudioEndpoint(dev_enumerator, eRender, eMultimedia, &mm_device)){
1836 	if(error != NULL){
1837 	  g_set_error(error,
1838 		      AGS_WASAPI_DEVOUT_ERROR,
1839 		      AGS_WASAPI_DEVOUT_ERROR_LOCKED_SOUNDCARD,
1840 		      "unable to open pcm device: Can't get IAudioClient.");
1841 	}
1842 
1843 	dev_enumerator->lpVtbl->Release(dev_enumerator);
1844 	CoUninitialize();
1845 
1846 	wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_START_PLAY);
1847 
1848 	g_rec_mutex_unlock(wasapi_devout_mutex);
1849 
1850 	g_message("WASAPI failed - get device");
1851 
1852 	return;
1853       }
1854     }
1855 
1856     wasapi_devout->mm_device = mm_device;
1857 
1858     // Get its IAudioClient (used to set audio format, latency, and start/stop)
1859     if(mm_device->lpVtbl->Activate(mm_device, &ags_wasapi_iid_audio_client_guid, CLSCTX_ALL, 0, (void **) &audio_client)){
1860       if(error != NULL){
1861 	g_set_error(error,
1862 		    AGS_WASAPI_DEVOUT_ERROR,
1863 		    AGS_WASAPI_DEVOUT_ERROR_LOCKED_SOUNDCARD,
1864 		    "unable to open pcm device: Can't get IAudioClient.");
1865       }
1866 
1867       mm_device->lpVtbl->Release(mm_device);
1868       dev_enumerator->lpVtbl->Release(dev_enumerator);
1869       CoUninitialize();
1870 
1871       wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_START_PLAY);
1872 
1873       g_rec_mutex_unlock(wasapi_devout_mutex);
1874 
1875       g_message("WASAPI failed - get audio client");
1876 
1877       return;
1878     }
1879 
1880     wasapi_devout->audio_client = audio_client;
1881 
1882     if((AGS_WASAPI_DEVOUT_SHARE_MODE_EXCLUSIVE & (wasapi_devout->flags)) != 0){
1883       wave_format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1884       wave_format.Format.nSamplesPerSec = wasapi_devout->samplerate; // necessary
1885       wave_format.Format.nChannels = wasapi_devout->pcm_channels; // presumed
1886 
1887       bit_resolution = 16;
1888 
1889       switch(wasapi_devout->format){
1890       case AGS_SOUNDCARD_SIGNED_16_BIT:
1891       {
1892 	bit_resolution = 16;
1893       }
1894       break;
1895       case AGS_SOUNDCARD_SIGNED_24_BIT:
1896       {
1897 	bit_resolution = 24;
1898       }
1899       break;
1900       case AGS_SOUNDCARD_SIGNED_32_BIT:
1901       {
1902 	bit_resolution = 32;
1903       }
1904       break;
1905       }
1906 
1907       if(bit_resolution == 24){
1908 	wave_format.Format.wBitsPerSample = 32;
1909 	wave_format.Format.nBlockAlign = 2 * (32 / 8);
1910 	wave_format.Samples.wValidBitsPerSample = 24;
1911       }else{
1912 	wave_format.Format.wBitsPerSample =
1913 	  wave_format.Samples.wValidBitsPerSample = bit_resolution;
1914 	wave_format.Format.nBlockAlign = 2 * (bit_resolution / 8);
1915       }
1916 
1917       wave_format.Format.nBlockAlign = wave_format.Format.nChannels * wave_format.Format.wBitsPerSample / 8;
1918       wave_format.Format.nAvgBytesPerSec = wave_format.Format.nSamplesPerSec * wave_format.Format.nBlockAlign;
1919       wave_format.Format.cbSize = 22;
1920       wave_format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
1921       wave_format.SubFormat = ags_wasapi_pcm_subformat_guid;
1922 
1923       if((hr = audio_client->lpVtbl->GetMixFormat(audio_client, &internal_format))){
1924 	g_message("get mix format");
1925       }
1926 
1927       desired_format = &(wave_format.Format);
1928 
1929       desired_format->wFormatTag = 0xFFFE;
1930       desired_format->cbSize = 22;
1931 
1932       if((hr = audio_client->lpVtbl->IsFormatSupported(audio_client, AUDCLNT_SHAREMODE_EXCLUSIVE, desired_format, NULL))){
1933       ags_wasapi_devout_client_init_EXCLUSIVE_BROKEN_CONFIGURATION:
1934 
1935 	mm_device->lpVtbl->Release(mm_device);
1936 	dev_enumerator->lpVtbl->Release(dev_enumerator);
1937 	CoUninitialize();
1938 
1939 	wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_START_PLAY);
1940 
1941 	g_rec_mutex_unlock(wasapi_devout_mutex);
1942 
1943 	g_message("WASAPI failed - broken configuration");
1944 
1945 	return;
1946       }
1947 
1948       audio_client->lpVtbl->GetDevicePeriod(audio_client, NULL, &min_duration);
1949 
1950       min_duration = (AGS_NSEC_PER_SEC / 100) / wasapi_devout->samplerate * wasapi_devout->wasapi_buffer_size;
1951 
1952       if((hr = audio_client->lpVtbl->Initialize(audio_client, AUDCLNT_SHAREMODE_EXCLUSIVE, 0, min_duration, min_duration, desired_format, NULL))){
1953 	audio_client->lpVtbl->Release(audio_client);
1954 
1955 	goto ags_wasapi_devout_client_init_EXCLUSIVE_BROKEN_CONFIGURATION;
1956       }
1957     }else{
1958       wave_format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1959       wave_format.Format.nSamplesPerSec = wasapi_devout->samplerate; // necessary
1960       wave_format.Format.nChannels = wasapi_devout->pcm_channels; // presumed
1961 
1962       bit_resolution = 16;
1963 
1964       switch(wasapi_devout->format){
1965       case AGS_SOUNDCARD_SIGNED_16_BIT:
1966       {
1967 	bit_resolution = 16;
1968       }
1969       break;
1970       case AGS_SOUNDCARD_SIGNED_24_BIT:
1971       {
1972 	bit_resolution = 24;
1973       }
1974       break;
1975       case AGS_SOUNDCARD_SIGNED_32_BIT:
1976       {
1977 	bit_resolution = 32;
1978       }
1979       break;
1980       }
1981 
1982       if(bit_resolution == 24){
1983 	wave_format.Format.wBitsPerSample = 32;
1984 	wave_format.Format.nBlockAlign = 2 * (32 / 8);
1985 	wave_format.Samples.wValidBitsPerSample = 24;
1986       }else{
1987 	wave_format.Format.wBitsPerSample =
1988 	  wave_format.Samples.wValidBitsPerSample = bit_resolution;
1989 	wave_format.Format.nBlockAlign = 2 * (bit_resolution / 8);
1990       }
1991 
1992       wave_format.Format.nBlockAlign = wave_format.Format.nChannels * wave_format.Format.wBitsPerSample / 8;
1993       wave_format.Format.nAvgBytesPerSec = wave_format.Format.nSamplesPerSec * wave_format.Format.nBlockAlign;
1994       wave_format.Format.cbSize = 22;
1995       wave_format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
1996       wave_format.SubFormat = ags_wasapi_pcm_subformat_guid;
1997 
1998       if((hr = audio_client->lpVtbl->GetMixFormat(audio_client, &internal_format))){
1999 	g_message("get mix format");
2000 
2001       ags_wasapi_devout_client_init_SHARED_BROKEN_CONFIGURATION:
2002 
2003 	mm_device->lpVtbl->Release(mm_device);
2004 	dev_enumerator->lpVtbl->Release(dev_enumerator);
2005 	CoUninitialize();
2006 
2007 	wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_START_PLAY);
2008 
2009 	g_rec_mutex_unlock(wasapi_devout_mutex);
2010 
2011 	g_message("WASAPI failed - broken configuration");
2012 
2013 	return;
2014       }
2015 
2016       desired_format = internal_format;
2017 
2018       if((hr = audio_client->lpVtbl->IsFormatSupported(audio_client, AUDCLNT_SHAREMODE_SHARED, desired_format, &desired_format))){
2019 	goto ags_wasapi_devout_client_init_SHARED_BROKEN_CONFIGURATION;
2020       }
2021 
2022       desired_format = internal_format;
2023 
2024       audio_client->lpVtbl->GetDevicePeriod(audio_client, NULL, &min_duration);
2025 
2026       min_duration = (AGS_NSEC_PER_SEC / 100) / wasapi_devout->samplerate * wasapi_devout->wasapi_buffer_size;
2027 
2028       if((hr = audio_client->lpVtbl->Initialize(audio_client, AUDCLNT_SHAREMODE_SHARED, 0, min_duration, 0, desired_format, NULL))){
2029 	audio_client->lpVtbl->Release(audio_client);
2030 
2031 	goto ags_wasapi_devout_client_init_SHARED_BROKEN_CONFIGURATION;
2032       }
2033     }
2034 
2035     // Start audio playback
2036     audio_client->lpVtbl->Start(audio_client);
2037   }
2038 
2039   audio_client = wasapi_devout->audio_client;
2040 #endif
2041 
2042   wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_START_PLAY);
2043 
2044   if((AGS_WASAPI_DEVOUT_INITIALIZED & (wasapi_devout->flags)) == 0){
2045     g_rec_mutex_unlock(wasapi_devout_mutex);
2046 
2047     return;
2048   }
2049 
2050   //  g_message("play - 0x%0x", ((AGS_WASAPI_DEVOUT_BUFFER0 |
2051   //				AGS_WASAPI_DEVOUT_BUFFER1 |
2052   //				AGS_WASAPI_DEVOUT_BUFFER2 |
2053   //				AGS_WASAPI_DEVOUT_BUFFER3) & (wasapi_devout->flags)));
2054 
2055   if((AGS_WASAPI_DEVOUT_SHUTDOWN & (wasapi_devout->flags)) == 0){
2056     /* check buffer flag */
2057     nth_buffer = 0;
2058 
2059     if((AGS_WASAPI_DEVOUT_BUFFER0 & (wasapi_devout->flags)) != 0){
2060       nth_buffer = 0;
2061     }else if((AGS_WASAPI_DEVOUT_BUFFER1 & (wasapi_devout->flags)) != 0){
2062       nth_buffer = 1;
2063     }else if((AGS_WASAPI_DEVOUT_BUFFER2 & (wasapi_devout->flags)) != 0){
2064       nth_buffer = 2;
2065     }else if((AGS_WASAPI_DEVOUT_BUFFER3 & (wasapi_devout->flags)) != 0){
2066       nth_buffer = 3;
2067     }else if((AGS_WASAPI_DEVOUT_BUFFER4 & (wasapi_devout->flags)) != 0){
2068       nth_buffer = 4;
2069     }else if((AGS_WASAPI_DEVOUT_BUFFER5 & (wasapi_devout->flags)) != 0){
2070       nth_buffer = 5;
2071     }else if((AGS_WASAPI_DEVOUT_BUFFER6 & (wasapi_devout->flags)) != 0){
2072       nth_buffer = 6;
2073     }else if((AGS_WASAPI_DEVOUT_BUFFER7 & (wasapi_devout->flags)) != 0){
2074       nth_buffer = 7;
2075     }
2076 
2077 #ifdef AGS_WITH_WASAPI
2078     audio_client->lpVtbl->GetBufferSize(audio_client, &buffer_frame_count);
2079 
2080     {
2081       HRESULT res;
2082 
2083       res = audio_client->lpVtbl->GetService(audio_client, &ags_wasapi_iid_audio_render_client_guid, (void **) &audio_render_client);
2084 
2085       switch(res){
2086       case E_POINTER:
2087       {
2088 	g_message("pointer");
2089       }
2090       break;
2091       case E_NOINTERFACE:
2092       {
2093 	g_message("no interface");
2094       }
2095       break;
2096       case AUDCLNT_E_NOT_INITIALIZED:
2097       {
2098 	g_message("not initialized");
2099       }
2100       break;
2101       case AUDCLNT_E_WRONG_ENDPOINT_TYPE:
2102       {
2103 	g_message("wrong endpoint");
2104       }
2105       break;
2106       case AUDCLNT_E_DEVICE_INVALIDATED:
2107       {
2108 	g_message("device invalidated");
2109       }
2110       break;
2111       case AUDCLNT_E_SERVICE_NOT_RUNNING:
2112       {
2113 	g_message("no service");
2114       }
2115       break;
2116       }
2117     }
2118 
2119     if(audio_render_client == NULL){
2120       g_rec_mutex_unlock(wasapi_devout_mutex);
2121 
2122       g_message("audio_render_client = NULL");
2123 
2124       return;
2125     }
2126 
2127     {
2128       UINT32 padding_frames;
2129 
2130       static const struct timespec poll_delay = {
2131 	0,
2132 	400,
2133       };
2134 
2135       audio_client->lpVtbl->GetCurrentPadding(audio_client, &padding_frames);
2136 
2137       while(buffer_frame_count - padding_frames < wasapi_devout->buffer_size &&
2138 	    padding_frames != 0){
2139 	nanosleep(&poll_delay, NULL);
2140 
2141 	audio_client->lpVtbl->GetCurrentPadding(audio_client, &padding_frames);
2142       }
2143     }
2144 
2145     {
2146       HRESULT res;
2147 
2148       res = audio_render_client->lpVtbl->GetBuffer(audio_render_client, wasapi_devout->buffer_size, &data);
2149 
2150       switch(res){
2151       case AUDCLNT_E_BUFFER_ERROR:
2152       {
2153 	g_message("buffer error");
2154       }
2155       break;
2156       case AUDCLNT_E_BUFFER_TOO_LARGE:
2157       {
2158 	g_message("buffer too large");
2159       }
2160       break;
2161       case AUDCLNT_E_BUFFER_SIZE_ERROR:
2162       {
2163 	g_message("buffer size error");
2164       }
2165       break;
2166       case AUDCLNT_E_OUT_OF_ORDER:
2167       {
2168 	g_message("out of order");
2169       }
2170       break;
2171       case AUDCLNT_E_DEVICE_INVALIDATED:
2172       {
2173 	g_message("invalidated");
2174       }
2175       break;
2176       case AUDCLNT_E_BUFFER_OPERATION_PENDING:
2177       {
2178 	g_message("operation pending");
2179       }
2180       break;
2181       case AUDCLNT_E_SERVICE_NOT_RUNNING:
2182       {
2183 	g_message("no service");
2184       }
2185       break;
2186       case E_POINTER:
2187       {
2188 	g_message("pointer");
2189       }
2190       break;
2191       }
2192     }
2193 
2194     /* retrieve word size */
2195     if(data != NULL){
2196       ags_soundcard_lock_buffer(soundcard,
2197 				wasapi_devout->buffer[nth_buffer]);
2198 
2199       switch(wasapi_devout->format){
2200       case AGS_SOUNDCARD_SIGNED_16_BIT:
2201       {
2202 	memset(data, 0, wasapi_devout->pcm_channels * wasapi_devout->buffer_size * sizeof(gint16));
2203 	ags_audio_buffer_util_copy_s16_to_s16((gint16 *) data, 1,
2204 					      (gint16 *) wasapi_devout->buffer[nth_buffer], 1,
2205 					      wasapi_devout->pcm_channels * wasapi_devout->buffer_size);
2206       }
2207       break;
2208       case AGS_SOUNDCARD_SIGNED_24_BIT:
2209       {
2210 	memset(data, 0, wasapi_devout->pcm_channels * wasapi_devout->buffer_size * sizeof(gint32));
2211 	ags_audio_buffer_util_copy_s24_to_s24((gint32 *) data, 1,
2212 					      (gint32 *) wasapi_devout->buffer[nth_buffer], 1,
2213 					      wasapi_devout->pcm_channels * wasapi_devout->buffer_size);
2214       }
2215       break;
2216       case AGS_SOUNDCARD_SIGNED_32_BIT:
2217       {
2218 	memset(data, 0, wasapi_devout->pcm_channels * wasapi_devout->buffer_size * sizeof(gint32));
2219 	ags_audio_buffer_util_copy_s32_to_s32((gint32 *) data, 1,
2220 					      (gint32 *) wasapi_devout->buffer[nth_buffer], 1,
2221 					      wasapi_devout->pcm_channels * wasapi_devout->buffer_size);
2222       }
2223       break;
2224       }
2225 
2226       ags_soundcard_unlock_buffer(soundcard,
2227 				  wasapi_devout->buffer[nth_buffer]);
2228     }else{
2229       g_message("data = NULL");
2230     }
2231 
2232     audio_render_client->lpVtbl->ReleaseBuffer(audio_render_client, wasapi_devout->buffer_size, 0);
2233 
2234     audio_render_client->lpVtbl->Release(audio_render_client);
2235 #endif
2236   }
2237 
2238   if((AGS_WASAPI_DEVOUT_SHUTDOWN & (wasapi_devout->flags)) != 0){
2239     AgsThread *audio_loop;
2240     AgsThread *soundcard_thread;
2241 
2242     AgsApplicationContext *application_context;
2243 
2244 #ifdef AGS_WITH_WASAPI
2245     IMMDevice *mm_device;
2246 
2247     HRESULT hr;
2248 
2249     g_message("wasapi shutdown");
2250 
2251     audio_client = wasapi_devout->audio_client;
2252     audio_client->lpVtbl->GetService(audio_client, &ags_wasapi_iid_audio_render_client_guid, (void **) &audio_render_client);
2253     mm_device = wasapi_devout->mm_device;
2254 
2255     hr = audio_client->lpVtbl->Stop(audio_client);
2256 
2257     if(FAILED(hr)){
2258       g_message("failed to stop WASAPI");
2259     }
2260 
2261     audio_client->lpVtbl->Reset(audio_client);
2262 
2263     if(audio_render_client != NULL){
2264       audio_render_client->lpVtbl->Release(audio_render_client);
2265     }
2266 
2267     audio_client->lpVtbl->Release(audio_client);
2268     mm_device->lpVtbl->Release(mm_device);
2269 
2270     wasapi_devout->audio_client = NULL;
2271     wasapi_devout->mm_device = NULL;
2272 
2273     CoUninitialize();
2274 #endif
2275     application_context = ags_application_context_get_instance();
2276 
2277     /* get main loop */
2278     audio_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
2279 
2280     soundcard_thread = ags_thread_find_type(audio_loop,
2281 					    AGS_TYPE_SOUNDCARD_THREAD);
2282 
2283     soundcard_thread = ags_soundcard_thread_find_soundcard(soundcard_thread,
2284 							   AGS_WASAPI_DEVOUT(soundcard));
2285 
2286     ags_thread_stop(soundcard_thread);
2287 
2288     g_object_unref(soundcard_thread);
2289   }
2290 
2291   g_rec_mutex_unlock(wasapi_devout_mutex);
2292 
2293   if((AGS_WASAPI_DEVOUT_SHUTDOWN & (wasapi_devout->flags)) == 0){
2294     /* update soundcard */
2295     task_launcher = ags_concurrency_provider_get_task_launcher(AGS_CONCURRENCY_PROVIDER(application_context));
2296 
2297     task = NULL;
2298 
2299     /* tic soundcard */
2300     tic_device = ags_tic_device_new((GObject *) wasapi_devout);
2301     task = g_list_append(task,
2302 			 tic_device);
2303 
2304     /* reset - clear buffer */
2305     clear_buffer = ags_clear_buffer_new((GObject *) wasapi_devout);
2306     task = g_list_append(task,
2307 			 clear_buffer);
2308 
2309     /* reset - switch buffer flags */
2310     switch_buffer_flag = ags_switch_buffer_flag_new((GObject *) wasapi_devout);
2311     task = g_list_append(task,
2312 			 switch_buffer_flag);
2313 
2314     /* append tasks */
2315     ags_task_launcher_add_task_all(task_launcher,
2316 				   task);
2317 
2318     /* unref */
2319     g_object_unref(task_launcher);
2320   }
2321 }
2322 
2323 void
ags_wasapi_devout_client_free(AgsSoundcard * soundcard)2324 ags_wasapi_devout_client_free(AgsSoundcard *soundcard)
2325 {
2326   AgsWasapiDevout *wasapi_devout;
2327 
2328   guint i;
2329 
2330   GRecMutex *wasapi_devout_mutex;
2331 
2332   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2333 
2334   /* get wasapi devout mutex */
2335   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2336 
2337   /* lock */
2338   g_rec_mutex_lock(wasapi_devout_mutex);
2339 
2340   if((AGS_WASAPI_DEVOUT_INITIALIZED & (wasapi_devout->flags)) == 0){
2341     g_rec_mutex_unlock(wasapi_devout_mutex);
2342 
2343     return;
2344   }
2345 
2346   wasapi_devout->flags |= (AGS_WASAPI_DEVOUT_SHUTDOWN);
2347 
2348   g_rec_mutex_unlock(wasapi_devout_mutex);
2349 
2350   g_rec_mutex_lock(wasapi_devout_mutex);
2351 
2352   wasapi_devout->note_offset = wasapi_devout->start_note_offset;
2353   wasapi_devout->note_offset_absolute = wasapi_devout->start_note_offset;
2354 
2355   g_rec_mutex_unlock(wasapi_devout_mutex);
2356 }
2357 
2358 void
ags_wasapi_devout_tic(AgsSoundcard * soundcard)2359 ags_wasapi_devout_tic(AgsSoundcard *soundcard)
2360 {
2361   AgsWasapiDevout *wasapi_devout;
2362 
2363   gdouble delay;
2364   gdouble delay_counter;
2365   guint note_offset_absolute;
2366   guint note_offset;
2367   guint loop_left, loop_right;
2368   gboolean do_loop;
2369 
2370   GRecMutex *wasapi_devout_mutex;
2371 
2372   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2373 
2374   /* get wasapi devout mutex */
2375   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2376 
2377   /* determine if attack should be switched */
2378   g_rec_mutex_lock(wasapi_devout_mutex);
2379 
2380   delay = wasapi_devout->delay[wasapi_devout->tic_counter];
2381   delay_counter = wasapi_devout->delay_counter;
2382 
2383   note_offset = wasapi_devout->note_offset;
2384   note_offset_absolute = wasapi_devout->note_offset_absolute;
2385 
2386   loop_left = wasapi_devout->loop_left;
2387   loop_right = wasapi_devout->loop_right;
2388 
2389   do_loop = wasapi_devout->do_loop;
2390 
2391   g_rec_mutex_unlock(wasapi_devout_mutex);
2392 
2393   if(delay_counter + 1.0 >= floor(delay)){
2394     if(do_loop &&
2395        note_offset + 1 == loop_right){
2396       ags_soundcard_set_note_offset(soundcard,
2397 				    loop_left);
2398     }else{
2399       ags_soundcard_set_note_offset(soundcard,
2400 				    note_offset + 1);
2401     }
2402 
2403     ags_soundcard_set_note_offset_absolute(soundcard,
2404 					   note_offset_absolute + 1);
2405 
2406     /* delay */
2407     ags_soundcard_offset_changed(soundcard,
2408 				 note_offset);
2409 
2410     /* reset - delay counter */
2411     g_rec_mutex_lock(wasapi_devout_mutex);
2412 
2413     wasapi_devout->delay_counter = delay_counter + 1.0 - delay;
2414     wasapi_devout->tact_counter += 1.0;
2415 
2416     g_rec_mutex_unlock(wasapi_devout_mutex);
2417   }else{
2418     g_rec_mutex_lock(wasapi_devout_mutex);
2419 
2420     wasapi_devout->delay_counter += 1.0;
2421 
2422     g_rec_mutex_unlock(wasapi_devout_mutex);
2423   }
2424 }
2425 
2426 void
ags_wasapi_devout_offset_changed(AgsSoundcard * soundcard,guint note_offset)2427 ags_wasapi_devout_offset_changed(AgsSoundcard *soundcard,
2428 				 guint note_offset)
2429 {
2430   AgsWasapiDevout *wasapi_devout;
2431 
2432   GRecMutex *wasapi_devout_mutex;
2433 
2434   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2435 
2436   /* get wasapi devout mutex */
2437   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2438 
2439   /* offset changed */
2440   g_rec_mutex_lock(wasapi_devout_mutex);
2441 
2442   wasapi_devout->tic_counter += 1;
2443 
2444   if(wasapi_devout->tic_counter == AGS_SOUNDCARD_DEFAULT_PERIOD){
2445     /* reset - tic counter i.e. modified delay index within period */
2446     wasapi_devout->tic_counter = 0;
2447   }
2448 
2449   g_rec_mutex_unlock(wasapi_devout_mutex);
2450 }
2451 
2452 void
ags_wasapi_devout_set_bpm(AgsSoundcard * soundcard,gdouble bpm)2453 ags_wasapi_devout_set_bpm(AgsSoundcard *soundcard,
2454 			  gdouble bpm)
2455 {
2456   AgsWasapiDevout *wasapi_devout;
2457 
2458   GRecMutex *wasapi_devout_mutex;
2459 
2460   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2461 
2462   /* get wasapi devout mutex */
2463   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2464 
2465   /* set bpm */
2466   g_rec_mutex_lock(wasapi_devout_mutex);
2467 
2468   wasapi_devout->bpm = bpm;
2469 
2470   g_rec_mutex_unlock(wasapi_devout_mutex);
2471 
2472   ags_wasapi_devout_adjust_delay_and_attack(wasapi_devout);
2473 }
2474 
2475 gdouble
ags_wasapi_devout_get_bpm(AgsSoundcard * soundcard)2476 ags_wasapi_devout_get_bpm(AgsSoundcard *soundcard)
2477 {
2478   AgsWasapiDevout *wasapi_devout;
2479 
2480   gdouble bpm;
2481 
2482   GRecMutex *wasapi_devout_mutex;
2483 
2484   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2485 
2486   /* get wasapi devout mutex */
2487   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2488 
2489   /* get bpm */
2490   g_rec_mutex_lock(wasapi_devout_mutex);
2491 
2492   bpm = wasapi_devout->bpm;
2493 
2494   g_rec_mutex_unlock(wasapi_devout_mutex);
2495 
2496   return(bpm);
2497 }
2498 
2499 void
ags_wasapi_devout_set_delay_factor(AgsSoundcard * soundcard,gdouble delay_factor)2500 ags_wasapi_devout_set_delay_factor(AgsSoundcard *soundcard,
2501 				   gdouble delay_factor)
2502 {
2503   AgsWasapiDevout *wasapi_devout;
2504 
2505   GRecMutex *wasapi_devout_mutex;
2506 
2507   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2508 
2509   /* get wasapi devout mutex */
2510   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2511 
2512   /* set delay factor */
2513   g_rec_mutex_lock(wasapi_devout_mutex);
2514 
2515   wasapi_devout->delay_factor = delay_factor;
2516 
2517   g_rec_mutex_unlock(wasapi_devout_mutex);
2518 
2519   ags_wasapi_devout_adjust_delay_and_attack(wasapi_devout);
2520 }
2521 
2522 gdouble
ags_wasapi_devout_get_delay_factor(AgsSoundcard * soundcard)2523 ags_wasapi_devout_get_delay_factor(AgsSoundcard *soundcard)
2524 {
2525   AgsWasapiDevout *wasapi_devout;
2526 
2527   gdouble delay_factor;
2528 
2529   GRecMutex *wasapi_devout_mutex;
2530 
2531   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2532 
2533   /* get wasapi devout mutex */
2534   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2535 
2536   /* get delay factor */
2537   g_rec_mutex_lock(wasapi_devout_mutex);
2538 
2539   delay_factor = wasapi_devout->delay_factor;
2540 
2541   g_rec_mutex_unlock(wasapi_devout_mutex);
2542 
2543   return(delay_factor);
2544 }
2545 
2546 gdouble
ags_wasapi_devout_get_delay(AgsSoundcard * soundcard)2547 ags_wasapi_devout_get_delay(AgsSoundcard *soundcard)
2548 {
2549   AgsWasapiDevout *wasapi_devout;
2550 
2551   guint delay_index;
2552   gdouble delay;
2553 
2554   GRecMutex *wasapi_devout_mutex;
2555 
2556   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2557 
2558   /* get wasapi devout mutex */
2559   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2560 
2561   /* get delay */
2562   g_rec_mutex_lock(wasapi_devout_mutex);
2563 
2564   delay_index = wasapi_devout->tic_counter;
2565 
2566   delay = wasapi_devout->delay[delay_index];
2567 
2568   g_rec_mutex_unlock(wasapi_devout_mutex);
2569 
2570   return(delay);
2571 }
2572 
2573 gdouble
ags_wasapi_devout_get_absolute_delay(AgsSoundcard * soundcard)2574 ags_wasapi_devout_get_absolute_delay(AgsSoundcard *soundcard)
2575 {
2576   AgsWasapiDevout *wasapi_devout;
2577 
2578   gdouble absolute_delay;
2579 
2580   GRecMutex *wasapi_devout_mutex;
2581 
2582   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2583 
2584   /* get wasapi devout mutex */
2585   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2586 
2587   /* get absolute delay */
2588   g_rec_mutex_lock(wasapi_devout_mutex);
2589 
2590   absolute_delay = (60.0 * (((gdouble) wasapi_devout->samplerate / (gdouble) wasapi_devout->buffer_size) / (gdouble) wasapi_devout->bpm) * ((1.0 / 16.0) * (1.0 / (gdouble) wasapi_devout->delay_factor)));
2591 
2592   g_rec_mutex_unlock(wasapi_devout_mutex);
2593 
2594   return(absolute_delay);
2595 }
2596 
2597 guint
ags_wasapi_devout_get_attack(AgsSoundcard * soundcard)2598 ags_wasapi_devout_get_attack(AgsSoundcard *soundcard)
2599 {
2600   AgsWasapiDevout *wasapi_devout;
2601 
2602   guint attack_index;
2603   guint attack;
2604 
2605   GRecMutex *wasapi_devout_mutex;
2606 
2607   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2608 
2609   /* get wasapi devout mutex */
2610   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2611 
2612   /* get attack */
2613   g_rec_mutex_lock(wasapi_devout_mutex);
2614 
2615   attack_index = wasapi_devout->tic_counter;
2616 
2617   attack = wasapi_devout->attack[attack_index];
2618 
2619   g_rec_mutex_unlock(wasapi_devout_mutex);
2620 
2621   return(attack);
2622 }
2623 
2624 void*
ags_wasapi_devout_get_buffer(AgsSoundcard * soundcard)2625 ags_wasapi_devout_get_buffer(AgsSoundcard *soundcard)
2626 {
2627   AgsWasapiDevout *wasapi_devout;
2628 
2629   void *buffer;
2630 
2631   GRecMutex *wasapi_devout_mutex;
2632 
2633   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2634 
2635   /* get wasapi devout mutex */
2636   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2637 
2638   if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER0)){
2639     buffer = wasapi_devout->buffer[0];
2640   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER1)){
2641     buffer = wasapi_devout->buffer[1];
2642   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER2)){
2643     buffer = wasapi_devout->buffer[2];
2644   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER3)){
2645     buffer = wasapi_devout->buffer[3];
2646   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER4)){
2647     buffer = wasapi_devout->buffer[4];
2648   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER5)){
2649     buffer = wasapi_devout->buffer[5];
2650   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER6)){
2651     buffer = wasapi_devout->buffer[6];
2652   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER7)){
2653     buffer = wasapi_devout->buffer[7];
2654   }else{
2655     buffer = NULL;
2656   }
2657 
2658   return(buffer);
2659 }
2660 
2661 void*
ags_wasapi_devout_get_next_buffer(AgsSoundcard * soundcard)2662 ags_wasapi_devout_get_next_buffer(AgsSoundcard *soundcard)
2663 {
2664   AgsWasapiDevout *wasapi_devout;
2665 
2666   void *buffer;
2667 
2668   GRecMutex *wasapi_devout_mutex;
2669 
2670   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2671 
2672   /* get wasapi devout mutex */
2673   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2674 
2675   g_rec_mutex_lock(wasapi_devout_mutex);
2676 
2677   if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER0)){
2678     buffer = wasapi_devout->buffer[1];
2679   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER1)){
2680     buffer = wasapi_devout->buffer[2];
2681   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER2)){
2682     buffer = wasapi_devout->buffer[3];
2683   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER3)){
2684     buffer = wasapi_devout->buffer[4];
2685   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER4)){
2686     buffer = wasapi_devout->buffer[5];
2687   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER5)){
2688     buffer = wasapi_devout->buffer[6];
2689   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER6)){
2690     buffer = wasapi_devout->buffer[7];
2691   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER7)){
2692     buffer = wasapi_devout->buffer[0];
2693   }else{
2694     buffer = NULL;
2695   }
2696 
2697   g_rec_mutex_unlock(wasapi_devout_mutex);
2698 
2699   return(buffer);
2700 }
2701 
2702 void*
ags_wasapi_devout_get_prev_buffer(AgsSoundcard * soundcard)2703 ags_wasapi_devout_get_prev_buffer(AgsSoundcard *soundcard)
2704 {
2705   AgsWasapiDevout *wasapi_devout;
2706 
2707   void *buffer;
2708 
2709   GRecMutex *wasapi_devout_mutex;
2710 
2711   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2712 
2713   /* get wasapi devout mutex */
2714   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2715 
2716   g_rec_mutex_lock(wasapi_devout_mutex);
2717 
2718   if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER0)){
2719     buffer = wasapi_devout->buffer[7];
2720   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER1)){
2721     buffer = wasapi_devout->buffer[0];
2722   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER2)){
2723     buffer = wasapi_devout->buffer[1];
2724   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER3)){
2725     buffer = wasapi_devout->buffer[2];
2726   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER4)){
2727     buffer = wasapi_devout->buffer[3];
2728   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER5)){
2729     buffer = wasapi_devout->buffer[4];
2730   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER6)){
2731     buffer = wasapi_devout->buffer[5];
2732   }else if(ags_wasapi_devout_test_flags(wasapi_devout, AGS_WASAPI_DEVOUT_BUFFER7)){
2733     buffer = wasapi_devout->buffer[6];
2734   }else{
2735     buffer = NULL;
2736   }
2737 
2738   g_rec_mutex_unlock(wasapi_devout_mutex);
2739 
2740   return(buffer);
2741 }
2742 
2743 void
ags_wasapi_devout_lock_buffer(AgsSoundcard * soundcard,void * buffer)2744 ags_wasapi_devout_lock_buffer(AgsSoundcard *soundcard,
2745 			      void *buffer)
2746 {
2747   AgsWasapiDevout *wasapi_devout;
2748 
2749   GRecMutex *buffer_mutex;
2750 
2751   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2752 
2753   buffer_mutex = NULL;
2754 
2755   if(wasapi_devout->buffer != NULL){
2756     if(buffer == wasapi_devout->buffer[0]){
2757       buffer_mutex = wasapi_devout->buffer_mutex[0];
2758     }else if(buffer == wasapi_devout->buffer[1]){
2759       buffer_mutex = wasapi_devout->buffer_mutex[1];
2760     }else if(buffer == wasapi_devout->buffer[2]){
2761       buffer_mutex = wasapi_devout->buffer_mutex[2];
2762     }else if(buffer == wasapi_devout->buffer[3]){
2763       buffer_mutex = wasapi_devout->buffer_mutex[3];
2764     }else if(buffer == wasapi_devout->buffer[4]){
2765       buffer_mutex = wasapi_devout->buffer_mutex[4];
2766     }else if(buffer == wasapi_devout->buffer[5]){
2767       buffer_mutex = wasapi_devout->buffer_mutex[5];
2768     }else if(buffer == wasapi_devout->buffer[6]){
2769       buffer_mutex = wasapi_devout->buffer_mutex[6];
2770     }else if(buffer == wasapi_devout->buffer[7]){
2771       buffer_mutex = wasapi_devout->buffer_mutex[7];
2772     }
2773   }
2774 
2775   if(buffer_mutex != NULL){
2776     g_rec_mutex_lock(buffer_mutex);
2777   }
2778 }
2779 
2780 void
ags_wasapi_devout_unlock_buffer(AgsSoundcard * soundcard,void * buffer)2781 ags_wasapi_devout_unlock_buffer(AgsSoundcard *soundcard,
2782 				void *buffer)
2783 {
2784   AgsWasapiDevout *wasapi_devout;
2785 
2786   GRecMutex *buffer_mutex;
2787 
2788   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2789 
2790   buffer_mutex = NULL;
2791 
2792   if(wasapi_devout->buffer != NULL){
2793     if(buffer == wasapi_devout->buffer[0]){
2794       buffer_mutex = wasapi_devout->buffer_mutex[0];
2795     }else if(buffer == wasapi_devout->buffer[1]){
2796       buffer_mutex = wasapi_devout->buffer_mutex[1];
2797     }else if(buffer == wasapi_devout->buffer[2]){
2798       buffer_mutex = wasapi_devout->buffer_mutex[2];
2799     }else if(buffer == wasapi_devout->buffer[3]){
2800       buffer_mutex = wasapi_devout->buffer_mutex[3];
2801     }else if(buffer == wasapi_devout->buffer[4]){
2802       buffer_mutex = wasapi_devout->buffer_mutex[4];
2803     }else if(buffer == wasapi_devout->buffer[5]){
2804       buffer_mutex = wasapi_devout->buffer_mutex[5];
2805     }else if(buffer == wasapi_devout->buffer[6]){
2806       buffer_mutex = wasapi_devout->buffer_mutex[6];
2807     }else if(buffer == wasapi_devout->buffer[7]){
2808       buffer_mutex = wasapi_devout->buffer_mutex[7];
2809     }
2810   }
2811 
2812   if(buffer_mutex != NULL){
2813     g_rec_mutex_unlock(buffer_mutex);
2814   }
2815 }
2816 
2817 guint
ags_wasapi_devout_get_delay_counter(AgsSoundcard * soundcard)2818 ags_wasapi_devout_get_delay_counter(AgsSoundcard *soundcard)
2819 {
2820   AgsWasapiDevout *wasapi_devout;
2821 
2822   guint delay_counter;
2823 
2824   GRecMutex *wasapi_devout_mutex;
2825 
2826   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2827 
2828   /* get wasapi devout mutex */
2829   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2830 
2831   /* delay counter */
2832   g_rec_mutex_lock(wasapi_devout_mutex);
2833 
2834   delay_counter = wasapi_devout->delay_counter;
2835 
2836   g_rec_mutex_unlock(wasapi_devout_mutex);
2837 
2838   return(delay_counter);
2839 }
2840 
2841 void
ags_wasapi_devout_set_start_note_offset(AgsSoundcard * soundcard,guint start_note_offset)2842 ags_wasapi_devout_set_start_note_offset(AgsSoundcard *soundcard,
2843 					guint start_note_offset)
2844 {
2845   AgsWasapiDevout *wasapi_devout;
2846 
2847   GRecMutex *wasapi_devout_mutex;
2848 
2849   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2850 
2851   /* get wasapi devout mutex */
2852   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2853 
2854   /* set note offset */
2855   g_rec_mutex_lock(wasapi_devout_mutex);
2856 
2857   wasapi_devout->start_note_offset = start_note_offset;
2858 
2859   g_rec_mutex_unlock(wasapi_devout_mutex);
2860 }
2861 
2862 guint
ags_wasapi_devout_get_start_note_offset(AgsSoundcard * soundcard)2863 ags_wasapi_devout_get_start_note_offset(AgsSoundcard *soundcard)
2864 {
2865   AgsWasapiDevout *wasapi_devout;
2866 
2867   guint start_note_offset;
2868 
2869   GRecMutex *wasapi_devout_mutex;
2870 
2871   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2872 
2873   /* get wasapi devout mutex */
2874   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2875 
2876   /* set note offset */
2877   g_rec_mutex_lock(wasapi_devout_mutex);
2878 
2879   start_note_offset = wasapi_devout->start_note_offset;
2880 
2881   g_rec_mutex_unlock(wasapi_devout_mutex);
2882 
2883   return(start_note_offset);
2884 }
2885 
2886 void
ags_wasapi_devout_set_note_offset(AgsSoundcard * soundcard,guint note_offset)2887 ags_wasapi_devout_set_note_offset(AgsSoundcard *soundcard,
2888 				  guint note_offset)
2889 {
2890   AgsWasapiDevout *wasapi_devout;
2891 
2892   GRecMutex *wasapi_devout_mutex;
2893 
2894   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2895 
2896   /* get wasapi devout mutex */
2897   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2898 
2899   /* set note offset */
2900   g_rec_mutex_lock(wasapi_devout_mutex);
2901 
2902   wasapi_devout->note_offset = note_offset;
2903 
2904   g_rec_mutex_unlock(wasapi_devout_mutex);
2905 }
2906 
2907 guint
ags_wasapi_devout_get_note_offset(AgsSoundcard * soundcard)2908 ags_wasapi_devout_get_note_offset(AgsSoundcard *soundcard)
2909 {
2910   AgsWasapiDevout *wasapi_devout;
2911 
2912   guint note_offset;
2913 
2914   GRecMutex *wasapi_devout_mutex;
2915 
2916   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2917 
2918   /* get wasapi devout mutex */
2919   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2920 
2921   /* set note offset */
2922   g_rec_mutex_lock(wasapi_devout_mutex);
2923 
2924   note_offset = wasapi_devout->note_offset;
2925 
2926   g_rec_mutex_unlock(wasapi_devout_mutex);
2927 
2928   return(note_offset);
2929 }
2930 
2931 void
ags_wasapi_devout_set_note_offset_absolute(AgsSoundcard * soundcard,guint note_offset_absolute)2932 ags_wasapi_devout_set_note_offset_absolute(AgsSoundcard *soundcard,
2933 					   guint note_offset_absolute)
2934 {
2935   AgsWasapiDevout *wasapi_devout;
2936 
2937   GRecMutex *wasapi_devout_mutex;
2938 
2939   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2940 
2941   /* get wasapi devout mutex */
2942   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2943 
2944   /* set note offset */
2945   g_rec_mutex_lock(wasapi_devout_mutex);
2946 
2947   wasapi_devout->note_offset_absolute = note_offset_absolute;
2948 
2949   g_rec_mutex_unlock(wasapi_devout_mutex);
2950 }
2951 
2952 guint
ags_wasapi_devout_get_note_offset_absolute(AgsSoundcard * soundcard)2953 ags_wasapi_devout_get_note_offset_absolute(AgsSoundcard *soundcard)
2954 {
2955   AgsWasapiDevout *wasapi_devout;
2956 
2957   guint note_offset_absolute;
2958 
2959   GRecMutex *wasapi_devout_mutex;
2960 
2961   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2962 
2963   /* get wasapi devout mutex */
2964   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2965 
2966   /* set note offset */
2967   g_rec_mutex_lock(wasapi_devout_mutex);
2968 
2969   note_offset_absolute = wasapi_devout->note_offset_absolute;
2970 
2971   g_rec_mutex_unlock(wasapi_devout_mutex);
2972 
2973   return(note_offset_absolute);
2974 }
2975 
2976 void
ags_wasapi_devout_set_loop(AgsSoundcard * soundcard,guint loop_left,guint loop_right,gboolean do_loop)2977 ags_wasapi_devout_set_loop(AgsSoundcard *soundcard,
2978 			   guint loop_left, guint loop_right,
2979 			   gboolean do_loop)
2980 {
2981   AgsWasapiDevout *wasapi_devout;
2982 
2983   GRecMutex *wasapi_devout_mutex;
2984 
2985   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
2986 
2987   /* get wasapi devout mutex */
2988   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
2989 
2990   /* set loop */
2991   g_rec_mutex_lock(wasapi_devout_mutex);
2992 
2993   wasapi_devout->loop_left = loop_left;
2994   wasapi_devout->loop_right = loop_right;
2995   wasapi_devout->do_loop = do_loop;
2996 
2997   if(do_loop){
2998     wasapi_devout->loop_offset = wasapi_devout->note_offset;
2999   }
3000 
3001   g_rec_mutex_unlock(wasapi_devout_mutex);
3002 }
3003 
3004 void
ags_wasapi_devout_get_loop(AgsSoundcard * soundcard,guint * loop_left,guint * loop_right,gboolean * do_loop)3005 ags_wasapi_devout_get_loop(AgsSoundcard *soundcard,
3006 			   guint *loop_left, guint *loop_right,
3007 			   gboolean *do_loop)
3008 {
3009   AgsWasapiDevout *wasapi_devout;
3010 
3011   GRecMutex *wasapi_devout_mutex;
3012 
3013   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
3014 
3015   /* get wasapi devout mutex */
3016   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
3017 
3018   /* get loop */
3019   g_rec_mutex_lock(wasapi_devout_mutex);
3020 
3021   if(loop_left != NULL){
3022     *loop_left = wasapi_devout->loop_left;
3023   }
3024 
3025   if(loop_right != NULL){
3026     *loop_right = wasapi_devout->loop_right;
3027   }
3028 
3029   if(do_loop != NULL){
3030     *do_loop = wasapi_devout->do_loop;
3031   }
3032 
3033   g_rec_mutex_unlock(wasapi_devout_mutex);
3034 }
3035 
3036 guint
ags_wasapi_devout_get_loop_offset(AgsSoundcard * soundcard)3037 ags_wasapi_devout_get_loop_offset(AgsSoundcard *soundcard)
3038 {
3039   AgsWasapiDevout *wasapi_devout;
3040 
3041   guint loop_offset;
3042 
3043   GRecMutex *wasapi_devout_mutex;
3044 
3045   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
3046 
3047   /* get wasapi devout mutex */
3048   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
3049 
3050   /* get loop offset */
3051   g_rec_mutex_lock(wasapi_devout_mutex);
3052 
3053   loop_offset = wasapi_devout->loop_offset;
3054 
3055   g_rec_mutex_unlock(wasapi_devout_mutex);
3056 
3057   return(loop_offset);
3058 }
3059 
3060 guint
ags_wasapi_devout_get_sub_block_count(AgsSoundcard * soundcard)3061 ags_wasapi_devout_get_sub_block_count(AgsSoundcard *soundcard)
3062 {
3063   AgsWasapiDevout *wasapi_devout;
3064 
3065   guint sub_block_count;
3066 
3067   GRecMutex *wasapi_devout_mutex;
3068 
3069   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
3070 
3071   /* get wasapi devout mutex */
3072   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
3073 
3074   /* get loop offset */
3075   g_rec_mutex_lock(wasapi_devout_mutex);
3076 
3077   sub_block_count = wasapi_devout->sub_block_count;
3078 
3079   g_rec_mutex_unlock(wasapi_devout_mutex);
3080 
3081   return(sub_block_count);
3082 }
3083 
3084 gboolean
ags_wasapi_devout_trylock_sub_block(AgsSoundcard * soundcard,void * buffer,guint sub_block)3085 ags_wasapi_devout_trylock_sub_block(AgsSoundcard *soundcard,
3086 				    void *buffer, guint sub_block)
3087 {
3088   AgsWasapiDevout *wasapi_devout;
3089 
3090   guint pcm_channels;
3091   guint sub_block_count;
3092   gboolean success;
3093 
3094   GRecMutex *wasapi_devout_mutex;
3095   GRecMutex *sub_block_mutex;
3096 
3097   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
3098 
3099   /* get wasapi devout mutex */
3100   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
3101 
3102   /* get loop offset */
3103   g_rec_mutex_lock(wasapi_devout_mutex);
3104 
3105   pcm_channels = wasapi_devout->pcm_channels;
3106   sub_block_count = wasapi_devout->sub_block_count;
3107 
3108   g_rec_mutex_unlock(wasapi_devout_mutex);
3109 
3110   sub_block_mutex = NULL;
3111 
3112   success = FALSE;
3113 
3114   if(wasapi_devout->buffer != NULL){
3115     if(buffer == wasapi_devout->buffer[0]){
3116       sub_block_mutex = wasapi_devout->sub_block_mutex[sub_block];
3117     }else if(buffer == wasapi_devout->buffer[1]){
3118       sub_block_mutex = wasapi_devout->sub_block_mutex[pcm_channels * sub_block_count + sub_block];
3119     }else if(buffer == wasapi_devout->buffer[2]){
3120       sub_block_mutex = wasapi_devout->sub_block_mutex[2 * pcm_channels * sub_block_count + sub_block];
3121     }else if(buffer == wasapi_devout->buffer[3]){
3122       sub_block_mutex = wasapi_devout->sub_block_mutex[3 * pcm_channels * sub_block_count + sub_block];
3123     }else if(buffer == wasapi_devout->buffer[4]){
3124       sub_block_mutex = wasapi_devout->sub_block_mutex[4 * pcm_channels * sub_block_count + sub_block];
3125     }else if(buffer == wasapi_devout->buffer[5]){
3126       sub_block_mutex = wasapi_devout->sub_block_mutex[5 * pcm_channels * sub_block_count + sub_block];
3127     }else if(buffer == wasapi_devout->buffer[6]){
3128       sub_block_mutex = wasapi_devout->sub_block_mutex[6 * pcm_channels * sub_block_count + sub_block];
3129     }else if(buffer == wasapi_devout->buffer[7]){
3130       sub_block_mutex = wasapi_devout->sub_block_mutex[7 * pcm_channels * sub_block_count + sub_block];
3131     }
3132   }
3133 
3134   if(sub_block_mutex != NULL){
3135     if(g_rec_mutex_trylock(sub_block_mutex)){
3136       success = TRUE;
3137     }
3138   }
3139 
3140   return(success);
3141 }
3142 
3143 void
ags_wasapi_devout_unlock_sub_block(AgsSoundcard * soundcard,void * buffer,guint sub_block)3144 ags_wasapi_devout_unlock_sub_block(AgsSoundcard *soundcard,
3145 				   void *buffer, guint sub_block)
3146 {
3147   AgsWasapiDevout *wasapi_devout;
3148 
3149   guint pcm_channels;
3150   guint sub_block_count;
3151 
3152   GRecMutex *wasapi_devout_mutex;
3153   GRecMutex *sub_block_mutex;
3154 
3155   wasapi_devout = AGS_WASAPI_DEVOUT(soundcard);
3156 
3157   /* get wasapi devout mutex */
3158   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
3159 
3160   /* get loop offset */
3161   g_rec_mutex_lock(wasapi_devout_mutex);
3162 
3163   pcm_channels = wasapi_devout->pcm_channels;
3164   sub_block_count = wasapi_devout->sub_block_count;
3165 
3166   g_rec_mutex_unlock(wasapi_devout_mutex);
3167 
3168   sub_block_mutex = NULL;
3169 
3170   if(wasapi_devout->buffer != NULL){
3171     if(buffer == wasapi_devout->buffer[0]){
3172       sub_block_mutex = wasapi_devout->sub_block_mutex[sub_block];
3173     }else if(buffer == wasapi_devout->buffer[1]){
3174       sub_block_mutex = wasapi_devout->sub_block_mutex[pcm_channels * sub_block_count + sub_block];
3175     }else if(buffer == wasapi_devout->buffer[2]){
3176       sub_block_mutex = wasapi_devout->sub_block_mutex[2 * pcm_channels * sub_block_count + sub_block];
3177     }else if(buffer == wasapi_devout->buffer[3]){
3178       sub_block_mutex = wasapi_devout->sub_block_mutex[3 * pcm_channels * sub_block_count + sub_block];
3179     }else if(buffer == wasapi_devout->buffer[4]){
3180       sub_block_mutex = wasapi_devout->sub_block_mutex[4 * pcm_channels * sub_block_count + sub_block];
3181     }else if(buffer == wasapi_devout->buffer[5]){
3182       sub_block_mutex = wasapi_devout->sub_block_mutex[5 * pcm_channels * sub_block_count + sub_block];
3183     }else if(buffer == wasapi_devout->buffer[6]){
3184       sub_block_mutex = wasapi_devout->sub_block_mutex[6 * pcm_channels * sub_block_count + sub_block];
3185     }else if(buffer == wasapi_devout->buffer[7]){
3186       sub_block_mutex = wasapi_devout->sub_block_mutex[7 * pcm_channels * sub_block_count + sub_block];
3187     }
3188   }
3189 
3190   if(sub_block_mutex != NULL){
3191     g_rec_mutex_unlock(sub_block_mutex);
3192   }
3193 }
3194 
3195 /**
3196  * ags_wasapi_devout_switch_buffer_flag:
3197  * @wasapi_devout: an #AgsWasapiDevout
3198  *
3199  * The buffer flag indicates the currently played buffer.
3200  *
3201  * Since: 3.0.0
3202  */
3203 void
ags_wasapi_devout_switch_buffer_flag(AgsWasapiDevout * wasapi_devout)3204 ags_wasapi_devout_switch_buffer_flag(AgsWasapiDevout *wasapi_devout)
3205 {
3206   GRecMutex *wasapi_devout_mutex;
3207 
3208   if(!AGS_IS_WASAPI_DEVOUT(wasapi_devout)){
3209     return;
3210   }
3211 
3212   /* get wasapi devout mutex */
3213   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
3214 
3215   /* switch buffer flag */
3216   g_rec_mutex_lock(wasapi_devout_mutex);
3217 
3218   if((AGS_WASAPI_DEVOUT_BUFFER0 & (wasapi_devout->flags)) != 0){
3219     wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_BUFFER0);
3220     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_BUFFER1;
3221   }else if((AGS_WASAPI_DEVOUT_BUFFER1 & (wasapi_devout->flags)) != 0){
3222     wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_BUFFER1);
3223     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_BUFFER2;
3224   }else if((AGS_WASAPI_DEVOUT_BUFFER2 & (wasapi_devout->flags)) != 0){
3225     wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_BUFFER2);
3226     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_BUFFER3;
3227   }else if((AGS_WASAPI_DEVOUT_BUFFER3 & (wasapi_devout->flags)) != 0){
3228     wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_BUFFER3);
3229     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_BUFFER4;
3230   }else if((AGS_WASAPI_DEVOUT_BUFFER4 & (wasapi_devout->flags)) != 0){
3231     wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_BUFFER4);
3232     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_BUFFER5;
3233   }else if((AGS_WASAPI_DEVOUT_BUFFER5 & (wasapi_devout->flags)) != 0){
3234     wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_BUFFER5);
3235     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_BUFFER6;
3236   }else if((AGS_WASAPI_DEVOUT_BUFFER6 & (wasapi_devout->flags)) != 0){
3237     wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_BUFFER6);
3238     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_BUFFER7;
3239   }else if((AGS_WASAPI_DEVOUT_BUFFER7 & (wasapi_devout->flags)) != 0){
3240     wasapi_devout->flags &= (~AGS_WASAPI_DEVOUT_BUFFER7);
3241     wasapi_devout->flags |= AGS_WASAPI_DEVOUT_BUFFER0;
3242   }
3243 
3244   g_rec_mutex_unlock(wasapi_devout_mutex);
3245 }
3246 
3247 /**
3248  * ags_wasapi_devout_adjust_delay_and_attack:
3249  * @wasapi_devout: the #AgsWasapiDevout
3250  *
3251  * Calculate delay and attack and reset it.
3252  *
3253  * Since: 3.0.0
3254  */
3255 void
ags_wasapi_devout_adjust_delay_and_attack(AgsWasapiDevout * wasapi_devout)3256 ags_wasapi_devout_adjust_delay_and_attack(AgsWasapiDevout *wasapi_devout)
3257 {
3258   if(!AGS_IS_WASAPI_DEVOUT(wasapi_devout)){
3259     return;
3260   }
3261 
3262   ags_soundcard_util_adjust_delay_and_attack(wasapi_devout);
3263 }
3264 
3265 /**
3266  * ags_wasapi_devout_realloc_buffer:
3267  * @wasapi_devout: the #AgsWasapiDevout
3268  *
3269  * Reallocate the internal audio buffer.
3270  *
3271  * Since: 3.0.0
3272  */
3273 void
ags_wasapi_devout_realloc_buffer(AgsWasapiDevout * wasapi_devout)3274 ags_wasapi_devout_realloc_buffer(AgsWasapiDevout *wasapi_devout)
3275 {
3276   guint pcm_channels;
3277   guint buffer_size;
3278   guint format;
3279   guint word_size;
3280 
3281   GRecMutex *wasapi_devout_mutex;
3282 
3283   if(!AGS_IS_WASAPI_DEVOUT(wasapi_devout)){
3284     return;
3285   }
3286 
3287   /* get wasapi devout mutex */
3288   wasapi_devout_mutex = AGS_WASAPI_DEVOUT_GET_OBJ_MUTEX(wasapi_devout);
3289 
3290   /* get word size */
3291   g_rec_mutex_lock(wasapi_devout_mutex);
3292 
3293   pcm_channels = wasapi_devout->pcm_channels;
3294   buffer_size = wasapi_devout->buffer_size;
3295 
3296   format = wasapi_devout->format;
3297 
3298   g_rec_mutex_unlock(wasapi_devout_mutex);
3299 
3300   switch(format){
3301   case AGS_SOUNDCARD_SIGNED_16_BIT:
3302   {
3303     word_size = sizeof(gint16);
3304   }
3305   break;
3306   case AGS_SOUNDCARD_SIGNED_24_BIT:
3307   {
3308     word_size = sizeof(gint32);
3309   }
3310   break;
3311   case AGS_SOUNDCARD_SIGNED_32_BIT:
3312   {
3313     word_size = sizeof(gint32);
3314   }
3315   break;
3316   default:
3317     g_warning("ags_wasapi_devout_realloc_buffer(): unsupported word size");
3318     return;
3319   }
3320 
3321   /* AGS_WASAPI_DEVOUT_BUFFER_0 */
3322   if(wasapi_devout->buffer[0] != NULL){
3323     free(wasapi_devout->buffer[0]);
3324   }
3325 
3326   wasapi_devout->buffer[0] = (void *) malloc(pcm_channels * buffer_size * word_size);
3327 
3328   /* AGS_WASAPI_DEVOUT_BUFFER_1 */
3329   if(wasapi_devout->buffer[1] != NULL){
3330     free(wasapi_devout->buffer[1]);
3331   }
3332 
3333   wasapi_devout->buffer[1] = (void *) malloc(pcm_channels * buffer_size * word_size);
3334 
3335   /* AGS_WASAPI_DEVOUT_BUFFER_2 */
3336   if(wasapi_devout->buffer[2] != NULL){
3337     free(wasapi_devout->buffer[2]);
3338   }
3339 
3340   wasapi_devout->buffer[2] = (void *) malloc(pcm_channels * buffer_size * word_size);
3341 
3342   /* AGS_WASAPI_DEVOUT_BUFFER_3 */
3343   if(wasapi_devout->buffer[3] != NULL){
3344     free(wasapi_devout->buffer[3]);
3345   }
3346 
3347   wasapi_devout->buffer[3] = (void *) malloc(pcm_channels * buffer_size * word_size);
3348 
3349   /* AGS_WASAPI_DEVOUT_BUFFER_4 */
3350   if(wasapi_devout->buffer[4] != NULL){
3351     free(wasapi_devout->buffer[4]);
3352   }
3353 
3354   wasapi_devout->buffer[4] = (void *) malloc(pcm_channels * buffer_size * word_size);
3355 
3356   /* AGS_WASAPI_DEVOUT_BUFFER_5 */
3357   if(wasapi_devout->buffer[5] != NULL){
3358     free(wasapi_devout->buffer[5]);
3359   }
3360 
3361   wasapi_devout->buffer[5] = (void *) malloc(pcm_channels * buffer_size * word_size);
3362 
3363   /* AGS_WASAPI_DEVOUT_BUFFER_6 */
3364   if(wasapi_devout->buffer[6] != NULL){
3365     free(wasapi_devout->buffer[6]);
3366   }
3367 
3368   wasapi_devout->buffer[6] = (void *) malloc(pcm_channels * buffer_size * word_size);
3369 
3370   /* AGS_WASAPI_DEVOUT_BUFFER_7 */
3371   if(wasapi_devout->buffer[7] != NULL){
3372     free(wasapi_devout->buffer[7]);
3373   }
3374 
3375   wasapi_devout->buffer[7] = (void *) malloc(pcm_channels * buffer_size * word_size);
3376 }
3377 
3378 /**
3379  * ags_wasapi_devout_new:
3380  *
3381  * Creates a new instance of #AgsWasapiDevout.
3382  *
3383  * Returns: a new #AgsWasapiDevout
3384  *
3385  * Since: 3.0.0
3386  */
3387 AgsWasapiDevout*
ags_wasapi_devout_new()3388 ags_wasapi_devout_new()
3389 {
3390   AgsWasapiDevout *wasapi_devout;
3391 
3392   wasapi_devout = (AgsWasapiDevout *) g_object_new(AGS_TYPE_WASAPI_DEVOUT,
3393 						   NULL);
3394 
3395   return(wasapi_devout);
3396 }
3397