1 /* FluidSynth - A Software Synthesizer
2 *
3 * Copyright (C) 2003 Peter Hanappe and others.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 */
20
21 /* fluid_coreaudio.c
22 *
23 * Driver for the Apple's CoreAudio on MacOS X
24 *
25 */
26
27 #include "fluid_adriver.h"
28 #include "fluid_settings.h"
29
30 /*
31 * !!! Make sure that no include above includes <netinet/tcp.h> !!!
32 * It #defines some macros that collide with enum definitions of OpenTransportProviders.h, which is included from OSServices.h, included from CoreServices.h
33 *
34 * https://trac.macports.org/ticket/36962
35 */
36
37 #if COREAUDIO_SUPPORT
38 #include <CoreServices/CoreServices.h>
39 #include <CoreAudio/CoreAudioTypes.h>
40 #include <CoreAudio/AudioHardware.h>
41 #include <AudioUnit/AudioUnit.h>
42
43 /*
44 * fluid_core_audio_driver_t
45 *
46 */
47 typedef struct
48 {
49 fluid_audio_driver_t driver;
50 AudioUnit outputUnit;
51 AudioStreamBasicDescription format;
52 fluid_audio_func_t callback;
53 void *data;
54 unsigned int buffer_size;
55 float *buffers[2];
56 double phase;
57 } fluid_core_audio_driver_t;
58
59
60 OSStatus fluid_core_audio_callback(void *data,
61 AudioUnitRenderActionFlags *ioActionFlags,
62 const AudioTimeStamp *inTimeStamp,
63 UInt32 inBusNumber,
64 UInt32 inNumberFrames,
65 AudioBufferList *ioData);
66
67
68 /**************************************************************
69 *
70 * CoreAudio audio driver
71 *
72 */
73
74 #define OK(x) (x == noErr)
75
76 int
get_num_outputs(AudioDeviceID deviceID)77 get_num_outputs(AudioDeviceID deviceID)
78 {
79 int i, total = 0;
80 UInt32 size;
81 AudioObjectPropertyAddress pa;
82 pa.mSelector = kAudioDevicePropertyStreamConfiguration;
83 pa.mScope = kAudioDevicePropertyScopeOutput;
84 pa.mElement = kAudioObjectPropertyElementMaster;
85
86 if(OK(AudioObjectGetPropertyDataSize(deviceID, &pa, 0, 0, &size)) && size > 0)
87 {
88 AudioBufferList *bufList = FLUID_MALLOC(size);
89
90 if(bufList == NULL)
91 {
92 FLUID_LOG(FLUID_ERR, "Out of memory");
93 return 0;
94 }
95
96 if(OK(AudioObjectGetPropertyData(deviceID, &pa, 0, 0, &size, bufList)))
97 {
98 int numStreams = bufList->mNumberBuffers;
99
100 for(i = 0; i < numStreams; ++i)
101 {
102 AudioBuffer b = bufList->mBuffers[i];
103 total += b.mNumberChannels;
104 }
105 }
106
107 FLUID_FREE(bufList);
108 }
109
110 return total;
111 }
112
113 void
fluid_core_audio_driver_settings(fluid_settings_t * settings)114 fluid_core_audio_driver_settings(fluid_settings_t *settings)
115 {
116 int i;
117 UInt32 size;
118 AudioObjectPropertyAddress pa;
119 pa.mSelector = kAudioHardwarePropertyDevices;
120 pa.mScope = kAudioObjectPropertyScopeWildcard;
121 pa.mElement = kAudioObjectPropertyElementMaster;
122
123 fluid_settings_register_str(settings, "audio.coreaudio.device", "default", 0);
124 fluid_settings_add_option(settings, "audio.coreaudio.device", "default");
125
126 if(OK(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa, 0, 0, &size)))
127 {
128 int num = size / (int) sizeof(AudioDeviceID);
129 AudioDeviceID devs [num];
130
131 if(OK(AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa, 0, 0, &size, devs)))
132 {
133 for(i = 0; i < num; ++i)
134 {
135 char name [1024];
136 size = sizeof(name);
137 pa.mSelector = kAudioDevicePropertyDeviceName;
138
139 if(OK(AudioObjectGetPropertyData(devs[i], &pa, 0, 0, &size, name)))
140 {
141 if(get_num_outputs(devs[i]) > 0)
142 {
143 fluid_settings_add_option(settings, "audio.coreaudio.device", name);
144 }
145 }
146 }
147 }
148 }
149 }
150
151 /*
152 * new_fluid_core_audio_driver
153 */
154 fluid_audio_driver_t *
new_fluid_core_audio_driver(fluid_settings_t * settings,fluid_synth_t * synth)155 new_fluid_core_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
156 {
157 return new_fluid_core_audio_driver2(settings,
158 NULL,
159 synth);
160 }
161
162 /*
163 * new_fluid_core_audio_driver2
164 */
165 fluid_audio_driver_t *
new_fluid_core_audio_driver2(fluid_settings_t * settings,fluid_audio_func_t func,void * data)166 new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)
167 {
168 char *devname = NULL;
169 fluid_core_audio_driver_t *dev = NULL;
170 int period_size, periods;
171 double sample_rate;
172 OSStatus status;
173 UInt32 size;
174 int i;
175
176 dev = FLUID_NEW(fluid_core_audio_driver_t);
177
178 if(dev == NULL)
179 {
180 FLUID_LOG(FLUID_ERR, "Out of memory");
181 return NULL;
182 }
183
184 FLUID_MEMSET(dev, 0, sizeof(fluid_core_audio_driver_t));
185
186 dev->callback = func;
187 dev->data = data;
188
189 // Open the default output unit
190 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
191 ComponentDescription desc;
192 #else
193 AudioComponentDescription desc;
194 #endif
195 desc.componentType = kAudioUnitType_Output;
196 desc.componentSubType = kAudioUnitSubType_HALOutput; //kAudioUnitSubType_DefaultOutput;
197 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
198 desc.componentFlags = 0;
199 desc.componentFlagsMask = 0;
200
201 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
202 Component comp = FindNextComponent(NULL, &desc);
203 #else
204 AudioComponent comp = AudioComponentFindNext(NULL, &desc);
205 #endif
206
207 if(comp == NULL)
208 {
209 FLUID_LOG(FLUID_ERR, "Failed to get the default audio device");
210 goto error_recovery;
211 }
212
213 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
214 status = OpenAComponent(comp, &dev->outputUnit);
215 #else
216 status = AudioComponentInstanceNew(comp, &dev->outputUnit);
217 #endif
218
219 if(status != noErr)
220 {
221 FLUID_LOG(FLUID_ERR, "Failed to open the default audio device. Status=%ld\n", (long int)status);
222 goto error_recovery;
223 }
224
225 // Set up a callback function to generate output
226 AURenderCallbackStruct render;
227 render.inputProc = fluid_core_audio_callback;
228 render.inputProcRefCon = (void *) dev;
229 status = AudioUnitSetProperty(dev->outputUnit,
230 kAudioUnitProperty_SetRenderCallback,
231 kAudioUnitScope_Input,
232 0,
233 &render,
234 sizeof(render));
235
236 if(status != noErr)
237 {
238 FLUID_LOG(FLUID_ERR, "Error setting the audio callback. Status=%ld\n", (long int)status);
239 goto error_recovery;
240 }
241
242 fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
243 fluid_settings_getint(settings, "audio.periods", &periods);
244 fluid_settings_getint(settings, "audio.period-size", &period_size);
245
246 /* get the selected device name. if none is specified, use NULL for the default device. */
247 if(fluid_settings_dupstr(settings, "audio.coreaudio.device", &devname) == FLUID_OK /* alloc device name */
248 && devname && strlen(devname) > 0)
249 {
250 AudioObjectPropertyAddress pa;
251 pa.mSelector = kAudioHardwarePropertyDevices;
252 pa.mScope = kAudioObjectPropertyScopeWildcard;
253 pa.mElement = kAudioObjectPropertyElementMaster;
254
255 if(OK(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa, 0, 0, &size)))
256 {
257 int num = size / (int) sizeof(AudioDeviceID);
258 AudioDeviceID devs [num];
259
260 if(OK(AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa, 0, 0, &size, devs)))
261 {
262 for(i = 0; i < num; ++i)
263 {
264 char name [1024];
265 size = sizeof(name);
266 pa.mSelector = kAudioDevicePropertyDeviceName;
267
268 if(OK(AudioObjectGetPropertyData(devs[i], &pa, 0, 0, &size, name)))
269 {
270 if(get_num_outputs(devs[i]) > 0 && FLUID_STRCASECMP(devname, name) == 0)
271 {
272 AudioDeviceID selectedID = devs[i];
273 status = AudioUnitSetProperty(dev->outputUnit,
274 kAudioOutputUnitProperty_CurrentDevice,
275 kAudioUnitScope_Global,
276 0,
277 &selectedID,
278 sizeof(AudioDeviceID));
279
280 if(status != noErr)
281 {
282 FLUID_LOG(FLUID_ERR, "Error setting the selected output device. Status=%ld\n", (long int)status);
283 goto error_recovery;
284 }
285 }
286 }
287 }
288 }
289 }
290 }
291
292 FLUID_FREE(devname); /* free device name */
293
294 dev->buffer_size = period_size * periods;
295
296 // The DefaultOutputUnit should do any format conversions
297 // necessary from our format to the device's format.
298 dev->format.mSampleRate = sample_rate; // sample rate of the audio stream
299 dev->format.mFormatID = kAudioFormatLinearPCM; // encoding type of the audio stream
300 dev->format.mFormatFlags = kLinearPCMFormatFlagIsFloat;
301 dev->format.mBytesPerPacket = 2 * sizeof(float);
302 dev->format.mFramesPerPacket = 1;
303 dev->format.mBytesPerFrame = 2 * sizeof(float);
304 dev->format.mChannelsPerFrame = 2;
305 dev->format.mBitsPerChannel = 8 * sizeof(float);
306
307 FLUID_LOG(FLUID_DBG, "mSampleRate %g", dev->format.mSampleRate);
308 FLUID_LOG(FLUID_DBG, "mFormatFlags %08X", dev->format.mFormatFlags);
309 FLUID_LOG(FLUID_DBG, "mBytesPerPacket %d", dev->format.mBytesPerPacket);
310 FLUID_LOG(FLUID_DBG, "mFramesPerPacket %d", dev->format.mFramesPerPacket);
311 FLUID_LOG(FLUID_DBG, "mChannelsPerFrame %d", dev->format.mChannelsPerFrame);
312 FLUID_LOG(FLUID_DBG, "mBytesPerFrame %d", dev->format.mBytesPerFrame);
313 FLUID_LOG(FLUID_DBG, "mBitsPerChannel %d", dev->format.mBitsPerChannel);
314
315 status = AudioUnitSetProperty(dev->outputUnit,
316 kAudioUnitProperty_StreamFormat,
317 kAudioUnitScope_Input,
318 0,
319 &dev->format,
320 sizeof(AudioStreamBasicDescription));
321
322 if(status != noErr)
323 {
324 FLUID_LOG(FLUID_ERR, "Error setting the audio format. Status=%ld\n", (long int)status);
325 goto error_recovery;
326 }
327
328 status = AudioUnitSetProperty(dev->outputUnit,
329 kAudioUnitProperty_MaximumFramesPerSlice,
330 kAudioUnitScope_Input,
331 0,
332 &dev->buffer_size,
333 sizeof(unsigned int));
334
335 if(status != noErr)
336 {
337 FLUID_LOG(FLUID_ERR, "Failed to set the MaximumFramesPerSlice. Status=%ld\n", (long int)status);
338 goto error_recovery;
339 }
340
341 FLUID_LOG(FLUID_DBG, "MaximumFramesPerSlice = %d", dev->buffer_size);
342
343 dev->buffers[0] = FLUID_ARRAY(float, dev->buffer_size);
344 dev->buffers[1] = FLUID_ARRAY(float, dev->buffer_size);
345
346 if(dev->buffers[0] == NULL || dev->buffers[1] == NULL)
347 {
348 FLUID_LOG(FLUID_ERR, "Out of memory.");
349 goto error_recovery;
350 }
351
352 // Initialize the audio unit
353 status = AudioUnitInitialize(dev->outputUnit);
354
355 if(status != noErr)
356 {
357 FLUID_LOG(FLUID_ERR, "Error calling AudioUnitInitialize(). Status=%ld\n", (long int)status);
358 goto error_recovery;
359 }
360
361 // Start the rendering
362 status = AudioOutputUnitStart(dev->outputUnit);
363
364 if(status != noErr)
365 {
366 FLUID_LOG(FLUID_ERR, "Error calling AudioOutputUnitStart(). Status=%ld\n", (long int)status);
367 goto error_recovery;
368 }
369
370 return (fluid_audio_driver_t *) dev;
371
372 error_recovery:
373
374 delete_fluid_core_audio_driver((fluid_audio_driver_t *) dev);
375 return NULL;
376 }
377
378 /*
379 * delete_fluid_core_audio_driver
380 */
381 void
delete_fluid_core_audio_driver(fluid_audio_driver_t * p)382 delete_fluid_core_audio_driver(fluid_audio_driver_t *p)
383 {
384 fluid_core_audio_driver_t *dev = (fluid_core_audio_driver_t *) p;
385 fluid_return_if_fail(dev != NULL);
386
387 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
388 CloseComponent(dev->outputUnit);
389 #else
390 AudioComponentInstanceDispose(dev->outputUnit);
391 #endif
392
393 if(dev->buffers[0])
394 {
395 FLUID_FREE(dev->buffers[0]);
396 }
397
398 if(dev->buffers[1])
399 {
400 FLUID_FREE(dev->buffers[1]);
401 }
402
403 FLUID_FREE(dev);
404 }
405
406 OSStatus
fluid_core_audio_callback(void * data,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)407 fluid_core_audio_callback(void *data,
408 AudioUnitRenderActionFlags *ioActionFlags,
409 const AudioTimeStamp *inTimeStamp,
410 UInt32 inBusNumber,
411 UInt32 inNumberFrames,
412 AudioBufferList *ioData)
413 {
414 int i, k;
415 fluid_core_audio_driver_t *dev = (fluid_core_audio_driver_t *) data;
416 int len = inNumberFrames;
417 float *buffer = ioData->mBuffers[0].mData;
418
419 if(dev->callback)
420 {
421 float *left = dev->buffers[0];
422 float *right = dev->buffers[1];
423
424 FLUID_MEMSET(left, 0, len * sizeof(float));
425 FLUID_MEMSET(right, 0, len * sizeof(float));
426
427 (*dev->callback)(dev->data, len, 0, NULL, 2, dev->buffers);
428
429 for(i = 0, k = 0; i < len; i++)
430 {
431 buffer[k++] = left[i];
432 buffer[k++] = right[i];
433 }
434 }
435 else
436 fluid_synth_write_float((fluid_synth_t *) dev->data, len, buffer, 0, 2,
437 buffer, 1, 2);
438
439 return noErr;
440 }
441
442
443 #endif /* #if COREAUDIO_SUPPORT */
444