1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2019 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/core-audio/ags_core_audio_port.h>
21
22 #include <ags/audio/ags_sound_provider.h>
23 #include <ags/audio/ags_audio_signal.h>
24 #include <ags/audio/ags_audio_buffer_util.h>
25
26 #include <ags/audio/thread/ags_audio_loop.h>
27
28 #include <ags/audio/core-audio/ags_core_audio_server.h>
29 #include <ags/audio/core-audio/ags_core_audio_client.h>
30 #include <ags/audio/core-audio/ags_core_audio_devout.h>
31 #include <ags/audio/core-audio/ags_core_audio_devin.h>
32 #include <ags/audio/core-audio/ags_core_audio_midiin.h>
33
34 #include <ags/config.h>
35 #include <ags/i18n.h>
36
37 #ifdef AGS_WITH_CORE_AUDIO
38 #include <CoreFoundation/CoreFoundation.h>
39 #include <AudioToolbox/AudioToolbox.h>
40 #endif
41
42 #include <time.h>
43
44 void ags_core_audio_port_class_init(AgsCoreAudioPortClass *core_audio_port);
45 void ags_core_audio_port_connectable_interface_init(AgsConnectableInterface *connectable);
46 void ags_core_audio_port_init(AgsCoreAudioPort *core_audio_port);
47 void ags_core_audio_port_set_property(GObject *gobject,
48 guint prop_id,
49 const GValue *value,
50 GParamSpec *param_spec);
51 void ags_core_audio_port_get_property(GObject *gobject,
52 guint prop_id,
53 GValue *value,
54 GParamSpec *param_spec);
55 void ags_core_audio_port_dispose(GObject *gobject);
56 void ags_core_audio_port_finalize(GObject *gobject);
57
58 AgsUUID* ags_core_audio_port_get_uuid(AgsConnectable *connectable);
59 gboolean ags_core_audio_port_has_resource(AgsConnectable *connectable);
60 gboolean ags_core_audio_port_is_ready(AgsConnectable *connectable);
61 void ags_core_audio_port_add_to_registry(AgsConnectable *connectable);
62 void ags_core_audio_port_remove_from_registry(AgsConnectable *connectable);
63 xmlNode* ags_core_audio_port_list_resource(AgsConnectable *connectable);
64 xmlNode* ags_core_audio_port_xml_compose(AgsConnectable *connectable);
65 void ags_core_audio_port_xml_parse(AgsConnectable *connectable,
66 xmlNode *node);
67 gboolean ags_core_audio_port_is_connected(AgsConnectable *connectable);
68 void ags_core_audio_port_connect(AgsConnectable *connectable);
69 void ags_core_audio_port_disconnect(AgsConnectable *connectable);
70
71 #ifdef AGS_WITH_CORE_AUDIO
72 void* ags_core_audio_port_cached_output_thread(AgsCoreAudioPort *core_audio_port);
73 void* ags_core_audio_port_cached_input_thread(AgsCoreAudioPort *core_audio_port);
74
75 void* ags_core_audio_port_output_thread(AgsCoreAudioPort *core_audio_port);
76 void* ags_core_audio_port_input_thread(AgsCoreAudioPort *core_audio_port);
77
78 void ags_core_audio_port_cached_handle_output_buffer(AgsCoreAudioPort *core_audio_port,
79 AudioQueueRef in_audio_queue, AudioQueueBufferRef in_buffer);
80 void ags_core_audio_port_cached_handle_input_buffer(AgsCoreAudioPort *core_audio_port,
81 AudioQueueRef in_audio_queue, AudioQueueBufferRef in_buffer,
82 const AudioTimeStamp *in_start_time, UInt32 in_num_packets,
83 const AudioStreamPacketDescription *in_packet_desc);
84
85 void ags_core_audio_port_handle_output_buffer(AgsCoreAudioPort *core_audio_port,
86 AudioQueueRef in_audio_queue, AudioQueueBufferRef in_buffer);
87 void ags_core_audio_port_handle_input_buffer(AgsCoreAudioPort *core_audio_port,
88 AudioQueueRef in_audio_queue, AudioQueueBufferRef in_buffer,
89 const AudioTimeStamp *in_start_time, UInt32 in_num_packets,
90 const AudioStreamPacketDescription *in_packet_desc);
91
92 void ags_core_audio_port_midi_notify_callback(const MIDINotification *message,
93 void *ref_con);
94 void ags_core_audio_port_midi_read_callback(const MIDIPacketList *pkt_list,
95 void *ref_con,
96 void *conn_ref_con);
97 #endif
98
99 /**
100 * SECTION:ags_core_audio_port
101 * @short_description: core audio resource.
102 * @title: AgsCoreAudioPort
103 * @section_id:
104 * @include: ags/audio/core-audio/ags_core_audio_port.h
105 *
106 * The #AgsCoreAudioPort represents either a core audio sequencer or soundcard to communicate
107 * with.
108 */
109
110 enum{
111 PROP_0,
112 PROP_CORE_AUDIO_CLIENT,
113 PROP_CORE_AUDIO_DEVICE,
114 PROP_PORT_NAME,
115 };
116
117 static gpointer ags_core_audio_port_parent_class = NULL;
118
119 #ifdef AGS_WITH_CORE_AUDIO
120 volatile gint ags_core_audio_port_output_run_loop_initialized;
121 volatile gint ags_core_audio_port_input_run_loop_initialized;
122
123 #ifdef AGS_MAC_BUNDLE
124 void ags_core_audio_port_premain() __attribute__ ((constructor));
125 #endif
126
ags_core_audio_port_premain()127 void ags_core_audio_port_premain()
128 {
129 g_atomic_int_set(&ags_core_audio_port_output_run_loop_initialized,
130 FALSE);
131 g_atomic_int_set(&ags_core_audio_port_input_run_loop_initialized,
132 FALSE);
133 }
134
135 CFRunLoopRef ags_core_audio_port_output_run_loop = NULL;
136 CFRunLoopRef ags_core_audio_port_input_run_loop = NULL;
137 #endif
138
139 GType
ags_core_audio_port_get_type()140 ags_core_audio_port_get_type()
141 {
142 static volatile gsize g_define_type_id__volatile = 0;
143
144 if(g_once_init_enter (&g_define_type_id__volatile)){
145 GType ags_type_core_audio_port = 0;
146
147 static const GTypeInfo ags_core_audio_port_info = {
148 sizeof(AgsCoreAudioPortClass),
149 NULL, /* base_init */
150 NULL, /* base_finalize */
151 (GClassInitFunc) ags_core_audio_port_class_init,
152 NULL, /* class_finalize */
153 NULL, /* class_data */
154 sizeof(AgsCoreAudioPort),
155 0, /* n_preallocs */
156 (GInstanceInitFunc) ags_core_audio_port_init,
157 };
158
159 static const GInterfaceInfo ags_connectable_interface_info = {
160 (GInterfaceInitFunc) ags_core_audio_port_connectable_interface_init,
161 NULL, /* interface_finalize */
162 NULL, /* interface_data */
163 };
164
165 ags_type_core_audio_port = g_type_register_static(G_TYPE_OBJECT,
166 "AgsCoreAudioPort",
167 &ags_core_audio_port_info,
168 0);
169
170 g_type_add_interface_static(ags_type_core_audio_port,
171 AGS_TYPE_CONNECTABLE,
172 &ags_connectable_interface_info);
173
174 g_once_init_leave(&g_define_type_id__volatile, ags_type_core_audio_port);
175 }
176
177 return g_define_type_id__volatile;
178 }
179
180 void
ags_core_audio_port_class_init(AgsCoreAudioPortClass * core_audio_port)181 ags_core_audio_port_class_init(AgsCoreAudioPortClass *core_audio_port)
182 {
183 GObjectClass *gobject;
184 GParamSpec *param_spec;
185
186 ags_core_audio_port_parent_class = g_type_class_peek_parent(core_audio_port);
187
188 /* GObjectClass */
189 gobject = (GObjectClass *) core_audio_port;
190
191 gobject->set_property = ags_core_audio_port_set_property;
192 gobject->get_property = ags_core_audio_port_get_property;
193
194 gobject->dispose = ags_core_audio_port_dispose;
195 gobject->finalize = ags_core_audio_port_finalize;
196
197 /* properties */
198 /**
199 * AgsCoreAudioPort:core-audio-client:
200 *
201 * The assigned #AgsCoreAudioClient.
202 *
203 * Since: 3.0.0
204 */
205 param_spec = g_param_spec_object("core-audio-client",
206 i18n_pspec("assigned core audio client"),
207 i18n_pspec("The assigned core audio client"),
208 AGS_TYPE_CORE_AUDIO_CLIENT,
209 G_PARAM_READABLE | G_PARAM_WRITABLE);
210 g_object_class_install_property(gobject,
211 PROP_CORE_AUDIO_CLIENT,
212 param_spec);
213
214 /**
215 * AgsCoreAudioPort:core-audio-device:
216 *
217 * The assigned #AgsCoreAudioDevout.
218 *
219 * Since: 3.0.0
220 */
221 param_spec = g_param_spec_object("core-audio-device",
222 i18n_pspec("assigned core audio devout"),
223 i18n_pspec("The assigned core audio devout"),
224 G_TYPE_OBJECT,
225 G_PARAM_READABLE | G_PARAM_WRITABLE);
226 g_object_class_install_property(gobject,
227 PROP_CORE_AUDIO_DEVICE,
228 param_spec);
229
230 /**
231 * AgsCoreAudioPort:port-name:
232 *
233 * The core audio soundcard indentifier
234 *
235 * Since: 3.0.0
236 */
237 param_spec = g_param_spec_string("port-name",
238 i18n_pspec("port name"),
239 i18n_pspec("The port name"),
240 "hw:0",
241 G_PARAM_READABLE | G_PARAM_WRITABLE);
242 g_object_class_install_property(gobject,
243 PROP_PORT_NAME,
244 param_spec);
245 }
246
247 void
ags_core_audio_port_connectable_interface_init(AgsConnectableInterface * connectable)248 ags_core_audio_port_connectable_interface_init(AgsConnectableInterface *connectable)
249 {
250 connectable->get_uuid = ags_core_audio_port_get_uuid;
251 connectable->has_resource = ags_core_audio_port_has_resource;
252
253 connectable->is_ready = ags_core_audio_port_is_ready;
254 connectable->add_to_registry = ags_core_audio_port_add_to_registry;
255 connectable->remove_from_registry = ags_core_audio_port_remove_from_registry;
256
257 connectable->list_resource = ags_core_audio_port_list_resource;
258 connectable->xml_compose = ags_core_audio_port_xml_compose;
259 connectable->xml_parse = ags_core_audio_port_xml_parse;
260
261 connectable->is_connected = ags_core_audio_port_is_connected;
262 connectable->connect = ags_core_audio_port_connect;
263 connectable->disconnect = ags_core_audio_port_disconnect;
264
265 connectable->connect_connection = NULL;
266 connectable->disconnect_connection = NULL;
267 }
268
269 void
ags_core_audio_port_init(AgsCoreAudioPort * core_audio_port)270 ags_core_audio_port_init(AgsCoreAudioPort *core_audio_port)
271 {
272 AgsConfig *config;
273
274 gchar *str;
275
276 guint word_size;
277 guint fixed_size;
278 guint i;
279
280 /* flags */
281 core_audio_port->flags = 0;
282
283 /* port mutex */
284 g_rec_mutex_init(&(core_audio_port->obj_mutex));
285
286 /* parent */
287 core_audio_port->core_audio_client = NULL;
288
289 /* uuid */
290 core_audio_port->uuid = ags_uuid_alloc();
291 ags_uuid_generate(core_audio_port->uuid);
292
293 /* */
294 core_audio_port->core_audio_device = NULL;
295
296 core_audio_port->port_uuid = ags_id_generator_create_uuid();
297 core_audio_port->port_name = NULL;
298
299 /* read config */
300 config = ags_config_get_instance();
301
302 core_audio_port->pcm_channels = ags_soundcard_helper_config_get_pcm_channels(config);
303
304 core_audio_port->samplerate = ags_soundcard_helper_config_get_samplerate(config);
305 core_audio_port->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
306 core_audio_port->format = ags_soundcard_helper_config_get_format(config);
307
308 core_audio_port->use_cache = TRUE;
309 core_audio_port->cache_buffer_size = AGS_CORE_AUDIO_PORT_DEFAULT_CACHE_BUFFER_SIZE;
310
311 core_audio_port->current_cache = 0;
312 core_audio_port->completed_cache = 0;
313 core_audio_port->cache_offset = 0;
314
315 core_audio_port->cache = (void **) malloc(4 * sizeof(void *));
316
317 #ifdef AGS_WITH_CORE_AUDIO
318 /* Audio */
319 //core_audio_port->aq_ref = (AudioQueueRef *) malloc(sizeof(AudioQueueRef));
320 memset(&(core_audio_port->aq_ref), 0, sizeof(AudioQueueRef));
321 memset(&(core_audio_port->record_aq_ref), 0, sizeof(AudioQueueRef));
322
323 //core_audio_port->data_format = (AudioStreamBasicDescription *) malloc(sizeof(AudioStreamBasicDescription));
324 memset(&(core_audio_port->data_format), 0, sizeof(AudioStreamBasicDescription));
325
326 size_t bytesPerSample = sizeof(gint16);
327
328 core_audio_port->data_format.mBitsPerChannel = 8 * bytesPerSample;
329
330 core_audio_port->data_format.mBytesPerPacket = core_audio_port->pcm_channels * bytesPerSample;
331 core_audio_port->data_format.mBytesPerFrame = core_audio_port->pcm_channels * bytesPerSample;
332
333 core_audio_port->data_format.mFramesPerPacket = 1;
334 core_audio_port->data_format.mChannelsPerFrame = core_audio_port->pcm_channels;
335
336 core_audio_port->data_format.mFormatID = kAudioFormatLinearPCM;
337 core_audio_port->data_format.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
338
339 core_audio_port->data_format.mSampleRate = (float) core_audio_port->samplerate;
340
341 memset(&(core_audio_port->record_format), 0, sizeof(AudioStreamBasicDescription));
342
343 core_audio_port->record_format.mBitsPerChannel = 8 * bytesPerSample;
344
345 core_audio_port->record_format.mBytesPerPacket = core_audio_port->pcm_channels * bytesPerSample;
346 core_audio_port->record_format.mBytesPerFrame = core_audio_port->pcm_channels * bytesPerSample;
347
348 core_audio_port->record_format.mFramesPerPacket = 1;
349 core_audio_port->record_format.mChannelsPerFrame = core_audio_port->pcm_channels;
350
351 core_audio_port->record_format.mFormatID = kAudioFormatLinearPCM;
352 core_audio_port->record_format.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
353
354 core_audio_port->record_format.mSampleRate = (float) core_audio_port->samplerate;
355
356 /* MIDI */
357 core_audio_port->midi_client = (MIDIClientRef *) malloc(sizeof(MIDIClientRef));
358 memset(core_audio_port->midi_client, 0, sizeof(MIDIClientRef));
359
360 core_audio_port->midi_port = (MIDIPortRef *) malloc(sizeof(MIDIPortRef));
361 memset(core_audio_port->midi_port, 0, sizeof(MIDIPortRef));
362 #else
363 core_audio_port->aq_ref = NULL;
364
365 core_audio_port->data_format = NULL;
366
367 core_audio_port->midi_client = NULL;
368 core_audio_port->midi_port = NULL;
369 #endif
370
371 word_size = 0;
372
373 switch(core_audio_port->format){
374 case AGS_SOUNDCARD_SIGNED_16_BIT:
375 {
376 core_audio_port->cache[0] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint16));
377 core_audio_port->cache[1] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint16));
378 core_audio_port->cache[2] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint16));
379 core_audio_port->cache[3] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint16));
380
381 word_size = sizeof(gint16);
382 }
383 break;
384 case AGS_SOUNDCARD_SIGNED_24_BIT:
385 {
386 core_audio_port->cache[0] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
387 core_audio_port->cache[1] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
388 core_audio_port->cache[2] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
389 core_audio_port->cache[3] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
390
391 word_size = sizeof(gint32);
392 }
393 break;
394 case AGS_SOUNDCARD_SIGNED_32_BIT:
395 {
396 core_audio_port->cache[0] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
397 core_audio_port->cache[1] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
398 core_audio_port->cache[2] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
399 core_audio_port->cache[3] = (void *) malloc(core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
400
401 word_size = sizeof(gint32);
402 }
403 break;
404 default:
405 g_warning("core audio devout/devin - unsupported format");
406 }
407
408 fixed_size = core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * word_size;
409
410 memset(core_audio_port->cache[0], 0, core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * word_size);
411 memset(core_audio_port->cache[1], 0, core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * word_size);
412 memset(core_audio_port->cache[2], 0, core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * word_size);
413 memset(core_audio_port->cache[3], 0, core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * word_size);
414
415 core_audio_port->midi_port_number = 0;
416
417 g_atomic_int_set(&(core_audio_port->is_empty),
418 FALSE);
419
420 g_atomic_int_set(&(core_audio_port->queued),
421 0);
422 }
423
424 void
ags_core_audio_port_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)425 ags_core_audio_port_set_property(GObject *gobject,
426 guint prop_id,
427 const GValue *value,
428 GParamSpec *param_spec)
429 {
430 AgsCoreAudioPort *core_audio_port;
431
432 GRecMutex *core_audio_port_mutex;
433
434 core_audio_port = AGS_CORE_AUDIO_PORT(gobject);
435
436 /* get core_audio port mutex */
437 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
438
439 switch(prop_id){
440 case PROP_CORE_AUDIO_CLIENT:
441 {
442 AgsCoreAudioClient *core_audio_client;
443
444 core_audio_client = (AgsCoreAudioClient *) g_value_get_object(value);
445
446 g_rec_mutex_lock(core_audio_port_mutex);
447
448 if(core_audio_port->core_audio_client == (GObject *) core_audio_client){
449 g_rec_mutex_unlock(core_audio_port_mutex);
450
451 return;
452 }
453
454 if(core_audio_port->core_audio_client != NULL){
455 g_object_unref(core_audio_port->core_audio_client);
456 }
457
458 if(core_audio_client != NULL){
459 g_object_ref(core_audio_client);
460 }
461
462 core_audio_port->core_audio_client = (GObject *) core_audio_client;
463
464 g_rec_mutex_unlock(core_audio_port_mutex);
465 }
466 break;
467 case PROP_CORE_AUDIO_DEVICE:
468 {
469 GObject *core_audio_device;
470
471 core_audio_device = g_value_get_object(value);
472
473 g_rec_mutex_lock(core_audio_port_mutex);
474
475 if(core_audio_port->core_audio_device == core_audio_device){
476 g_rec_mutex_unlock(core_audio_port_mutex);
477
478 return;
479 }
480
481 if(core_audio_port->core_audio_device != NULL){
482 g_object_unref(core_audio_port->core_audio_device);
483 }
484
485 if(core_audio_device != NULL){
486 g_object_ref(core_audio_device);
487 }
488
489 core_audio_port->core_audio_device = (GObject *) core_audio_device;
490
491 g_rec_mutex_unlock(core_audio_port_mutex);
492 }
493 break;
494 case PROP_PORT_NAME:
495 {
496 gchar *port_name;
497
498 port_name = g_value_get_string(value);
499
500 g_rec_mutex_lock(core_audio_port_mutex);
501
502 if(core_audio_port->port_name == port_name){
503 g_rec_mutex_unlock(core_audio_port_mutex);
504
505 return;
506 }
507
508 if(core_audio_port->port_name != NULL){
509 g_free(core_audio_port->port_name);
510 }
511
512 core_audio_port->port_name = port_name;
513
514 g_rec_mutex_unlock(core_audio_port_mutex);
515 }
516 break;
517 default:
518 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
519 break;
520 }
521 }
522
523 void
ags_core_audio_port_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)524 ags_core_audio_port_get_property(GObject *gobject,
525 guint prop_id,
526 GValue *value,
527 GParamSpec *param_spec)
528 {
529 AgsCoreAudioPort *core_audio_port;
530
531 GRecMutex *core_audio_port_mutex;
532
533 core_audio_port = AGS_CORE_AUDIO_PORT(gobject);
534
535 /* get core_audio port mutex */
536 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
537
538 switch(prop_id){
539 case PROP_CORE_AUDIO_CLIENT:
540 {
541 g_rec_mutex_lock(core_audio_port_mutex);
542
543 g_value_set_object(value, core_audio_port->core_audio_client);
544
545 g_rec_mutex_unlock(core_audio_port_mutex);
546 }
547 break;
548 case PROP_CORE_AUDIO_DEVICE:
549 {
550 g_rec_mutex_lock(core_audio_port_mutex);
551
552 g_value_set_object(value, core_audio_port->core_audio_device);
553
554 g_rec_mutex_unlock(core_audio_port_mutex);
555 }
556 break;
557 case PROP_PORT_NAME:
558 {
559 g_rec_mutex_lock(core_audio_port_mutex);
560
561 g_value_set_string(value, core_audio_port->port_name);
562
563 g_rec_mutex_unlock(core_audio_port_mutex);
564 }
565 break;
566 default:
567 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
568 break;
569 }
570 }
571
572 void
ags_core_audio_port_dispose(GObject * gobject)573 ags_core_audio_port_dispose(GObject *gobject)
574 {
575 AgsCoreAudioPort *core_audio_port;
576
577 core_audio_port = AGS_CORE_AUDIO_PORT(gobject);
578
579 /* core audio client */
580 if(core_audio_port->core_audio_client != NULL){
581 g_object_unref(core_audio_port->core_audio_client);
582
583 core_audio_port->core_audio_client = NULL;
584 }
585
586 /* core audio device */
587 if(core_audio_port->core_audio_device != NULL){
588 g_object_unref(core_audio_port->core_audio_device);
589
590 core_audio_port->core_audio_device = NULL;
591 }
592
593 /* call parent */
594 G_OBJECT_CLASS(ags_core_audio_port_parent_class)->dispose(gobject);
595 }
596
597 void
ags_core_audio_port_finalize(GObject * gobject)598 ags_core_audio_port_finalize(GObject *gobject)
599 {
600 AgsCoreAudioPort *core_audio_port;
601
602 core_audio_port = AGS_CORE_AUDIO_PORT(gobject);
603
604 /* core audio client */
605 if(core_audio_port->core_audio_client != NULL){
606 g_object_unref(core_audio_port->core_audio_client);
607 }
608
609 /* core audio device */
610 if(core_audio_port->core_audio_device != NULL){
611 g_object_unref(core_audio_port->core_audio_device);
612 }
613
614 /* name */
615 g_free(core_audio_port->port_name);
616
617 if(core_audio_port->midi_client != NULL){
618 free(core_audio_port->midi_client);
619 }
620
621 if(core_audio_port->midi_port != NULL){
622 free(core_audio_port->midi_port);
623 }
624
625 /* call parent */
626 G_OBJECT_CLASS(ags_core_audio_port_parent_class)->finalize(gobject);
627 }
628
629 AgsUUID*
ags_core_audio_port_get_uuid(AgsConnectable * connectable)630 ags_core_audio_port_get_uuid(AgsConnectable *connectable)
631 {
632 AgsCoreAudioPort *core_audio_port;
633
634 AgsUUID *ptr;
635
636 GRecMutex *core_audio_port_mutex;
637
638 core_audio_port = AGS_CORE_AUDIO_PORT(connectable);
639
640 /* get core_audio port signal mutex */
641 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
642
643 /* get UUID */
644 g_rec_mutex_lock(core_audio_port_mutex);
645
646 ptr = core_audio_port->uuid;
647
648 g_rec_mutex_unlock(core_audio_port_mutex);
649
650 return(ptr);
651 }
652
653 gboolean
ags_core_audio_port_has_resource(AgsConnectable * connectable)654 ags_core_audio_port_has_resource(AgsConnectable *connectable)
655 {
656 return(FALSE);
657 }
658
659 gboolean
ags_core_audio_port_is_ready(AgsConnectable * connectable)660 ags_core_audio_port_is_ready(AgsConnectable *connectable)
661 {
662 AgsCoreAudioPort *core_audio_port;
663
664 gboolean is_ready;
665
666 core_audio_port = AGS_CORE_AUDIO_PORT(connectable);
667
668 /* check is added */
669 is_ready = ags_core_audio_port_test_flags(core_audio_port, AGS_CORE_AUDIO_PORT_ADDED_TO_REGISTRY);
670
671 return(is_ready);
672 }
673
674 void
ags_core_audio_port_add_to_registry(AgsConnectable * connectable)675 ags_core_audio_port_add_to_registry(AgsConnectable *connectable)
676 {
677 AgsCoreAudioPort *core_audio_port;
678
679 if(ags_connectable_is_ready(connectable)){
680 return;
681 }
682
683 core_audio_port = AGS_CORE_AUDIO_PORT(connectable);
684
685 ags_core_audio_port_set_flags(core_audio_port, AGS_CORE_AUDIO_PORT_ADDED_TO_REGISTRY);
686 }
687
688 void
ags_core_audio_port_remove_from_registry(AgsConnectable * connectable)689 ags_core_audio_port_remove_from_registry(AgsConnectable *connectable)
690 {
691 AgsCoreAudioPort *core_audio_port;
692
693 if(!ags_connectable_is_ready(connectable)){
694 return;
695 }
696
697 core_audio_port = AGS_CORE_AUDIO_PORT(connectable);
698
699 ags_core_audio_port_unset_flags(core_audio_port, AGS_CORE_AUDIO_PORT_ADDED_TO_REGISTRY);
700 }
701
702 xmlNode*
ags_core_audio_port_list_resource(AgsConnectable * connectable)703 ags_core_audio_port_list_resource(AgsConnectable *connectable)
704 {
705 xmlNode *node;
706
707 node = NULL;
708
709 //TODO:JK: implement me
710
711 return(node);
712 }
713
714 xmlNode*
ags_core_audio_port_xml_compose(AgsConnectable * connectable)715 ags_core_audio_port_xml_compose(AgsConnectable *connectable)
716 {
717 xmlNode *node;
718
719 node = NULL;
720
721 //TODO:JK: implement me
722
723 return(node);
724 }
725
726 void
ags_core_audio_port_xml_parse(AgsConnectable * connectable,xmlNode * node)727 ags_core_audio_port_xml_parse(AgsConnectable *connectable,
728 xmlNode *node)
729 {
730 //TODO:JK: implement me
731 }
732
733 gboolean
ags_core_audio_port_is_connected(AgsConnectable * connectable)734 ags_core_audio_port_is_connected(AgsConnectable *connectable)
735 {
736 AgsCoreAudioPort *core_audio_port;
737
738 gboolean is_connected;
739
740 core_audio_port = AGS_CORE_AUDIO_PORT(connectable);
741
742 /* check is connected */
743 is_connected = ags_core_audio_port_test_flags(core_audio_port, AGS_CORE_AUDIO_PORT_CONNECTED);
744
745 return(is_connected);
746 }
747
748 void
ags_core_audio_port_connect(AgsConnectable * connectable)749 ags_core_audio_port_connect(AgsConnectable *connectable)
750 {
751 AgsCoreAudioPort *core_audio_port;
752
753 if(ags_connectable_is_connected(connectable)){
754 return;
755 }
756
757 core_audio_port = AGS_CORE_AUDIO_PORT(connectable);
758
759 ags_core_audio_port_set_flags(core_audio_port, AGS_CORE_AUDIO_PORT_CONNECTED);
760 }
761
762 void
ags_core_audio_port_disconnect(AgsConnectable * connectable)763 ags_core_audio_port_disconnect(AgsConnectable *connectable)
764 {
765
766 AgsCoreAudioPort *core_audio_port;
767
768 if(!ags_connectable_is_connected(connectable)){
769 return;
770 }
771
772 core_audio_port = AGS_CORE_AUDIO_PORT(connectable);
773
774 ags_core_audio_port_unset_flags(core_audio_port, AGS_CORE_AUDIO_PORT_CONNECTED);
775 }
776
777 /**
778 * ags_core_audio_port_test_flags:
779 * @core_audio_port: the #AgsCoreAudioPort
780 * @flags: the flags
781 *
782 * Test @flags to be set on @core_audio_port.
783 *
784 * Returns: %TRUE if flags are set, else %FALSE
785 *
786 * Since: 3.0.0
787 */
788 gboolean
ags_core_audio_port_test_flags(AgsCoreAudioPort * core_audio_port,guint flags)789 ags_core_audio_port_test_flags(AgsCoreAudioPort *core_audio_port, guint flags)
790 {
791 gboolean retval;
792
793 GRecMutex *core_audio_port_mutex;
794
795 if(!AGS_IS_CORE_AUDIO_PORT(core_audio_port)){
796 return(FALSE);
797 }
798
799 /* get core_audio port mutex */
800 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
801
802 /* test */
803 g_rec_mutex_lock(core_audio_port_mutex);
804
805 retval = (flags & (core_audio_port->flags)) ? TRUE: FALSE;
806
807 g_rec_mutex_unlock(core_audio_port_mutex);
808
809 return(retval);
810 }
811
812 /**
813 * ags_core_audio_port_set_flags:
814 * @core_audio_port: the #AgsCoreAudioPort
815 * @flags: see #AgsCoreAudioPortFlags-enum
816 *
817 * Enable a feature of @core_audio_port.
818 *
819 * Since: 3.0.0
820 */
821 void
ags_core_audio_port_set_flags(AgsCoreAudioPort * core_audio_port,guint flags)822 ags_core_audio_port_set_flags(AgsCoreAudioPort *core_audio_port, guint flags)
823 {
824 GRecMutex *core_audio_port_mutex;
825
826 if(!AGS_IS_CORE_AUDIO_PORT(core_audio_port)){
827 return;
828 }
829
830 /* get core_audio port mutex */
831 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
832
833 //TODO:JK: add more?
834
835 /* set flags */
836 g_rec_mutex_lock(core_audio_port_mutex);
837
838 core_audio_port->flags |= flags;
839
840 g_rec_mutex_unlock(core_audio_port_mutex);
841 }
842
843 /**
844 * ags_core_audio_port_unset_flags:
845 * @core_audio_port: the #AgsCoreAudioPort
846 * @flags: see #AgsCoreAudioPortFlags-enum
847 *
848 * Disable a feature of @core_audio_port.
849 *
850 * Since: 3.0.0
851 */
852 void
ags_core_audio_port_unset_flags(AgsCoreAudioPort * core_audio_port,guint flags)853 ags_core_audio_port_unset_flags(AgsCoreAudioPort *core_audio_port, guint flags)
854 {
855 GRecMutex *core_audio_port_mutex;
856
857 if(!AGS_IS_CORE_AUDIO_PORT(core_audio_port)){
858 return;
859 }
860
861 /* get core_audio port mutex */
862 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
863
864 //TODO:JK: add more?
865
866 /* unset flags */
867 g_rec_mutex_lock(core_audio_port_mutex);
868
869 core_audio_port->flags &= (~flags);
870
871 g_rec_mutex_unlock(core_audio_port_mutex);
872 }
873
874 /**
875 * ags_core_audio_port_find:
876 * @core_audio_port: (element-type AgsAudio.CoreAudioPort) (transfer none): the #GList-struct containing #AgsCoreAudioPort
877 * @port_name: the port name to find
878 *
879 * Finds next match of @port_name in @core_audio_port.
880 *
881 * Returns: (element-type AgsAudio.CoreAudioPort) (transfer none): the next matching #GList-struct or %NULL
882 *
883 * Since: 3.0.0
884 */
885 GList*
ags_core_audio_port_find(GList * core_audio_port,gchar * port_name)886 ags_core_audio_port_find(GList *core_audio_port,
887 gchar *port_name)
888 {
889 gboolean success;
890
891 GRecMutex *core_audio_port_mutex;
892
893 while(core_audio_port != NULL){
894 /* get core_audio port mutex */
895 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port->data);
896
897 /* check port name */
898 g_rec_mutex_lock(core_audio_port_mutex);
899
900 success = (!g_ascii_strcasecmp(AGS_CORE_AUDIO_PORT(core_audio_port->data)->port_name,
901 port_name)) ? TRUE: FALSE;
902
903 g_rec_mutex_unlock(core_audio_port_mutex);
904
905 if(success){
906 return(core_audio_port);
907 }
908 }
909
910 return(NULL);
911 }
912
913 #ifdef AGS_WITH_CORE_AUDIO
914 OSStatus
SetCurrentIOBufferFrameSize(AudioObjectID inDeviceID,UInt32 inIOBufferFrameSize)915 SetCurrentIOBufferFrameSize(AudioObjectID inDeviceID,
916 UInt32 inIOBufferFrameSize)
917 {
918 AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyBufferFrameSize,
919 kAudioObjectPropertyScopeGlobal,
920 kAudioObjectPropertyElementMaster };
921
922 return AudioObjectSetPropertyData(inDeviceID,
923 &theAddress,
924 0,
925 NULL,
926 sizeof(UInt32), &inIOBufferFrameSize);
927 }
928 #endif
929
930 #ifdef AGS_WITH_CORE_AUDIO
931 void*
ags_core_audio_port_output_thread(AgsCoreAudioPort * core_audio_port)932 ags_core_audio_port_output_thread(AgsCoreAudioPort *core_audio_port)
933 {
934 ags_core_audio_port_output_run_loop = CFRunLoopGetCurrent();
935
936 g_atomic_int_set(&ags_core_audio_port_output_run_loop_initialized,
937 TRUE);
938
939 do{
940 CFRunLoopRunInMode(kCFRunLoopDefaultMode,
941 0,
942 TRUE);
943 }while(g_atomic_int_get(&(core_audio_port->output_running)));
944
945 g_thread_exit(NULL);
946
947 return(NULL);
948 }
949
950 void*
ags_core_audio_port_input_thread(AgsCoreAudioPort * core_audio_port)951 ags_core_audio_port_input_thread(AgsCoreAudioPort *core_audio_port)
952 {
953 ags_core_audio_port_input_run_loop = CFRunLoopGetCurrent();
954
955 g_atomic_int_set(&ags_core_audio_port_input_run_loop_initialized,
956 TRUE);
957
958 do{
959 CFRunLoopRunInMode(kCFRunLoopDefaultMode,
960 0,
961 TRUE);
962 }while(g_atomic_int_get(&(core_audio_port->input_running)));
963
964 g_thread_exit(NULL);
965
966 return(NULL);
967 }
968 #endif
969
970 /**
971 * ags_core_audio_port_register:
972 * @core_audio_port: the #AgsCoreAudioPort
973 * @port_name: the name as string
974 * @is_audio: if %TRUE interpreted as audio port
975 * @is_midi: if %TRUE interpreted as midi port
976 * @is_output: if %TRUE port is acting as output, otherwise as input
977 *
978 * Register a new core audio port and read uuid. Creates a new AgsSequencer or AgsSoundcard
979 * object.
980 *
981 * Since: 3.0.0
982 */
983 void
ags_core_audio_port_register(AgsCoreAudioPort * core_audio_port,gchar * port_name,gboolean is_audio,gboolean is_midi,gboolean is_output)984 ags_core_audio_port_register(AgsCoreAudioPort *core_audio_port,
985 gchar *port_name,
986 gboolean is_audio, gboolean is_midi,
987 gboolean is_output)
988 {
989 AgsCoreAudioServer *core_audio_server;
990 AgsCoreAudioClient *core_audio_client;
991
992 GList *list;
993
994 gchar *name, *uuid;
995
996 guint format;
997 guint i;
998 gboolean use_cache;
999
1000 #ifdef AGS_WITH_CORE_AUDIO
1001 AUGraph *graph;
1002 OSStatus retval;
1003 #else
1004 gpointer graph;
1005 #endif
1006
1007 GRecMutex *core_audio_client_mutex;
1008 GRecMutex *core_audio_port_mutex;
1009
1010 if(!AGS_IS_CORE_AUDIO_PORT(core_audio_port) ||
1011 port_name == NULL){
1012 return;
1013 }
1014
1015 g_object_get(core_audio_port,
1016 "core-audio-client", &core_audio_client,
1017 NULL);
1018
1019 if(core_audio_client == NULL){
1020 g_warning("ags_core_audio_port.c - no assigned AgsCore_AudioClient");
1021
1022 return;
1023 }
1024
1025 if(ags_core_audio_port_test_flags(core_audio_port, AGS_CORE_AUDIO_PORT_REGISTERED)){
1026 g_object_unref(core_audio_client);
1027
1028 return;
1029 }
1030
1031 /* get core_audio server and application context */
1032 g_object_get(core_audio_client,
1033 "core-audio-server", &core_audio_server,
1034 NULL);
1035
1036 if(core_audio_server == NULL){
1037 g_object_unref(core_audio_client);
1038
1039 return;
1040 }
1041
1042 /* get core_audio client mutex */
1043 core_audio_client_mutex = AGS_CORE_AUDIO_CLIENT_GET_OBJ_MUTEX(core_audio_client);
1044
1045 /* get graph */
1046 g_rec_mutex_lock(core_audio_client_mutex);
1047
1048 graph = core_audio_client->graph;
1049
1050 g_rec_mutex_unlock(core_audio_client_mutex);
1051
1052 if(graph == NULL){
1053 g_object_unref(core_audio_client);
1054
1055 g_object_unref(core_audio_server);
1056
1057 return;
1058 }
1059
1060 /* get core_audio port mutex */
1061 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
1062
1063 /* get port name */
1064 //FIXME:JK: memory leak?
1065 g_rec_mutex_lock(core_audio_port_mutex);
1066
1067 port_name = g_strdup(core_audio_port->port_name);
1068
1069 format = core_audio_port->format;
1070
1071 use_cache = core_audio_port->use_cache;
1072
1073 g_rec_mutex_unlock(core_audio_port_mutex);
1074
1075 /* create sequencer or soundcard */
1076 if(is_output){
1077 ags_core_audio_port_set_flags(core_audio_port, AGS_CORE_AUDIO_PORT_IS_OUTPUT);
1078 }else{
1079 ags_core_audio_port_set_flags(core_audio_port, AGS_CORE_AUDIO_PORT_IS_INPUT);
1080 }
1081
1082 if(is_audio){
1083 ags_core_audio_port_set_flags(core_audio_port, AGS_CORE_AUDIO_PORT_IS_AUDIO);
1084
1085 if(is_output){
1086 GThread *thread;
1087
1088 void **arr;
1089
1090 guint word_size;
1091
1092 switch(format){
1093 case AGS_SOUNDCARD_SIGNED_8_BIT:
1094 {
1095 word_size = sizeof(gint8);
1096 }
1097 break;
1098 case AGS_SOUNDCARD_SIGNED_16_BIT:
1099 {
1100 word_size = sizeof(gint16);
1101 }
1102 break;
1103 case AGS_SOUNDCARD_SIGNED_24_BIT:
1104 {
1105 word_size = sizeof(gint32);
1106 }
1107 break;
1108 case AGS_SOUNDCARD_SIGNED_32_BIT:
1109 {
1110 word_size = sizeof(gint32);
1111 }
1112 break;
1113 case AGS_SOUNDCARD_SIGNED_64_BIT:
1114 {
1115 word_size = sizeof(gint64);
1116 }
1117 break;
1118 default:
1119 g_message("core audio - unsupported word size");
1120 }
1121
1122 #ifdef AGS_WITH_CORE_AUDIO
1123 if(!g_atomic_int_get(&ags_core_audio_port_output_run_loop_initialized)){
1124 g_atomic_int_set(&(core_audio_port->output_running),
1125 TRUE);
1126 thread = g_thread_new("Advanced Gtk+ Sequencer - core-audio output",
1127 ags_core_audio_port_output_thread,
1128 core_audio_port);
1129
1130 while(!g_atomic_int_get(&ags_core_audio_port_output_run_loop_initialized)){
1131 usleep(400);
1132 }
1133 }
1134
1135 if(use_cache){
1136 AudioQueueNewOutput(&(core_audio_port->data_format),
1137 ags_core_audio_port_cached_handle_output_buffer,
1138 core_audio_port,
1139 ags_core_audio_port_output_run_loop, NULL,
1140 0,
1141 &(core_audio_port->aq_ref));
1142 }else{
1143 AudioQueueNewOutput(&(core_audio_port->data_format),
1144 ags_core_audio_port_handle_output_buffer,
1145 core_audio_port,
1146 ags_core_audio_port_output_run_loop, NULL,
1147 0,
1148 &(core_audio_port->aq_ref));
1149 }
1150
1151 for(i = 0; i < 8; i++){
1152 if(use_cache){
1153 AudioQueueAllocateBuffer(core_audio_port->aq_ref,
1154 (core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint16)),
1155 &(core_audio_port->buf_ref[i]));
1156 }else{
1157 AudioQueueAllocateBuffer(core_audio_port->aq_ref,
1158 (core_audio_port->pcm_channels * core_audio_port->buffer_size * sizeof(gint16)),
1159 &(core_audio_port->buf_ref[i]));
1160 }
1161
1162 ags_core_audio_port_handle_output_buffer(core_audio_port,
1163 core_audio_port->aq_ref,
1164 core_audio_port->buf_ref[i]);
1165 }
1166
1167 AudioQueueSetParameter(core_audio_port->aq_ref,
1168 kAudioQueueParam_Volume, 1.0);
1169
1170 AudioQueueStart(core_audio_port->aq_ref,
1171 NULL);
1172
1173 #endif
1174 }else{
1175 GThread *thread;
1176
1177 void **arr;
1178
1179 guint word_size;
1180
1181 switch(format){
1182 case AGS_SOUNDCARD_SIGNED_8_BIT:
1183 {
1184 word_size = sizeof(gint8);
1185 }
1186 break;
1187 case AGS_SOUNDCARD_SIGNED_16_BIT:
1188 {
1189 word_size = sizeof(gint16);
1190 }
1191 break;
1192 case AGS_SOUNDCARD_SIGNED_24_BIT:
1193 {
1194 word_size = sizeof(gint32);
1195 }
1196 break;
1197 case AGS_SOUNDCARD_SIGNED_32_BIT:
1198 {
1199 word_size = sizeof(gint32);
1200 }
1201 break;
1202 case AGS_SOUNDCARD_SIGNED_64_BIT:
1203 {
1204 word_size = sizeof(gint64);
1205 }
1206 break;
1207 default:
1208 g_message("core audio - unsupported word size");
1209 }
1210
1211 #ifdef AGS_WITH_CORE_AUDIO
1212 if(!g_atomic_int_get(&ags_core_audio_port_input_run_loop_initialized)){
1213 g_atomic_int_set(&(core_audio_port->input_running),
1214 TRUE);
1215 thread = g_thread_new("Advanced Gtk+ Sequencer - core-audio input",
1216 ags_core_audio_port_input_thread,
1217 core_audio_port);
1218
1219 while(!g_atomic_int_get(&ags_core_audio_port_input_run_loop_initialized)){
1220 usleep(400);
1221 }
1222 }
1223
1224 #if 0
1225 if(use_cache){
1226 AudioQueueNewInput(&(core_audio_port->record_format),
1227 ags_core_audio_port_cached_handle_input_buffer,
1228 core_audio_port,
1229 ags_core_audio_port_input_run_loop, kCFRunLoopDefaultMode,
1230 0,
1231 &(core_audio_port->record_aq_ref));
1232 }else{
1233
1234 }
1235 #endif
1236
1237 AudioQueueNewInput(&(core_audio_port->record_format),
1238 ags_core_audio_port_handle_input_buffer,
1239 core_audio_port,
1240 ags_core_audio_port_input_run_loop, kCFRunLoopDefaultMode,
1241 0,
1242 &(core_audio_port->record_aq_ref));
1243
1244 for(i = 0; i < 16; i++){
1245 AudioQueueAllocateBuffer(core_audio_port->record_aq_ref,
1246 (core_audio_port->pcm_channels * core_audio_port->buffer_size * sizeof(gint16)),
1247 &(core_audio_port->record_buf_ref[i]));
1248
1249 AudioQueueEnqueueBuffer(core_audio_port->record_aq_ref,
1250 core_audio_port->record_buf_ref[i],
1251 0,
1252 NULL);
1253 }
1254
1255 AudioQueueSetParameter(core_audio_port->record_aq_ref,
1256 kAudioQueueParam_Volume, 1.0);
1257
1258 AudioQueueStart(core_audio_port->record_aq_ref,
1259 NULL);
1260 #endif
1261 }
1262 }else if(is_midi){
1263 ags_core_audio_port_set_flags(core_audio_port, AGS_CORE_AUDIO_PORT_IS_MIDI);
1264
1265 if(is_output){
1266 //NOTE:JK: not implemented
1267 }else{
1268 #ifdef AGS_WITH_CORE_AUDIO
1269 MIDIEndpointRef endpoint;
1270
1271 retval = MIDIClientCreate(CFSTR("Advanced Gtk+ Sequencer - Core MIDI to System Sounds Demo"),
1272 NULL,
1273 core_audio_port,
1274 core_audio_port->midi_client);
1275
1276 if(retval != noErr){
1277 goto ags_core_audio_port_register_END;
1278 }
1279
1280 retval = MIDIInputPortCreate(*(core_audio_port->midi_client), CFSTR("Input port"),
1281 ags_core_audio_port_midi_read_callback,
1282 core_audio_port,
1283 core_audio_port->midi_port);
1284
1285 if(retval != noErr){
1286 goto ags_core_audio_port_register_END;
1287 }
1288
1289 endpoint = MIDIGetSource(core_audio_port->midi_port_number);
1290
1291 if(endpoint == 0){
1292 goto ags_core_audio_port_register_END;
1293 }
1294
1295 retval = MIDIPortConnectSource(*(core_audio_port->midi_port), endpoint, NULL);
1296
1297 if(retval != noErr){
1298 goto ags_core_audio_port_register_END;
1299 }
1300 #endif
1301 }
1302 }
1303
1304 ags_core_audio_port_set_flags(core_audio_port, AGS_CORE_AUDIO_PORT_REGISTERED);
1305
1306 ags_core_audio_port_register_END:
1307
1308 g_object_unref(core_audio_client);
1309
1310 g_object_unref(core_audio_server);
1311 }
1312
1313 void
ags_core_audio_port_unregister(AgsCoreAudioPort * core_audio_port)1314 ags_core_audio_port_unregister(AgsCoreAudioPort *core_audio_port)
1315 {
1316 if(!AGS_IS_CORE_AUDIO_PORT(core_audio_port)){
1317 return;
1318 }
1319
1320 g_atomic_int_set(&(core_audio_port->output_running),
1321 FALSE);
1322
1323 g_atomic_int_set(&(core_audio_port->input_running),
1324 FALSE);
1325 //NOTE:JK: not implemented
1326
1327 ags_core_audio_port_unset_flags(core_audio_port, AGS_CORE_AUDIO_PORT_REGISTERED);
1328 }
1329
1330 #ifdef AGS_WITH_CORE_AUDIO
1331 void
ags_core_audio_port_cached_handle_output_buffer(AgsCoreAudioPort * core_audio_port,AudioQueueRef in_audio_queue,AudioQueueBufferRef in_buffer)1332 ags_core_audio_port_cached_handle_output_buffer(AgsCoreAudioPort *core_audio_port,
1333 AudioQueueRef in_audio_queue, AudioQueueBufferRef in_buffer)
1334 {
1335 AgsCoreAudioDevout *core_audio_devout;
1336 AgsCoreAudioDevin *core_audio_devin;
1337
1338 AgsAudioLoop *audio_loop;
1339
1340 AgsApplicationContext *application_context;
1341
1342 GObject *soundcard;
1343
1344 struct timespec idle_time = {
1345 0,
1346 0,
1347 };
1348
1349 guint current_cache;
1350 guint next_cache, completed_cache;
1351 guint played_cache;
1352 guint word_size;
1353 guint frame_size;
1354 guint copy_mode;
1355 gboolean is_playing;
1356
1357 GRecMutex *core_audio_port_mutex;
1358
1359 if(core_audio_port == NULL){
1360 return;
1361 }
1362
1363 application_context = ags_application_context_get_instance();
1364
1365 audio_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
1366
1367 /* get core_audio port mutex */
1368 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
1369
1370 /* */
1371 g_rec_mutex_lock(core_audio_port_mutex);
1372
1373 core_audio_devout = (AgsCoreAudioDevout *) core_audio_port->core_audio_device;
1374
1375 switch(core_audio_port->format){
1376 case AGS_SOUNDCARD_SIGNED_16_BIT:
1377 {
1378 word_size = sizeof(gint16);
1379
1380 copy_mode = ags_audio_buffer_util_get_copy_mode(AGS_AUDIO_BUFFER_UTIL_S16,
1381 AGS_AUDIO_BUFFER_UTIL_S16);
1382 }
1383 break;
1384 case AGS_SOUNDCARD_SIGNED_24_BIT:
1385 {
1386 word_size = sizeof(gint32);
1387
1388 copy_mode = ags_audio_buffer_util_get_copy_mode(AGS_AUDIO_BUFFER_UTIL_S16,
1389 AGS_AUDIO_BUFFER_UTIL_S24);
1390 }
1391 break;
1392 case AGS_SOUNDCARD_SIGNED_32_BIT:
1393 {
1394 word_size = sizeof(gint32);
1395
1396 copy_mode = ags_audio_buffer_util_get_copy_mode(AGS_AUDIO_BUFFER_UTIL_S16,
1397 AGS_AUDIO_BUFFER_UTIL_S32);
1398 }
1399 break;
1400 }
1401
1402 frame_size = core_audio_port->pcm_channels * core_audio_port->cache_buffer_size;
1403 in_buffer->mAudioDataByteSize = frame_size * sizeof(gint16);
1404
1405 current_cache = core_audio_port->current_cache;
1406
1407 g_rec_mutex_unlock(core_audio_port_mutex);
1408
1409 soundcard = NULL;
1410
1411 if(core_audio_devout != NULL){
1412 soundcard = (GObject *) core_audio_devout;
1413 }else if(core_audio_devin != NULL){
1414 soundcard = (GObject *) core_audio_devin;
1415 }
1416
1417 is_playing = FALSE;
1418
1419 if(ags_soundcard_is_playing(AGS_SOUNDCARD(soundcard))){
1420 if(current_cache == 3){
1421 next_cache = 0;
1422 }else{
1423 next_cache = current_cache + 1;
1424 }
1425
1426 is_playing = TRUE;
1427 }else{
1428 next_cache = 0;
1429 }
1430
1431 /* wait until cache ready */
1432 g_rec_mutex_lock(core_audio_port_mutex);
1433
1434 completed_cache = core_audio_port->completed_cache;
1435
1436 g_rec_mutex_unlock(core_audio_port_mutex);
1437
1438 if(is_playing){
1439 idle_time.tv_nsec = ags_core_audio_port_get_latency(core_audio_port) / 8;
1440
1441 while(next_cache == completed_cache &&
1442 ags_soundcard_is_playing(AGS_SOUNDCARD(soundcard))){
1443 nanosleep(&idle_time, NULL);
1444
1445 g_rec_mutex_lock(core_audio_port_mutex);
1446
1447 completed_cache = core_audio_port->completed_cache;
1448
1449 g_rec_mutex_unlock(core_audio_port_mutex);
1450 }
1451
1452 if(current_cache == 0){
1453 played_cache = 3;
1454 }else{
1455 played_cache = current_cache - 1;
1456 }
1457 }else{
1458 played_cache = 0;
1459 }
1460
1461 // g_message("p %d", played_cache);
1462 ags_audio_buffer_util_clear_buffer(in_buffer->mAudioData, 1,
1463 (in_buffer->mAudioDataByteSize / sizeof(gint16)), AGS_AUDIO_BUFFER_UTIL_S16);
1464 ags_audio_buffer_util_copy_buffer_to_buffer(in_buffer->mAudioData, 1, 0,
1465 core_audio_port->cache[played_cache], 1, 0,
1466 frame_size, copy_mode);
1467
1468 AudioQueueEnqueueBuffer(core_audio_port->aq_ref,
1469 in_buffer,
1470 0,
1471 NULL);
1472
1473 /* seek current cache */
1474 g_rec_mutex_lock(core_audio_port_mutex);
1475
1476 core_audio_port->current_cache = next_cache;
1477
1478 g_rec_mutex_unlock(core_audio_port_mutex);
1479
1480 /* unref */
1481 g_object_unref(audio_loop);
1482 }
1483
1484 void
ags_core_audio_port_cached_handle_input_buffer(AgsCoreAudioPort * core_audio_port,AudioQueueRef in_audio_queue,AudioQueueBufferRef in_buffer,const AudioTimeStamp * in_start_time,UInt32 in_num_packets,const AudioStreamPacketDescription * in_packet_desc)1485 ags_core_audio_port_cached_handle_input_buffer(AgsCoreAudioPort *core_audio_port,
1486 AudioQueueRef in_audio_queue, AudioQueueBufferRef in_buffer,
1487 const AudioTimeStamp *in_start_time, UInt32 in_num_packets,
1488 const AudioStreamPacketDescription *in_packet_desc)
1489 {
1490 //TODO:JK: implement me
1491 }
1492
1493 void
ags_core_audio_port_handle_output_buffer(AgsCoreAudioPort * core_audio_port,AudioQueueRef in_audio_queue,AudioQueueBufferRef in_buffer)1494 ags_core_audio_port_handle_output_buffer(AgsCoreAudioPort *core_audio_port,
1495 AudioQueueRef in_audio_queue, AudioQueueBufferRef in_buffer)
1496 {
1497 AgsCoreAudioDevout *core_audio_devout;
1498
1499 AgsAudioLoop *audio_loop;
1500
1501 AgsApplicationContext *application_context;
1502
1503 guint word_size;
1504 guint nth_buffer;
1505 guint copy_mode;
1506 guint count;
1507 guint i;
1508 gboolean is_playing;
1509 gboolean pass_through;
1510 gboolean no_event;
1511 gboolean empty_run;
1512
1513 GRecMutex *core_audio_port_mutex;
1514 GRecMutex *device_mutex;
1515 GMutex *callback_mutex;
1516 GMutex *callback_finish_mutex;
1517
1518 if(core_audio_port == NULL){
1519 return;
1520 }
1521
1522 /* get core-audio port mutex */
1523 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
1524
1525 if(g_atomic_int_get(&(core_audio_port->queued)) > 0){
1526 g_warning("drop core audio output callback");
1527
1528 return;
1529 }else{
1530 g_atomic_int_inc(&(core_audio_port->queued));
1531 }
1532
1533 /*
1534 * process audio
1535 */
1536 /* */
1537 application_context = ags_application_context_get_instance();
1538
1539 audio_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
1540
1541 in_buffer->mAudioDataByteSize = core_audio_port->pcm_channels * core_audio_port->buffer_size * sizeof(gint16);
1542 ags_audio_buffer_util_clear_buffer(in_buffer->mAudioData, 1,
1543 (in_buffer->mAudioDataByteSize / sizeof(gint16)), AGS_AUDIO_BUFFER_UTIL_S16);
1544
1545 if(audio_loop == NULL){
1546 g_atomic_int_dec_and_test(&(core_audio_port->queued));
1547
1548 return;
1549 }
1550
1551 /* */
1552 g_rec_mutex_lock(core_audio_port_mutex);
1553
1554 core_audio_devout = core_audio_port->core_audio_device;
1555
1556 g_rec_mutex_unlock(core_audio_port_mutex);
1557
1558 /* get device mutex */
1559 device_mutex = AGS_CORE_AUDIO_DEVOUT_GET_OBJ_MUTEX(core_audio_devout);
1560
1561 /* */
1562 g_rec_mutex_lock(core_audio_port_mutex);
1563
1564 empty_run = FALSE;
1565
1566 switch(core_audio_port->format){
1567 case AGS_SOUNDCARD_SIGNED_8_BIT:
1568 {
1569 word_size = sizeof(gint8);
1570 }
1571 break;
1572 case AGS_SOUNDCARD_SIGNED_16_BIT:
1573 {
1574 word_size = sizeof(gint16);
1575 }
1576 break;
1577 case AGS_SOUNDCARD_SIGNED_24_BIT:
1578 {
1579 word_size = sizeof(gint32);
1580 }
1581 break;
1582 case AGS_SOUNDCARD_SIGNED_32_BIT:
1583 {
1584 word_size = sizeof(gint32);
1585 }
1586 break;
1587 case AGS_SOUNDCARD_SIGNED_64_BIT:
1588 {
1589 word_size = sizeof(gint64);
1590 }
1591 break;
1592 default:
1593 empty_run = TRUE;
1594 }
1595
1596 count = core_audio_port->pcm_channels * core_audio_port->buffer_size;
1597
1598 g_rec_mutex_unlock(core_audio_port_mutex);
1599
1600 /* wait callback */
1601 is_playing = ags_soundcard_is_playing(AGS_SOUNDCARD(core_audio_devout));
1602
1603 if(is_playing){
1604 g_atomic_int_and(&(core_audio_devout->sync_flags),
1605 (~(AGS_CORE_AUDIO_DEVOUT_PASS_THROUGH)));
1606 }
1607
1608 no_event = TRUE;
1609
1610 if(is_playing){
1611 callback_mutex = &(core_audio_devout->callback_mutex);
1612
1613 /* give back computing time until ready */
1614 if((AGS_CORE_AUDIO_DEVOUT_INITIAL_CALLBACK & (g_atomic_int_get(&(core_audio_devout->sync_flags)))) == 0){
1615 g_mutex_lock(callback_mutex);
1616
1617 if((AGS_CORE_AUDIO_DEVOUT_CALLBACK_DONE & (g_atomic_int_get(&(core_audio_devout->sync_flags)))) == 0){
1618 g_atomic_int_or(&(core_audio_devout->sync_flags),
1619 AGS_CORE_AUDIO_DEVOUT_CALLBACK_WAIT);
1620
1621 while((AGS_CORE_AUDIO_DEVOUT_CALLBACK_DONE & (g_atomic_int_get(&(core_audio_devout->sync_flags)))) == 0 &&
1622 (AGS_CORE_AUDIO_DEVOUT_CALLBACK_WAIT & (g_atomic_int_get(&(core_audio_devout->sync_flags)))) != 0){
1623 g_cond_wait(&(core_audio_devout->callback_cond),
1624 callback_mutex);
1625 }
1626 }else{
1627 g_atomic_int_and(&(core_audio_devout->sync_flags),
1628 (~AGS_CORE_AUDIO_DEVOUT_INITIAL_CALLBACK));
1629 }
1630
1631 g_atomic_int_and(&(core_audio_devout->sync_flags),
1632 (~(AGS_CORE_AUDIO_DEVOUT_CALLBACK_WAIT |
1633 AGS_CORE_AUDIO_DEVOUT_CALLBACK_DONE)));
1634
1635 g_mutex_unlock(callback_mutex);
1636
1637 no_event = FALSE;
1638 }
1639 }
1640
1641 /* get buffer */
1642 g_rec_mutex_lock(device_mutex);
1643
1644 if((AGS_CORE_AUDIO_DEVOUT_BUFFER0 & (core_audio_devout->flags)) != 0){
1645 nth_buffer = 7;
1646 }else if((AGS_CORE_AUDIO_DEVOUT_BUFFER1 & (core_audio_devout->flags)) != 0){
1647 nth_buffer = 0;
1648 }else if((AGS_CORE_AUDIO_DEVOUT_BUFFER2 & (core_audio_devout->flags)) != 0){
1649 nth_buffer = 1;
1650 }else if((AGS_CORE_AUDIO_DEVOUT_BUFFER3 & (core_audio_devout->flags)) != 0){
1651 nth_buffer = 2;
1652 }else if((AGS_CORE_AUDIO_DEVOUT_BUFFER4 & (core_audio_devout->flags)) != 0){
1653 nth_buffer = 3;
1654 }else if((AGS_CORE_AUDIO_DEVOUT_BUFFER5 & (core_audio_devout->flags)) != 0){
1655 nth_buffer = 4;
1656 }else if((AGS_CORE_AUDIO_DEVOUT_BUFFER6 & (core_audio_devout->flags)) != 0){
1657 nth_buffer = 5;
1658 }else if((AGS_CORE_AUDIO_DEVOUT_BUFFER7 & (core_audio_devout->flags)) != 0){
1659 nth_buffer = 6;
1660 }else{
1661 empty_run = TRUE;
1662 }
1663
1664 switch(core_audio_port->format){
1665 case AGS_SOUNDCARD_SIGNED_8_BIT:
1666 {
1667 word_size = sizeof(gint8);
1668 }
1669 break;
1670 case AGS_SOUNDCARD_SIGNED_16_BIT:
1671 {
1672 word_size = sizeof(gint16);
1673 }
1674 break;
1675 case AGS_SOUNDCARD_SIGNED_24_BIT:
1676 {
1677 word_size = sizeof(gint32);
1678 }
1679 break;
1680 case AGS_SOUNDCARD_SIGNED_32_BIT:
1681 {
1682 word_size = sizeof(gint32);
1683 }
1684 break;
1685 case AGS_SOUNDCARD_SIGNED_64_BIT:
1686 {
1687 word_size = sizeof(gint64);
1688 }
1689 break;
1690 default:
1691 empty_run = TRUE;
1692 }
1693
1694 g_rec_mutex_unlock(device_mutex);
1695
1696 /* get copy mode */
1697 if(!empty_run &&
1698 is_playing){
1699 g_atomic_int_set(&(core_audio_port->is_empty),
1700 FALSE);
1701
1702 copy_mode = ags_audio_buffer_util_get_copy_mode(AGS_AUDIO_BUFFER_UTIL_S16,
1703 ags_audio_buffer_util_format_from_soundcard(core_audio_devout->format));
1704
1705 ags_soundcard_lock_buffer(AGS_SOUNDCARD(core_audio_devout), core_audio_devout->buffer[nth_buffer]);
1706
1707 ags_audio_buffer_util_copy_buffer_to_buffer(in_buffer->mAudioData, 1, 0,
1708 core_audio_devout->buffer[nth_buffer], 1, 0,
1709 core_audio_port->pcm_channels * core_audio_port->buffer_size, copy_mode);
1710
1711 ags_soundcard_unlock_buffer(AGS_SOUNDCARD(core_audio_devout), core_audio_devout->buffer[nth_buffer]);
1712 }
1713
1714 AudioQueueEnqueueBuffer(core_audio_port->aq_ref,
1715 in_buffer,
1716 0,
1717 NULL);
1718
1719 /* signal finish */
1720 if(!no_event){
1721 callback_finish_mutex = &(core_audio_devout->callback_finish_mutex);
1722
1723 g_mutex_lock(callback_finish_mutex);
1724
1725 g_atomic_int_or(&(core_audio_devout->sync_flags),
1726 AGS_CORE_AUDIO_DEVOUT_CALLBACK_FINISH_DONE);
1727
1728 if((AGS_CORE_AUDIO_DEVOUT_CALLBACK_FINISH_WAIT & (g_atomic_int_get(&(core_audio_devout->sync_flags)))) != 0){
1729 g_cond_signal(&(core_audio_devout->callback_finish_cond));
1730 }
1731
1732 g_mutex_unlock(callback_finish_mutex);
1733 }
1734
1735 if(empty_run){
1736 g_atomic_int_set(&(core_audio_port->is_empty),
1737 TRUE);
1738 }
1739
1740 g_atomic_int_dec_and_test(&(core_audio_port->queued));
1741
1742 /* unref */
1743 g_object_unref(audio_loop);
1744 }
1745
1746 void
ags_core_audio_port_handle_input_buffer(AgsCoreAudioPort * core_audio_port,AudioQueueRef in_audio_queue,AudioQueueBufferRef in_buffer,const AudioTimeStamp * in_start_time,UInt32 in_num_packets,const AudioStreamPacketDescription * in_packet_desc)1747 ags_core_audio_port_handle_input_buffer(AgsCoreAudioPort *core_audio_port,
1748 AudioQueueRef in_audio_queue, AudioQueueBufferRef in_buffer,
1749 const AudioTimeStamp *in_start_time, UInt32 in_num_packets,
1750 const AudioStreamPacketDescription *in_packet_desc)
1751 {
1752 AgsCoreAudioDevin *core_audio_devin;
1753
1754 AgsAudioLoop *audio_loop;
1755
1756 AgsApplicationContext *application_context;
1757
1758 guint word_size;
1759 guint nth_buffer;
1760 guint copy_mode;
1761 guint count;
1762 guint i;
1763 gboolean is_recording;
1764 gboolean pass_through;
1765 gboolean no_event;
1766 gboolean empty_run;
1767
1768 GRecMutex *core_audio_port_mutex;
1769 GRecMutex *device_mutex;
1770 GMutex *callback_mutex;
1771 GMutex *callback_finish_mutex;
1772
1773 if(core_audio_port == NULL){
1774 return;
1775 }
1776
1777 /* get core-audio port mutex */
1778 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
1779
1780 if(g_atomic_int_get(&(core_audio_port->queued)) > 0){
1781 g_warning("drop core audio output callback");
1782
1783 return;
1784 }else{
1785 g_atomic_int_inc(&(core_audio_port->queued));
1786 }
1787
1788 /*
1789 * process audio
1790 */
1791 /* */
1792 application_context = ags_application_context_get_instance();
1793
1794 audio_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
1795
1796 if(audio_loop == NULL){
1797 g_atomic_int_dec_and_test(&(core_audio_port->queued));
1798
1799 return;
1800 }
1801
1802 /* */
1803 g_rec_mutex_lock(core_audio_port_mutex);
1804
1805 core_audio_devin = core_audio_port->core_audio_device;
1806
1807 g_rec_mutex_unlock(core_audio_port_mutex);
1808
1809 /* get device mutex */
1810 device_mutex = AGS_CORE_AUDIO_DEVIN_GET_OBJ_MUTEX(core_audio_devin);
1811
1812 /* */
1813 g_rec_mutex_lock(core_audio_port_mutex);
1814
1815 empty_run = FALSE;
1816
1817 switch(core_audio_port->format){
1818 case AGS_SOUNDCARD_SIGNED_8_BIT:
1819 {
1820 word_size = sizeof(gint8);
1821 }
1822 break;
1823 case AGS_SOUNDCARD_SIGNED_16_BIT:
1824 {
1825 word_size = sizeof(gint16);
1826 }
1827 break;
1828 case AGS_SOUNDCARD_SIGNED_24_BIT:
1829 {
1830 word_size = sizeof(gint32);
1831 }
1832 break;
1833 case AGS_SOUNDCARD_SIGNED_32_BIT:
1834 {
1835 word_size = sizeof(gint32);
1836 }
1837 break;
1838 case AGS_SOUNDCARD_SIGNED_64_BIT:
1839 {
1840 word_size = sizeof(gint64);
1841 }
1842 break;
1843 default:
1844 empty_run = TRUE;
1845 }
1846
1847 count = core_audio_port->pcm_channels * core_audio_port->buffer_size;
1848
1849 g_rec_mutex_unlock(core_audio_port_mutex);
1850
1851 /* wait callback */
1852 is_recording = ags_soundcard_is_recording(AGS_SOUNDCARD(core_audio_devin));
1853
1854 if(is_recording){
1855 g_atomic_int_and(&(core_audio_devin->sync_flags),
1856 (~(AGS_CORE_AUDIO_DEVIN_PASS_THROUGH)));
1857 }
1858
1859 no_event = TRUE;
1860
1861 if(is_recording){
1862 callback_mutex = &(core_audio_devin->callback_mutex);
1863
1864 /* give back computing time until ready */
1865 if((AGS_CORE_AUDIO_DEVIN_INITIAL_CALLBACK & (g_atomic_int_get(&(core_audio_devin->sync_flags)))) == 0){
1866 g_mutex_lock(callback_mutex);
1867
1868 if((AGS_CORE_AUDIO_DEVIN_CALLBACK_DONE & (g_atomic_int_get(&(core_audio_devin->sync_flags)))) == 0){
1869 g_atomic_int_or(&(core_audio_devin->sync_flags),
1870 AGS_CORE_AUDIO_DEVIN_CALLBACK_WAIT);
1871
1872 while((AGS_CORE_AUDIO_DEVIN_CALLBACK_DONE & (g_atomic_int_get(&(core_audio_devin->sync_flags)))) == 0 &&
1873 (AGS_CORE_AUDIO_DEVIN_CALLBACK_WAIT & (g_atomic_int_get(&(core_audio_devin->sync_flags)))) != 0){
1874 g_cond_wait(&(core_audio_devin->callback_cond),
1875 callback_mutex);
1876 }
1877 }else{
1878 g_atomic_int_and(&(core_audio_devin->sync_flags),
1879 (~AGS_CORE_AUDIO_DEVIN_INITIAL_CALLBACK));
1880 }
1881
1882 g_atomic_int_and(&(core_audio_devin->sync_flags),
1883 (~(AGS_CORE_AUDIO_DEVIN_CALLBACK_WAIT |
1884 AGS_CORE_AUDIO_DEVIN_CALLBACK_DONE)));
1885
1886 g_mutex_unlock(callback_mutex);
1887
1888 no_event = FALSE;
1889 }
1890 }
1891
1892 /* get buffer */
1893 g_rec_mutex_lock(device_mutex);
1894
1895 if((AGS_CORE_AUDIO_DEVIN_BUFFER0 & (core_audio_devin->flags)) != 0){
1896 nth_buffer = 0;
1897 }else if((AGS_CORE_AUDIO_DEVIN_BUFFER1 & (core_audio_devin->flags)) != 0){
1898 nth_buffer = 1;
1899 }else if((AGS_CORE_AUDIO_DEVIN_BUFFER2 & (core_audio_devin->flags)) != 0){
1900 nth_buffer = 2;
1901 }else if((AGS_CORE_AUDIO_DEVIN_BUFFER3 & (core_audio_devin->flags)) != 0){
1902 nth_buffer = 3;
1903 }else if((AGS_CORE_AUDIO_DEVIN_BUFFER4 & (core_audio_devin->flags)) != 0){
1904 nth_buffer = 4;
1905 }else if((AGS_CORE_AUDIO_DEVIN_BUFFER5 & (core_audio_devin->flags)) != 0){
1906 nth_buffer = 5;
1907 }else if((AGS_CORE_AUDIO_DEVIN_BUFFER6 & (core_audio_devin->flags)) != 0){
1908 nth_buffer = 6;
1909 }else if((AGS_CORE_AUDIO_DEVIN_BUFFER7 & (core_audio_devin->flags)) != 0){
1910 nth_buffer = 7;
1911 }else{
1912 empty_run = TRUE;
1913 }
1914
1915 word_size = 0;
1916
1917 switch(core_audio_port->format){
1918 case AGS_SOUNDCARD_SIGNED_8_BIT:
1919 {
1920 word_size = sizeof(gint8);
1921 }
1922 break;
1923 case AGS_SOUNDCARD_SIGNED_16_BIT:
1924 {
1925 word_size = sizeof(gint16);
1926 }
1927 break;
1928 case AGS_SOUNDCARD_SIGNED_24_BIT:
1929 {
1930 word_size = sizeof(gint32);
1931 }
1932 break;
1933 case AGS_SOUNDCARD_SIGNED_32_BIT:
1934 {
1935 word_size = sizeof(gint32);
1936 }
1937 break;
1938 case AGS_SOUNDCARD_SIGNED_64_BIT:
1939 {
1940 word_size = sizeof(gint64);
1941 }
1942 break;
1943 default:
1944 empty_run = TRUE;
1945 }
1946
1947 g_rec_mutex_unlock(device_mutex);
1948
1949 /* get copy mode */
1950 if(!empty_run &&
1951 is_recording){
1952 g_atomic_int_set(&(core_audio_port->is_empty),
1953 FALSE);
1954
1955 copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(core_audio_devin->format),
1956 AGS_AUDIO_BUFFER_UTIL_S16);
1957
1958 #if 0
1959 g_message("%d: %x %x %x %x", core_audio_port->pcm_channels * core_audio_port->buffer_size,
1960 ((gint16 *) in_buffer->mAudioData)[0],
1961 ((gint16 *) in_buffer->mAudioData)[1],
1962 ((gint16 *) in_buffer->mAudioData)[2],
1963 ((gint16 *) in_buffer->mAudioData)[3]);
1964 #endif
1965
1966 ags_soundcard_lock_buffer(AGS_SOUNDCARD(core_audio_devin), core_audio_devin->buffer[nth_buffer]);
1967
1968 ags_audio_buffer_util_copy_buffer_to_buffer(core_audio_devin->buffer[nth_buffer], 1, 0,
1969 in_buffer->mAudioData, 1, 0,
1970 core_audio_port->pcm_channels * core_audio_port->buffer_size, copy_mode);
1971
1972 ags_soundcard_unlock_buffer(AGS_SOUNDCARD(core_audio_devin), core_audio_devin->buffer[nth_buffer]);
1973 }
1974
1975 in_buffer->mAudioDataByteSize = core_audio_port->pcm_channels * core_audio_port->buffer_size * sizeof(gint16);
1976 ags_audio_buffer_util_clear_buffer(in_buffer->mAudioData, 1,
1977 (in_buffer->mAudioDataByteSize / sizeof(gint16)), AGS_AUDIO_BUFFER_UTIL_S16);
1978 AudioQueueEnqueueBuffer(core_audio_port->record_aq_ref,
1979 in_buffer,
1980 0,
1981 NULL);
1982
1983 /* signal finish */
1984 if(!no_event){
1985 callback_finish_mutex = &(core_audio_devin->callback_finish_mutex);
1986
1987 g_mutex_lock(callback_finish_mutex);
1988
1989 g_atomic_int_or(&(core_audio_devin->sync_flags),
1990 AGS_CORE_AUDIO_DEVIN_CALLBACK_FINISH_DONE);
1991
1992 if((AGS_CORE_AUDIO_DEVIN_CALLBACK_FINISH_WAIT & (g_atomic_int_get(&(core_audio_devin->sync_flags)))) != 0){
1993 g_cond_signal(&(core_audio_devin->callback_finish_cond));
1994 }
1995
1996 g_mutex_unlock(callback_finish_mutex);
1997 }
1998
1999 if(empty_run){
2000 g_atomic_int_set(&(core_audio_port->is_empty),
2001 TRUE);
2002 }
2003
2004 g_atomic_int_dec_and_test(&(core_audio_port->queued));
2005
2006 /* unref */
2007 g_object_unref(audio_loop);
2008 }
2009
2010 void
ags_core_audio_port_midi_notify_callback(const MIDINotification * message,void * ref_con)2011 ags_core_audio_port_midi_notify_callback(const MIDINotification *message,
2012 void *ref_con)
2013 {
2014 //NOTE:JK: unused
2015 }
2016
2017 void
ags_core_audio_port_midi_read_callback(const MIDIPacketList * pkt_list,void * ref_con,void * conn_ref_con)2018 ags_core_audio_port_midi_read_callback(const MIDIPacketList *pkt_list,
2019 void *ref_con,
2020 void *conn_ref_con)
2021 {
2022 AgsCoreAudioPort *core_audio_port;
2023 AgsCoreAudioMidiin *core_audio_midiin;
2024
2025 AgsAudioLoop *audio_loop;
2026
2027 AgsApplicationContext *application_context;
2028
2029 MIDIPacket *packet;
2030
2031 guint nth_buffer;
2032 gint num_packets;
2033 gint i;
2034 gboolean no_event;
2035
2036 GRecMutex *core_audio_port_mutex;
2037 GRecMutex *device_mutex;
2038 GMutex *callback_mutex;
2039 GMutex *callback_finish_mutex;
2040
2041 core_audio_port = (AgsCoreAudioPort *) ref_con;
2042
2043 if(core_audio_port == NULL){
2044 return;
2045 }
2046
2047 /* get core-audio port mutex */
2048 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
2049
2050 /*
2051 * process midi
2052 */
2053 /* */
2054 application_context = ags_application_context_get_instance();
2055
2056 audio_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
2057
2058 /* */
2059 g_rec_mutex_lock(core_audio_port_mutex);
2060
2061 core_audio_midiin = core_audio_port->core_audio_device;
2062
2063 g_rec_mutex_unlock(core_audio_port_mutex);
2064
2065 /* get device mutex */
2066 device_mutex = AGS_CORE_AUDIO_MIDIIN_GET_OBJ_MUTEX(core_audio_midiin);
2067
2068 /* */
2069 g_rec_mutex_lock(device_mutex);
2070
2071 callback_mutex = &(core_audio_midiin->callback_mutex);
2072 callback_finish_mutex = &(core_audio_midiin->callback_finish_mutex);
2073
2074 /* wait callback */
2075 g_atomic_int_inc(&(core_audio_port->queued));
2076
2077 no_event = TRUE;
2078
2079 if((AGS_CORE_AUDIO_MIDIIN_PASS_THROUGH & (g_atomic_int_get(&(core_audio_midiin->sync_flags)))) == 0){
2080 g_rec_mutex_unlock(device_mutex);
2081
2082 /* force wait */
2083 g_atomic_int_or(&(core_audio_midiin->sync_flags),
2084 AGS_CORE_AUDIO_MIDIIN_DO_SYNC);
2085
2086 /* wait callback */
2087 g_mutex_lock(callback_mutex);
2088
2089 if((AGS_CORE_AUDIO_MIDIIN_CALLBACK_WAIT & (g_atomic_int_get(&(core_audio_midiin->sync_flags)))) != 0){
2090 g_atomic_int_and(&(core_audio_midiin->sync_flags),
2091 (~AGS_CORE_AUDIO_MIDIIN_CALLBACK_DONE));
2092
2093 while((AGS_CORE_AUDIO_MIDIIN_CALLBACK_DONE & (g_atomic_int_get(&(core_audio_midiin->sync_flags)))) == 0 &&
2094 (AGS_CORE_AUDIO_MIDIIN_CALLBACK_WAIT & (g_atomic_int_get(&(core_audio_midiin->sync_flags)))) != 0){
2095 g_cond_wait(&(core_audio_midiin->callback_cond),
2096 callback_mutex);
2097 }
2098 }
2099
2100 g_mutex_unlock(callback_mutex);
2101
2102 g_atomic_int_or(&(core_audio_midiin->sync_flags),
2103 (AGS_CORE_AUDIO_MIDIIN_CALLBACK_WAIT | AGS_CORE_AUDIO_MIDIIN_CALLBACK_DONE));
2104
2105 /* lock device */
2106 g_rec_mutex_lock(device_mutex);
2107
2108 no_event = FALSE;
2109 }else{
2110 g_atomic_int_set(&(core_audio_port->is_empty),
2111 TRUE);
2112 }
2113
2114 /* get buffer */
2115 if((AGS_CORE_AUDIO_MIDIIN_BUFFER0 & (core_audio_midiin->flags)) != 0){
2116 nth_buffer = 1;
2117 }else if((AGS_CORE_AUDIO_MIDIIN_BUFFER1 & (core_audio_midiin->flags)) != 0){
2118 nth_buffer = 2;
2119 }else if((AGS_CORE_AUDIO_MIDIIN_BUFFER2 & (core_audio_midiin->flags)) != 0){
2120 nth_buffer = 3;
2121 }else if((AGS_CORE_AUDIO_MIDIIN_BUFFER3 & (core_audio_midiin->flags)) != 0){
2122 nth_buffer = 0;
2123 }
2124
2125 packet = &pkt_list->packet[0];
2126 num_packets = pkt_list->numPackets;
2127
2128 for(i = 0; i < num_packets; i++){
2129 guint length;
2130
2131 length = packet->length;
2132
2133 if(length == 0){
2134 packet = MIDIPacketNext(packet);
2135
2136 continue;
2137 }
2138
2139 if(ceil((core_audio_midiin->buffer_size[nth_buffer] + length) / 4096.0) > ceil(core_audio_midiin->buffer_size[nth_buffer] / 4096.0)){
2140 if(core_audio_midiin->buffer[nth_buffer] == NULL){
2141 core_audio_midiin->buffer[nth_buffer] = malloc(4096 * sizeof(char));
2142 }else{
2143 core_audio_midiin->buffer[nth_buffer] = realloc(core_audio_midiin->buffer[nth_buffer],
2144 (ceil(core_audio_midiin->buffer_size[nth_buffer] / 4096.0) * 4096 + 4096) * sizeof(char));
2145 }
2146 }
2147
2148 memcpy(&(core_audio_midiin->buffer[nth_buffer][core_audio_midiin->buffer_size[nth_buffer]]),
2149 packet->data,
2150 length);
2151 core_audio_midiin->buffer_size[nth_buffer] += length;
2152
2153 packet = MIDIPacketNext(packet);
2154 }
2155
2156 /* signal finish */
2157 if(!no_event){
2158 g_rec_mutex_unlock(device_mutex);
2159
2160 /* signal client - wait callback finish */
2161 g_mutex_lock(callback_finish_mutex);
2162
2163 g_atomic_int_and(&(core_audio_midiin->sync_flags),
2164 (~AGS_CORE_AUDIO_MIDIIN_CALLBACK_FINISH_WAIT));
2165
2166 if((AGS_CORE_AUDIO_MIDIIN_CALLBACK_FINISH_DONE & (g_atomic_int_get(&(core_audio_midiin->sync_flags)))) == 0){
2167 g_cond_signal(&(core_audio_midiin->callback_finish_cond));
2168 }
2169
2170 g_mutex_unlock(callback_finish_mutex);
2171 }
2172
2173 g_atomic_int_dec_and_test(&(core_audio_port->queued));
2174 }
2175 #endif
2176
2177 void
ags_core_audio_port_set_format(AgsCoreAudioPort * core_audio_port,guint format)2178 ags_core_audio_port_set_format(AgsCoreAudioPort *core_audio_port,
2179 guint format)
2180 {
2181 GRecMutex *core_audio_port_mutex;
2182
2183 /* get core-audio port mutex */
2184 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
2185
2186 /* */
2187 g_rec_mutex_lock(core_audio_port_mutex);
2188
2189 core_audio_port->format = format;
2190
2191 g_rec_mutex_unlock(core_audio_port_mutex);
2192 }
2193
2194 void
ags_core_audio_port_set_samplerate(AgsCoreAudioPort * core_audio_port,guint samplerate)2195 ags_core_audio_port_set_samplerate(AgsCoreAudioPort *core_audio_port,
2196 guint samplerate)
2197 {
2198 GRecMutex *core_audio_port_mutex;
2199
2200 /* get core-audio port mutex */
2201 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
2202
2203 /* */
2204 g_rec_mutex_lock(core_audio_port_mutex);
2205
2206 #ifdef AGS_WITH_CORE_AUDIO
2207 core_audio_port->data_format.mSampleRate = (float) samplerate;
2208 #endif
2209
2210 core_audio_port->samplerate = samplerate;
2211
2212 g_rec_mutex_unlock(core_audio_port_mutex);
2213 }
2214
2215 void
ags_core_audio_port_set_buffer_size(AgsCoreAudioPort * core_audio_port,guint buffer_size)2216 ags_core_audio_port_set_buffer_size(AgsCoreAudioPort *core_audio_port,
2217 guint buffer_size)
2218 {
2219 GRecMutex *core_audio_port_mutex;
2220
2221 /* get core-audio port mutex */
2222 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
2223
2224 /* */
2225 g_rec_mutex_lock(core_audio_port_mutex);
2226
2227 #ifdef AGS_WITH_CORE_AUDIO
2228 //TODO:JK: implement me
2229 #endif
2230
2231 core_audio_port->buffer_size = buffer_size;
2232
2233 g_rec_mutex_unlock(core_audio_port_mutex);
2234 }
2235
2236 void
ags_core_audio_port_set_pcm_channels(AgsCoreAudioPort * core_audio_port,guint pcm_channels)2237 ags_core_audio_port_set_pcm_channels(AgsCoreAudioPort *core_audio_port,
2238 guint pcm_channels)
2239 {
2240 GRecMutex *core_audio_port_mutex;
2241
2242 /* get core-audio port mutex */
2243 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
2244
2245 /* */
2246 g_rec_mutex_lock(core_audio_port_mutex);
2247
2248 core_audio_port->pcm_channels = pcm_channels;
2249
2250 #ifdef AGS_WITH_CORE_AUDIO
2251 core_audio_port->data_format.mChannelsPerFrame = pcm_channels;
2252 #endif
2253
2254 g_rec_mutex_unlock(core_audio_port_mutex);
2255 }
2256
2257 void
ags_core_audio_port_set_cache_buffer_size(AgsCoreAudioPort * core_audio_port,guint cache_buffer_size)2258 ags_core_audio_port_set_cache_buffer_size(AgsCoreAudioPort *core_audio_port,
2259 guint cache_buffer_size)
2260 {
2261 GRecMutex *core_audio_port_mutex;
2262
2263 /* get core_audio port mutex */
2264 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
2265
2266 /* lock core_audio port */
2267 g_rec_mutex_lock(core_audio_port_mutex);
2268
2269 switch(core_audio_port->format){
2270 case AGS_SOUNDCARD_SIGNED_16_BIT:
2271 {
2272 core_audio_port->cache[0] = (void *) realloc(core_audio_port->cache[0],
2273 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2274 core_audio_port->cache[1] = (void *) realloc(core_audio_port->cache[1],
2275 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2276 core_audio_port->cache[2] = (void *) realloc(core_audio_port->cache[2],
2277 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2278 core_audio_port->cache[3] = (void *) realloc(core_audio_port->cache[3],
2279 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2280 }
2281 break;
2282 case AGS_SOUNDCARD_SIGNED_24_BIT:
2283 {
2284 core_audio_port->cache[0] = (void *) realloc(core_audio_port->cache[0],
2285 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2286 core_audio_port->cache[1] = (void *) realloc(core_audio_port->cache[1],
2287 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2288 core_audio_port->cache[2] = (void *) realloc(core_audio_port->cache[2],
2289 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2290 core_audio_port->cache[3] = (void *) realloc(core_audio_port->cache[3],
2291 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2292 }
2293 break;
2294 case AGS_SOUNDCARD_SIGNED_32_BIT:
2295 {
2296 core_audio_port->cache[0] = (void *) realloc(core_audio_port->cache[0],
2297 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2298 core_audio_port->cache[1] = (void *) realloc(core_audio_port->cache[1],
2299 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2300 core_audio_port->cache[2] = (void *) realloc(core_audio_port->cache[2],
2301 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2302 core_audio_port->cache[3] = (void *) realloc(core_audio_port->cache[3],
2303 core_audio_port->pcm_channels * core_audio_port->cache_buffer_size * sizeof(gint32));
2304 }
2305 break;
2306 default:
2307 g_warning("core_audio devout - unsupported format");
2308 }
2309
2310 g_rec_mutex_unlock(core_audio_port_mutex);
2311 }
2312
2313 /**
2314 * ags_core_audio_port_get_latency:
2315 * @core_audio_port: the #AgsCoreAudioPort
2316 *
2317 * Gets latency.
2318 *
2319 * Since: 3.0.0
2320 */
2321 guint
ags_core_audio_port_get_latency(AgsCoreAudioPort * core_audio_port)2322 ags_core_audio_port_get_latency(AgsCoreAudioPort *core_audio_port)
2323 {
2324 guint latency;
2325
2326 GRecMutex *core_audio_port_mutex;
2327
2328 /* get core_audio port mutex */
2329 core_audio_port_mutex = AGS_CORE_AUDIO_PORT_GET_OBJ_MUTEX(core_audio_port);
2330
2331 /* lock core_audio port */
2332 g_rec_mutex_lock(core_audio_port_mutex);
2333
2334 latency = 0;
2335
2336 #ifdef AGS_WITH_CORE_AUDIO
2337 if(core_audio_port->use_cache){
2338 latency = (guint) floor((gdouble) NSEC_PER_SEC / (gdouble) core_audio_port->samplerate * (gdouble) core_audio_port->cache_buffer_size);
2339 }else{
2340 latency = (guint) floor((gdouble) NSEC_PER_SEC / (gdouble) core_audio_port->samplerate * (gdouble) core_audio_port->buffer_size);
2341 }
2342 #endif
2343
2344 g_rec_mutex_unlock(core_audio_port_mutex);
2345
2346 return(latency);
2347 }
2348
2349 /**
2350 * ags_core_audio_port_new:
2351 * @core_audio_client: the #AgsCoreAudioClient assigned to
2352 *
2353 * Create a new instance of #AgsCoreAudioPort.
2354 *
2355 * Returns: the new #AgsCoreAudioPort
2356 *
2357 * Since: 3.0.0
2358 */
2359 AgsCoreAudioPort*
ags_core_audio_port_new(GObject * core_audio_client)2360 ags_core_audio_port_new(GObject *core_audio_client)
2361 {
2362 AgsCoreAudioPort *core_audio_port;
2363
2364 core_audio_port = (AgsCoreAudioPort *) g_object_new(AGS_TYPE_CORE_AUDIO_PORT,
2365 "core-audio-client", core_audio_client,
2366 NULL);
2367
2368 return(core_audio_port);
2369 }
2370