2222#include "../../verbosity.h"
2323
2424#define CORE_MIDI_QUEUE_SIZE 1024
25+ #define CORE_MIDI_MAX_EVENT_SIZE 256
26+
27+ /* Persistent CoreMIDI client shared across all driver instances.
28+ * This avoids XPC race conditions from rapid client dispose/recreate cycles.
29+ * CoreMIDI clients are designed to be long-lived; ports are disposable. */
30+ static MIDIClientRef shared_midi_client = 0 ;
31+
32+ typedef struct
33+ {
34+ uint8_t data [CORE_MIDI_MAX_EVENT_SIZE ]; /* Inline data buffer */
35+ size_t data_size ;
36+ uint32_t delta_time ;
37+ } coremidi_event_t ;
2538
2639typedef struct
2740{
28- midi_event_t events [CORE_MIDI_QUEUE_SIZE ]; /* Event buffer */
41+ coremidi_event_t events [CORE_MIDI_QUEUE_SIZE ]; /* Event buffer */
2942 int read_index ; /* Current read position */
3043 int write_index ; /* Current write position */
3144} coremidi_queue_t ;
@@ -43,11 +56,21 @@ typedef struct
4356/* Write to the queue */
4457static bool coremidi_queue_write (coremidi_queue_t * q , const midi_event_t * ev )
4558{
59+ size_t copy_size ;
4660 int next_write = (q -> write_index + 1 ) % CORE_MIDI_QUEUE_SIZE ;
4761 if (next_write == q -> read_index ) /* Queue full */
4862 return false;
4963
50- memcpy (& q -> events [q -> write_index ], ev , sizeof (* ev ));
64+ /* Validate event data size */
65+ if (!ev -> data || ev -> data_size == 0 || ev -> data_size > CORE_MIDI_MAX_EVENT_SIZE )
66+ return false;
67+
68+ /* Copy data inline instead of storing pointer */
69+ copy_size = ev -> data_size ;
70+ memcpy (q -> events [q -> write_index ].data , ev -> data , copy_size );
71+ q -> events [q -> write_index ].data_size = copy_size ;
72+ q -> events [q -> write_index ].delta_time = ev -> delta_time ;
73+
5174 q -> write_index = next_write ;
5275 return true;
5376}
@@ -92,23 +115,30 @@ static void midi_read_callback(const MIDIPacketList *pktlist,
92115static void * coremidi_init (const char * input , const char * output )
93116{
94117 OSStatus err ;
95- coremidi_t * d = (coremidi_t * )calloc (1 , sizeof (coremidi_t ));
96- if (!d )
118+ coremidi_t * d ;
119+
120+ /* Create persistent client on first call */
121+ if (!shared_midi_client )
97122 {
98- RARCH_ERR ("[MIDI] Out of memory.\n" );
99- return NULL ;
123+ err = MIDIClientCreate (CFSTR ("RetroArch MIDI Client" ),
124+ NULL , NULL , & shared_midi_client );
125+ if (err != noErr )
126+ {
127+ RARCH_ERR ("[MIDI] MIDIClientCreate failed: %d.\n" , err );
128+ return NULL ;
129+ }
130+ RARCH_LOG ("[MIDI] Created persistent CoreMIDI client.\n" );
100131 }
101132
102- err = MIDIClientCreate (CFSTR ("RetroArch MIDI Client" ),
103- NULL , NULL , & d -> client );
104- if (err != noErr )
133+ d = (coremidi_t * )calloc (1 , sizeof (coremidi_t ));
134+ if (!d )
105135 {
106- RARCH_ERR ("[MIDI] MIDIClientCreate failed: %d.\n" , err );
107- free (d );
136+ RARCH_ERR ("[MIDI] Out of memory.\n" );
108137 return NULL ;
109138 }
110139
111- RARCH_LOG ("[MIDI] CoreMIDI client created successfully.\n" );
140+ /* Store reference to shared client */
141+ d -> client = shared_midi_client ;
112142
113143 /* Create input port if specified */
114144 if (input )
@@ -118,13 +148,9 @@ static void *coremidi_init(const char *input, const char *output)
118148 if (err != noErr )
119149 {
120150 RARCH_ERR ("[MIDI] MIDIInputPortCreate failed: %d.\n" , err );
121- MIDIClientDispose (d -> client );
122151 free (d );
123152 return NULL ;
124153 }
125- }
126- else
127- {
128154 RARCH_LOG ("[MIDI] CoreMIDI input port created successfully.\n" );
129155 }
130156
@@ -138,13 +164,9 @@ static void *coremidi_init(const char *input, const char *output)
138164 RARCH_ERR ("[MIDI] MIDIOutputPortCreate failed: %d.\n" , err );
139165 if (d -> input_port )
140166 MIDIPortDispose (d -> input_port );
141- MIDIClientDispose (d -> client );
142167 free (d );
143168 return NULL ;
144169 }
145- }
146- else
147- {
148170 RARCH_LOG ("[MIDI] CoreMIDI output port created successfully.\n" );
149171 }
150172
@@ -331,7 +353,11 @@ static bool coremidi_queue_read(coremidi_queue_t *q, midi_event_t *ev)
331353 if (q -> read_index == q -> write_index ) /* Queue empty */
332354 return false;
333355
334- memcpy (ev , & q -> events [q -> read_index ], sizeof (* ev ));
356+ /* Return pointer to inline data buffer */
357+ ev -> data = q -> events [q -> read_index ].data ;
358+ ev -> data_size = q -> events [q -> read_index ].data_size ;
359+ ev -> delta_time = q -> events [q -> read_index ].delta_time ;
360+
335361 q -> read_index = (q -> read_index + 1 ) % CORE_MIDI_QUEUE_SIZE ;
336362 return true;
337363}
@@ -443,23 +469,18 @@ static void coremidi_free(void *p)
443469 /* Clean up MIDI resources */
444470 if (d -> input_port )
445471 {
446- RARCH_LOG ("[MIDI] Disconnecting input port...\n" );
447- MIDIPortDisconnectSource (d -> input_port , d -> input_endpoint );
472+ RARCH_LOG ("[MIDI] Disconnecting and disposing input port...\n" );
473+ if (d -> input_endpoint )
474+ MIDIPortDisconnectSource (d -> input_port , d -> input_endpoint );
448475 MIDIPortDispose (d -> input_port );
449476 }
450477
451478 if (d -> output_port )
452479 {
453- RARCH_LOG ("[MIDI] Disconnecting output port...\n" );
454- MIDIPortDisconnectSource (d -> output_port , d -> output_endpoint );
480+ RARCH_LOG ("[MIDI] Disposing output port...\n" );
455481 MIDIPortDispose (d -> output_port );
456482 }
457483
458- if (d -> client )
459- {
460- RARCH_LOG ("[MIDI] Disposing of CoreMIDI client...\n" );
461- MIDIClientDispose (d -> client );
462- }
463484
464485 /* Free the driver instance */
465486 free (d );
0 commit comments