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