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