1 /*
2 rtauhal.c:
3
4 Copyright (C) 2011 Victor Lazzarini
5
6 This file is part of Csound.
7
8 The Csound Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 Csound is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with Csound; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 #include <AudioUnit/AudioUnit.h>
25 #include <CoreAudio/AudioHardware.h>
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include "csdl.h"
30 #include "soundio.h"
31
32 /* Modified from BSD sources for strlcpy */
33 /*
34 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
35 *
36 * Permission to use, copy, modify, and distribute this software for any
37 * purpose with or without fee is hereby granted, provided that the above
38 * copyright notice and this permission notice appear in all copies.
39 */
40 /* modifed for speed -- JPff */
41 char *
strNcpy(char * dst,const char * src,size_t siz)42 strNcpy(char *dst, const char *src, size_t siz)
43 {
44 char *d = dst;
45 const char *s = src;
46 size_t n = siz;
47
48 /* Copy as many bytes as will fit or until NULL */
49 if (n != 0) {
50 while (--n != 0) {
51 if ((*d++ = *s++) == '\0')
52 break;
53 }
54 }
55
56 /* Not enough room in dst, add NUL */
57 if (n == 0) {
58 if (siz != 0)
59 *d = '\0'; /* NUL-terminate dst */
60
61 //while (*s++) ;
62 }
63 return dst; /* count does not include NUL */
64 }
65
66 #if !defined(MAC_OS_X_VERSION_10_6)
67 /* the API was changed for 10.6, these make it backwards compatible */
68 typedef ComponentInstance AudioComponentInstance;
69 typedef Component AudioComponent;
70 typedef ComponentDescription AudioComponentDescription;
71 #define AudioComponentFindNext FindNextComponent
72 #define AudioComponentInstanceNew OpenAComponent
73 #define AudioComponentInstanceDispose CloseComponent
74 typedef float AudioUnitSampleType;
75 #endif
76
77
78 typedef struct {
79 char name[128];
80 int outchannels;
81 int inchannels;
82 int indevnum;
83 int outdevnum;
84 } Device_Info;
85
86
87 typedef struct csdata_ {
88 AudioDeviceID dev;
89 AudioStreamBasicDescription format;
90 int inBufSamples;
91 int outBufSamples;
92 int currentInputIndex;
93 int currentOutputIndex;
94 MYFLT *inputBuffer;
95 MYFLT *outputBuffer;
96 csRtAudioParams *inParm;
97 csRtAudioParams *outParm;
98 int onchnls, inchnls;
99 AudioComponentInstance outunit;
100 AudioComponentInstance inunit;
101 CSOUND *csound;
102 AudioBufferList *inputdata;
103 int disp;
104 AudioDeviceID defdevin;
105 AudioDeviceID defdevout;
106 int devnos;
107 int devin;
108 int devout;
109 void *incb;
110 void *outcb;
111 } csdata;
112
113
114 OSStatus Csound_Input(void *inRefCon,
115 AudioUnitRenderActionFlags *ioActionFlags,
116 const AudioTimeStamp *inTimeStamp,
117 UInt32 inBusNumber,
118 UInt32 inNumberFrames,
119 AudioBufferList *ioData);
120
121 OSStatus Csound_Render(void *inRefCon,
122 AudioUnitRenderActionFlags *ioActionFlags,
123 const AudioTimeStamp *inTimeStamp,
124 UInt32 dump,
125 UInt32 inNumberFrames,
126 AudioBufferList *ioData);
127
DAC_channels(CSOUND * csound,int chans)128 static void DAC_channels(CSOUND *csound, int chans){
129 int *dachans = (int *) csound->QueryGlobalVariable(csound, "_DAC_CHANNELS_");
130 if (dachans == NULL) {
131 if (csound->CreateGlobalVariable(csound, "_DAC_CHANNELS_",
132 sizeof(int)) != 0)
133 return;
134 dachans = (int *) csound->QueryGlobalVariable(csound, "_DAC_CHANNELS_");
135 *dachans = chans;
136 }
137 }
138
ADC_channels(CSOUND * csound,int chans)139 static void ADC_channels(CSOUND *csound, int chans){
140 int *dachans = (int *) csound->QueryGlobalVariable(csound, "_ADC_CHANNELS_");
141 if (dachans == NULL) {
142 if (csound->CreateGlobalVariable(csound, "_ADC_CHANNELS_",
143 sizeof(int)) != 0)
144 return;
145 dachans = (int *) csound->QueryGlobalVariable(csound, "_ADC_CHANNELS_");
146 *dachans = chans;
147 }
148 }
149
AuHAL_open(CSOUND * csound,const csRtAudioParams * parm,csdata * cdata,int isInput)150 int AuHAL_open(CSOUND *csound, const csRtAudioParams * parm,
151 csdata *cdata, int isInput)
152 {
153 UInt32 psize, devnum, devnos;
154 AudioDeviceID dev;
155 AudioDeviceID *sysdevs;
156 AudioStreamBasicDescription format;
157 int i;
158 Device_Info *devinfo;
159 UInt32 bufframes, nchnls;
160 int devouts = 0, devins = 0;
161 double srate;
162 UInt32 enableIO, maxFPS;
163 AudioComponent HALOutput;
164 AudioComponentInstance *aunit;
165 AudioComponentDescription cd = {kAudioUnitType_Output,
166 kAudioUnitSubType_HALOutput,
167 kAudioUnitManufacturer_Apple, 0, 0};
168 AudioObjectPropertyAddress prop = {
169 kAudioObjectPropertyName,
170 kAudioObjectPropertyScopeGlobal,
171 kAudioObjectPropertyElementMaster
172 };
173 CFStringRef devName;
174 CFStringEncoding defaultEncoding = CFStringGetSystemEncoding();
175
176
177
178 prop.mSelector = (isInput ?
179 kAudioHardwarePropertyDefaultInputDevice :
180 kAudioHardwarePropertyDefaultOutputDevice);
181
182 psize = sizeof(AudioDeviceID);
183 AudioObjectGetPropertyData(kAudioObjectSystemObject,
184 &prop, 0, NULL, &psize, &dev);
185
186 if(isInput) cdata->defdevin = dev;
187 else cdata->defdevout = dev;
188
189 prop.mSelector = kAudioHardwarePropertyDevices;
190 AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
191 &prop, 0, NULL, &psize);
192 devnos = psize / sizeof(AudioDeviceID);
193 sysdevs = (AudioDeviceID *) csound->Malloc(csound,psize);
194 devinfo = (Device_Info *) csound->Malloc(csound,devnos*sizeof(Device_Info));
195 AudioObjectGetPropertyData(kAudioObjectSystemObject,
196 &prop, 0, NULL, &psize, sysdevs);
197
198 cdata->devnos = devnos;
199 for (i = 0; (unsigned int) i < devnos; i++) {
200 AudioBufferList *b;
201 int devchannels, k, n;
202 int numlists;
203 psize = sizeof(CFStringRef);
204 prop.mScope = kAudioObjectPropertyScopeGlobal;
205 prop.mSelector = kAudioObjectPropertyName;
206 AudioObjectGetPropertyData(sysdevs[i],
207 &prop, 0, NULL, &psize, &devName);
208 if(CFStringGetCStringPtr(devName, defaultEncoding))
209 strNcpy(devinfo[i].name,
210 CFStringGetCStringPtr(devName, defaultEncoding), 127);
211 else
212 strNcpy(devinfo[i].name, "unnamed device", 127);
213 CFRelease(devName);
214
215 devchannels = 0;
216 prop.mScope = kAudioDevicePropertyScopeInput;
217 prop.mSelector = kAudioDevicePropertyStreamConfiguration;
218 AudioObjectGetPropertyDataSize(sysdevs[i],
219 &prop, 0, NULL, &psize);
220 b = (AudioBufferList *) csound->Malloc(csound,psize);
221 numlists = psize / sizeof(AudioBufferList);
222 AudioObjectGetPropertyData(sysdevs[i],
223 &prop, 0, NULL, &psize, b);
224 for(n=0; n < numlists; n++){
225 for(k=0; (unsigned int) k < b[n].mNumberBuffers; k++)
226 devchannels += b[n].mBuffers[k].mNumberChannels;
227 }
228 devinfo[i].inchannels = devchannels;
229 if(devchannels) {
230 devins++;
231 devinfo[i].indevnum = devins;
232 } else devinfo[i].indevnum = -1;
233 csound->Free(csound,b);
234
235 devchannels = 0;
236 prop.mScope = kAudioDevicePropertyScopeOutput;
237 AudioObjectGetPropertyDataSize(sysdevs[i],
238 &prop, 0, NULL, &psize);
239 b = (AudioBufferList *) csound->Malloc(csound,psize);
240 numlists = psize /sizeof(AudioBufferList);
241 AudioObjectGetPropertyData(sysdevs[i],
242 &prop, 0, NULL, &psize, b);
243 for(n=0; n < numlists; n++){
244 for(k=0; (unsigned int) k < b[n].mNumberBuffers; k++)
245 devchannels += b[n].mBuffers[k].mNumberChannels;
246 }
247 devinfo[i].outchannels = devchannels;
248 if(devchannels) {
249 devouts++;
250 devinfo[i].outdevnum = devouts;
251 } else devinfo[i].outdevnum = -1;
252 csound->Free(csound,b);
253 }
254
255
256 if(cdata->disp)
257 csound->Message(csound,
258 "==========================================================\n");
259
260 if (isInput)
261 csound->Message(csound,
262 Str("AuHAL Module: found %d input device(s):\n"), devins);
263 else csound->Message(csound,
264 Str("AuHAL Module: found %d output device(s):\n"),
265 devouts);
266
267 for (i = 0; (unsigned int) i < devnos; i++) {
268 if (isInput) {
269 if(devinfo[i].inchannels) {
270 csound->Message(csound, Str("%d: %s (%d channels)\n"),
271 devinfo[i].indevnum, devinfo[i].name,
272 devinfo[i].inchannels);
273 }
274 }
275 else {
276 if(devinfo[i].outchannels)
277 csound->Message(csound, Str("%d: %s (%d channels)\n"),
278 devinfo[i].outdevnum, devinfo[i].name,
279 devinfo[i].outchannels);
280 }
281 }
282
283 if (parm->devName != NULL) devnum = atoi(parm->devName);
284 else devnum = parm->devNum;
285
286 if (devnum > 0 && devnum < 1024) {
287 int CoreAudioDev = -1;
288 prop.mSelector = kAudioHardwarePropertyDevices;
289 if (isInput) {
290 for(i=0; (unsigned int) i < devnos; i++) {
291 if((unsigned int) devinfo[i].indevnum == devnum) {
292 CoreAudioDev = i;
293 break;
294 }
295 }
296 if (LIKELY(CoreAudioDev >= 0)) {
297 prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
298 dev = sysdevs[CoreAudioDev];
299 AudioObjectSetPropertyData(kAudioObjectSystemObject, &prop,
300 0, NULL, sizeof(AudioDeviceID), &dev);
301 }
302 else csound->Warning(csound, Str("requested device %d out of range"),
303 devnum);
304
305 }
306 else {
307 prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
308 for(i=0;(unsigned int) i < devnos; i++) {
309 if((unsigned int) devinfo[i].outdevnum == devnum) CoreAudioDev = i;
310 }
311 if (LIKELY(CoreAudioDev >= 0)) {
312 dev = sysdevs[CoreAudioDev];
313 AudioObjectSetPropertyData(kAudioObjectSystemObject, &prop,
314 0, NULL, sizeof(AudioDeviceID), &dev);
315
316 }
317 else csound->Warning(csound, Str("requested device %d (%s) out of range"),
318 devnum, devinfo[CoreAudioDev].name);
319 }
320 }
321
322 for(i=0; (unsigned int) i < devnos; i++) {
323 if(sysdevs[i] == dev){
324 if(isInput) {
325 if(devinfo[i].inchannels < parm->nChannels) {
326 csound->ErrorMsg(csound,
327 Str(" *** CoreAudio: Device has not enough"
328 " inputs (%d, requested %d)\n"),
329 devinfo[i].inchannels, parm->nChannels);
330 return -1;
331 }
332 ADC_channels(csound, devinfo[i].inchannels);
333 }
334 else {
335 if(devinfo[i].outchannels < parm->nChannels) {
336 csound->ErrorMsg(csound,
337 Str(" *** CoreAudio: Device has not enough"
338 " outputs (%d, requested %d)\n"),
339 devinfo[i].outchannels, parm->nChannels);
340 return -1;
341 }
342 DAC_channels(csound, devinfo[i].outchannels);
343 }
344 }
345 }
346 csound->Free(csound,sysdevs);
347 csound->Free(csound,devinfo);
348
349 psize = sizeof(CFStringRef);
350 prop.mSelector = kAudioObjectPropertyName;
351 AudioObjectGetPropertyData(dev,
352 &prop, 0, NULL, &psize, &devName);
353 if(isInput)
354 csound->Message(csound, Str("selected input device: %s\n"),
355 CFStringGetCStringPtr(devName, defaultEncoding));
356
357 else
358 csound->Message(csound, Str("selected output device: %s\n"),
359 CFStringGetCStringPtr(devName, defaultEncoding));
360
361 CFRelease(devName);
362
363 srate = csound->GetSr(csound);
364 if(!isInput){
365 nchnls =cdata->onchnls = parm->nChannels;
366 bufframes = csound->GetOutputBufferSize(csound)/nchnls;
367 }
368 else {
369 nchnls = cdata->inchnls = parm->nChannels;
370 bufframes = csound->GetInputBufferSize(csound)/nchnls;
371 }
372
373 /* although the SR is set in the stream properties,
374 we also need to set the device to match */
375 double sr;
376 prop.mSelector = kAudioDevicePropertyNominalSampleRate;
377 if(!isInput){
378 AudioObjectGetPropertyData(dev, &prop, 0, NULL, &psize, &sr);
379 csound->system_sr(csound, sr);
380 }
381
382 psize = sizeof(double);
383 AudioObjectSetPropertyData(dev, &prop, 0, NULL, psize, &srate);
384 AudioObjectGetPropertyData(dev, &prop, 0, NULL, &psize, &sr);
385
386 if(srate < 0)
387 srate = csound->system_sr(csound, sr);
388 if(UNLIKELY(sr != srate)) {
389 csound->Warning(csound,
390 Str("Attempted to set device SR, tried %.1f, got %.1f\n"),
391 srate, sr);
392 }
393
394 HALOutput = AudioComponentFindNext(NULL, &cd);
395 if (isInput) {
396 AudioComponentInstanceNew(HALOutput, &(cdata->inunit));
397 enableIO = 1;
398 AudioUnitSetProperty(cdata->inunit, kAudioOutputUnitProperty_EnableIO,
399 kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
400 enableIO = 0;
401 AudioUnitSetProperty(cdata->inunit, kAudioOutputUnitProperty_EnableIO,
402 kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
403 psize = sizeof(AudioDeviceID);
404 /* for input, select device AFTER enabling IO */
405 AudioUnitSetProperty(cdata->inunit,kAudioOutputUnitProperty_CurrentDevice,
406 kAudioUnitScope_Global, isInput, &dev, psize);
407 aunit = &(cdata->inunit);
408 }
409 else {
410 AudioComponentInstanceNew(HALOutput, &(cdata->outunit));
411 psize = sizeof(AudioDeviceID);
412 /* for output, select device BEFORE enabling IO */
413 AudioUnitSetProperty(cdata->outunit, kAudioOutputUnitProperty_CurrentDevice,
414 kAudioUnitScope_Global, isInput, &dev, psize);
415 enableIO = 1;
416 AudioUnitSetProperty(cdata->outunit, kAudioOutputUnitProperty_EnableIO,
417 kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
418 enableIO = 0;
419 AudioUnitSetProperty(cdata->outunit, kAudioOutputUnitProperty_EnableIO,
420 kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
421 aunit = &(cdata->outunit);
422 }
423 /* now set the buffer size */
424 psize = sizeof(AudioDeviceID);
425 AudioUnitGetProperty(*aunit, kAudioOutputUnitProperty_CurrentDevice,
426 kAudioUnitScope_Global, isInput, &dev, &psize);
427 prop.mSelector = kAudioDevicePropertyBufferFrameSize;
428 psize = 4;
429 AudioObjectSetPropertyData(dev, &prop, 0, NULL, psize, &bufframes);
430 psize = sizeof(maxFPS);
431 AudioUnitGetProperty(*aunit, kAudioUnitProperty_MaximumFramesPerSlice,
432 kAudioUnitScope_Global, isInput, &maxFPS, &psize);
433 AudioUnitSetProperty(*aunit, kAudioUnitProperty_MaximumFramesPerSlice,
434 kAudioUnitScope_Global, isInput, &bufframes,
435 sizeof(UInt32));
436 /* set the stream properties */
437 psize = sizeof(AudioStreamBasicDescription);
438 AudioUnitGetProperty(*aunit, kAudioUnitProperty_StreamFormat,
439 (isInput ? kAudioUnitScope_Output : kAudioUnitScope_Input),
440 isInput, &format, &psize);
441 format.mSampleRate = srate;
442 format.mFormatID = kAudioFormatLinearPCM;
443 format.mFormatFlags = kAudioFormatFlagIsFloat |
444 kAudioFormatFlagIsPacked |
445 kLinearPCMFormatFlagIsNonInterleaved;
446 format.mBytesPerPacket = sizeof(Float32);
447 format.mFramesPerPacket = 1;
448 format.mBytesPerFrame = sizeof(Float32);
449 format.mChannelsPerFrame = nchnls;
450 format.mBitsPerChannel = sizeof(Float32)*8;
451 AudioUnitSetProperty(*aunit, kAudioUnitProperty_StreamFormat,
452 (isInput ? kAudioUnitScope_Output : kAudioUnitScope_Input),
453 isInput, &format,
454 sizeof(AudioStreamBasicDescription));
455 /* set the callbacks and open the device */
456 if(!isInput) {
457 AURenderCallbackStruct output;
458 output.inputProc = Csound_Render;
459 output.inputProcRefCon = cdata;
460 AudioUnitSetProperty(*aunit, kAudioUnitProperty_SetRenderCallback,
461 kAudioUnitScope_Input, isInput, &output, sizeof(output));
462 AudioUnitInitialize(*aunit);
463 AudioOutputUnitStart(*aunit);
464
465 csound->Message(csound,
466 Str("***** AuHAL module: output device open with %d "
467 "buffer frames\n"),
468 bufframes);
469 cdata->disp = 0;
470 }
471 else {
472 AURenderCallbackStruct input;
473 AudioBufferList *CAInputData =
474 (AudioBufferList*)csound->Malloc(csound,sizeof(UInt32)
475 + cdata->inchnls * sizeof(AudioBuffer));
476 CAInputData->mNumberBuffers = cdata->inchnls;
477 for (i = 0; i < cdata->inchnls; i++) {
478 CAInputData->mBuffers[i].mNumberChannels = 1;
479 CAInputData->mBuffers[i].mDataByteSize =
480 bufframes * sizeof(Float32);
481 CAInputData->mBuffers[i].mData =
482 csound->Calloc(csound,bufframes* sizeof(Float32));
483 }
484 cdata->inputdata = CAInputData;
485
486 input.inputProc = Csound_Input;
487 input.inputProcRefCon = cdata;
488 AudioUnitSetProperty(*aunit, kAudioOutputUnitProperty_SetInputCallback,
489 kAudioUnitScope_Input, isInput, &input, sizeof(input));
490 AudioUnitInitialize(*aunit);
491 AudioOutputUnitStart(*aunit);
492 csound->Message(csound,
493 Str("***** AuHAL module: input device open with "
494 "%d buffer frames\n"),
495 (int) bufframes);
496 }
497 if(!cdata->disp)
498 csound->Message(csound,
499 "==========================================================\n");
500
501 cdata->disp = 0;
502 return 0;
503
504 }
505
listDevices(CSOUND * csound,CS_AUDIODEVICE * list,int isOutput)506 int listDevices(CSOUND *csound, CS_AUDIODEVICE *list, int isOutput){
507 UInt32 psize, devnos;
508 AudioDeviceID *sysdevs;
509 Device_Info *devinfo;
510 int i;
511 int devouts = 0, devins = 0;
512
513 AudioObjectPropertyAddress prop = {
514 kAudioObjectPropertyName,
515 kAudioObjectPropertyScopeGlobal,
516 kAudioObjectPropertyElementMaster
517 };
518 CFStringRef devName;
519 CFStringEncoding defaultEncoding = CFStringGetSystemEncoding();
520 prop.mSelector = kAudioHardwarePropertyDevices;
521 AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
522 &prop, 0, NULL, &psize);
523 devnos = psize / sizeof(AudioDeviceID);
524 sysdevs = (AudioDeviceID *) csound->Malloc(csound,psize);
525 devinfo = (Device_Info *) csound->Malloc(csound,devnos*sizeof*devinfo);
526 AudioObjectGetPropertyData(kAudioObjectSystemObject,
527 &prop, 0, NULL, &psize, sysdevs);
528
529 for (i = 0; (unsigned int) i < devnos; i++) {
530 AudioBufferList *b;
531 int devchannels, k, n;
532 int numlists;
533 psize = sizeof(CFStringRef);
534 prop.mScope = kAudioObjectPropertyScopeGlobal;
535 prop.mSelector = kAudioObjectPropertyName;
536 AudioObjectGetPropertyData(sysdevs[i],
537 &prop, 0, NULL, &psize, &devName);
538 memset(devinfo[i].name,0,128);
539 if(CFStringGetCStringPtr(devName, defaultEncoding) != NULL)
540 strNcpy(devinfo[i].name,
541 CFStringGetCStringPtr(devName, defaultEncoding),127);
542 CFRelease(devName);
543
544 devchannels = 0;
545 prop.mScope = kAudioDevicePropertyScopeInput;
546 prop.mSelector = kAudioDevicePropertyStreamConfiguration;
547 AudioObjectGetPropertyDataSize(sysdevs[i],
548 &prop, 0, NULL, &psize);
549 b = (AudioBufferList *) csound->Malloc(csound,psize);
550 numlists = psize / sizeof(AudioBufferList);
551 AudioObjectGetPropertyData(sysdevs[i],
552 &prop, 0, NULL, &psize, b);
553 for(n=0; n < numlists; n++){
554 for(k=0; (unsigned int) k < b[n].mNumberBuffers; k++)
555 devchannels += b[n].mBuffers[k].mNumberChannels;
556 }
557 devinfo[i].inchannels = devchannels;
558 if(devchannels) {
559 devins++;
560 devinfo[i].indevnum = devins;
561 } else devinfo[i].indevnum = -1;
562 csound->Free(csound,b);
563
564 devchannels = 0;
565 prop.mScope = kAudioDevicePropertyScopeOutput;
566 AudioObjectGetPropertyDataSize(sysdevs[i],
567 &prop, 0, NULL, &psize);
568 b = (AudioBufferList *) csound->Malloc(csound,psize);
569 numlists = psize /sizeof(AudioBufferList);
570 AudioObjectGetPropertyData(sysdevs[i],
571 &prop, 0, NULL, &psize, b);
572 for(n=0; n < numlists; n++){
573 for(k=0; (unsigned int) k < b[n].mNumberBuffers; k++)
574 devchannels += b[n].mBuffers[k].mNumberChannels;
575 }
576 devinfo[i].outchannels = devchannels;
577 if(devchannels) {
578 devouts++;
579 devinfo[i].outdevnum = devouts;
580 } else devinfo[i].outdevnum = -1;
581 csound->Free(csound,b);
582 }
583 if(list==NULL){
584 return (isOutput ? devouts : devins);
585 } else {
586
587 char tmp[64], *s;
588 int n=0, i;
589
590 if ((s = (char*) csound->QueryGlobalVariable(csound, "_RTAUDIO")) == NULL)
591 return 0;
592
593 if(!isOutput){
594 for(i=0; (unsigned int) i < devnos; i++) {
595 if(devinfo[i].inchannels) {
596 strNcpy(list[n].device_name, devinfo[i].name, 63);
597 snprintf(tmp, 64, "adc%d", devinfo[i].indevnum);
598 strNcpy(list[n].device_id, tmp, 63);
599 strNcpy(list[n].rt_module, s, 63);
600 list[n].max_nchnls = devinfo[i].inchannels;
601 list[n].isOutput = 0;
602 n++;
603 }
604 }
605 return n;
606 } else {
607 for(i=0;(unsigned int) i < devnos; i++){
608 if(devinfo[i].outchannels) {
609 strNcpy(list[n].device_name, devinfo[i].name, 63);
610 snprintf(tmp, 64, "dac%d", devinfo[i].outdevnum);
611 strNcpy(list[n].device_id, tmp, 63);
612 strNcpy(list[n].rt_module, s, 63);
613 list[n].max_nchnls = devinfo[i].outchannels;
614 list[n].isOutput = 1;
615 n++;
616 }
617 }
618 return n;
619 }
620 }
621 }
622
623 /* open for audio input */
recopen_(CSOUND * csound,const csRtAudioParams * parm)624 static int recopen_(CSOUND *csound, const csRtAudioParams * parm)
625 {
626 csdata *cdata;
627 void **recordata = csound->GetRtRecordUserData(csound);
628 if (*(csound->GetRtRecordUserData(csound)) != NULL)
629 return 0;
630
631 /* allocate structure */
632
633 if(*(csound->GetRtPlayUserData(csound) )!= NULL)
634 cdata = (csdata *) *(csound->GetRtPlayUserData(csound));
635 else {
636 cdata = (csdata *) csound->Calloc(csound, sizeof(csdata));
637 cdata->disp = 1;
638 }
639
640 cdata->inunit = NULL;
641 *recordata = (void *) cdata;
642 cdata->inParm = (csRtAudioParams *) parm;
643 cdata->csound = cdata->csound;
644 cdata->inputBuffer =
645 (MYFLT *) csound->Calloc(csound,
646 csound->GetInputBufferSize(csound)* sizeof(MYFLT));
647 cdata->incb =
648 csound->CreateCircularBuffer(csound,
649 parm->bufSamp_HW*parm->nChannels, sizeof(MYFLT));
650 int ret = AuHAL_open(csound, parm, cdata, 1);
651 return ret;
652 }
653
654 /* open for audio output */
playopen_(CSOUND * csound,const csRtAudioParams * parm)655 static int playopen_(CSOUND *csound, const csRtAudioParams * parm)
656 {
657 csdata *cdata;
658 void **playdata = csound->GetRtPlayUserData(csound);
659
660 if(*(csound->GetRtRecordUserData(csound)) != NULL)
661 cdata = (csdata *) *(csound->GetRtRecordUserData(csound));
662 else {
663 cdata = (csdata *) csound->Calloc(csound, sizeof(csdata));
664 cdata->disp = 1;
665 }
666 cdata->outunit = NULL;
667 *playdata = (void *) cdata;
668 cdata->outParm = (csRtAudioParams *) parm;
669 cdata->csound = csound;
670 cdata->outputBuffer =
671 (MYFLT *) csound->Calloc(csound,
672 csound->GetOutputBufferSize(csound)* sizeof(MYFLT));
673 memset(cdata->outputBuffer, 0,
674 csound->GetOutputBufferSize(csound)*sizeof(MYFLT));
675 cdata->outcb =
676 csound->CreateCircularBuffer(csound,
677 parm->bufSamp_HW*parm->nChannels, sizeof(MYFLT));
678 return AuHAL_open(csound, parm,cdata,0);
679 }
680
Csound_Input(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)681 OSStatus Csound_Input(void *inRefCon,
682 AudioUnitRenderActionFlags *ioActionFlags,
683 const AudioTimeStamp *inTimeStamp,
684 UInt32 inBusNumber,
685 UInt32 inNumberFrames,
686 AudioBufferList *ioData)
687 {
688 csdata *cdata = (csdata *) inRefCon;
689 CSOUND *csound = cdata->csound;
690 int inchnls = cdata->inchnls;
691 MYFLT *inputBuffer = cdata->inputBuffer;
692 int j,k;
693 Float32 *buffer;
694 int n = inNumberFrames*inchnls;
695 int l;
696 IGN(ioData);
697
698 AudioUnitRender(cdata->inunit, ioActionFlags, inTimeStamp, inBusNumber,
699 inNumberFrames, cdata->inputdata);
700 for (k = 0; k < inchnls; k++){
701 buffer = (Float32 *) cdata->inputdata->mBuffers[k].mData;
702 for(j=0; (unsigned int) j < inNumberFrames; j++){
703 inputBuffer[j*inchnls+k] = buffer[j];
704 }
705 }
706 l = csound->WriteCircularBuffer(csound, cdata->incb,inputBuffer,n);
707 return 0;
708 }
709
710 #define MICROS 1000000
rtrecord_(CSOUND * csound,MYFLT * inbuff_,int nbytes)711 static int rtrecord_(CSOUND *csound, MYFLT *inbuff_, int nbytes)
712 {
713 csdata *cdata;
714 int n = nbytes/sizeof(MYFLT);
715 int m = 0, l, w = n;
716 MYFLT sr = csound->GetSr(csound);
717 cdata = (csdata *) *(csound->GetRtRecordUserData(csound));
718 do{
719 l = csound->ReadCircularBuffer(csound,cdata->incb,&inbuff_[m],n);
720 m += l;
721 n -= l;
722 if(n) usleep(MICROS*w/sr);
723 } while(n);
724 return nbytes;
725 }
726
Csound_Render(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)727 OSStatus Csound_Render(void *inRefCon,
728 AudioUnitRenderActionFlags *ioActionFlags,
729 const AudioTimeStamp *inTimeStamp,
730 UInt32 inBusNumber,
731 UInt32 inNumberFrames,
732 AudioBufferList *ioData)
733 {
734 csdata *cdata = (csdata *) inRefCon;
735 CSOUND *csound = cdata->csound;
736 int onchnls = cdata->onchnls;
737 MYFLT *outputBuffer = cdata->outputBuffer;
738 int j,k;
739 Float32 *buffer;
740 int n = inNumberFrames*onchnls;
741 IGN(ioActionFlags);
742 IGN(inTimeStamp);
743 IGN(inBusNumber);
744
745 n = csound->ReadCircularBuffer(csound,cdata->outcb,outputBuffer,n);
746 for (k = 0; k < onchnls; k++) {
747 buffer = (Float32 *) ioData->mBuffers[k].mData;
748 for(j=0; (unsigned int) j < inNumberFrames; j++){
749 buffer[j] = (Float32) outputBuffer[j*onchnls+k] ;
750 outputBuffer[j*onchnls+k] = FL(0.0);
751 }
752 }
753 return 0;
754 }
755
rtplay_(CSOUND * csound,const MYFLT * outbuff_,int nbytes)756 static void rtplay_(CSOUND *csound, const MYFLT *outbuff_, int nbytes)
757 {
758 csdata *cdata;
759 int n = nbytes/sizeof(MYFLT);
760 int m = 0, l, w = n;
761 MYFLT sr = csound->GetSr(csound);
762 cdata = (csdata *) *(csound->GetRtPlayUserData(csound));
763 do {
764 l = csound->WriteCircularBuffer(csound, cdata->outcb,&outbuff_[m],n);
765 m += l;
766 n -= l;
767 if(n) usleep(MICROS*w/sr);
768 } while(n);
769 }
770
771 /* close the I/O device entirely */
772 /* called only when both complete */
773
rtclose_(CSOUND * csound)774 static void rtclose_(CSOUND *csound)
775 {
776 csdata *cdata;
777 cdata = (csdata *) *(csound->GetRtRecordUserData(csound));
778 if(cdata == NULL)
779 cdata = (csdata *) *(csound->GetRtPlayUserData(csound));
780
781 if (cdata != NULL) {
782 usleep(1000*csound->GetOutputBufferSize(csound)/
783 (csound->GetSr(csound)*csound->GetNchnls(csound)));
784
785 if(cdata->inunit != NULL){
786 AudioOutputUnitStop(cdata->inunit);
787 AudioUnitUninitialize(cdata->inunit);
788 AudioComponentInstanceDispose(cdata->inunit);
789 }
790
791 if(cdata->outunit != NULL){
792 AudioOutputUnitStop(cdata->outunit);
793 AudioUnitUninitialize(cdata->outunit);
794 AudioComponentInstanceDispose(cdata->outunit);
795 }
796
797 if (cdata->outputBuffer != NULL) {
798 csound->Free(csound,cdata->outputBuffer);
799 cdata->outputBuffer = NULL;
800 }
801 if (cdata->inputBuffer != NULL) {
802 csound->Free(csound,cdata->inputBuffer);
803 cdata->inputBuffer = NULL;
804 }
805
806 *(csound->GetRtRecordUserData(csound)) = NULL;
807 *(csound->GetRtPlayUserData(csound)) = NULL;
808
809 if(cdata->inputdata) {
810 int i;
811 for (i = 0; i < cdata->inchnls; i++)
812 csound->Free(csound,cdata->inputdata->mBuffers[i].mData);
813 csound->Free(csound,cdata->inputdata);
814 }
815
816 if(cdata->defdevin) {
817 AudioObjectPropertyAddress prop = {
818 kAudioHardwarePropertyDefaultInputDevice,
819 kAudioObjectPropertyScopeGlobal,
820 kAudioObjectPropertyElementMaster
821 };
822 UInt32 psize = sizeof(AudioDeviceID);
823 AudioObjectSetPropertyData(kAudioObjectSystemObject,
824 &prop, 0, NULL, psize, &cdata->defdevin);
825 }
826 if(cdata->defdevout) {
827 AudioObjectPropertyAddress prop = {
828 kAudioHardwarePropertyDefaultOutputDevice,
829 kAudioObjectPropertyScopeGlobal,
830 kAudioObjectPropertyElementMaster
831 };
832 UInt32 psize = sizeof(AudioDeviceID);
833 AudioObjectSetPropertyData(kAudioObjectSystemObject,
834 &prop, 0, NULL, psize, &cdata->defdevout);
835 }
836 csound->DestroyCircularBuffer(csound, cdata->incb);
837 csound->DestroyCircularBuffer(csound, cdata->outcb);
838 csound->Free(csound,cdata);
839 csound->Message(csound, "%s", Str("AuHAL module: device closed\n"));
840 }
841 }
842
csoundModuleInit(CSOUND * csound)843 int csoundModuleInit(CSOUND *csound)
844 {
845 char *drv;
846 csound->module_list_add(csound, "auhal", "audio");
847 drv = (char *) csound->QueryGlobalVariable(csound, "_RTAUDIO");
848 if (drv == NULL)
849 return 0;
850 if (!(strcmp(drv, "auhal") == 0 || strcmp(drv, "AuHal") == 0 ||
851 strcmp(drv, "AUHAL") == 0 ||
852 strcmp(drv, "coreaudio") == 0 || strcmp(drv, "CoreAudio") == 0 ||
853 strcmp(drv, "COREAUDIO") == 0))
854 return 0;
855 //if (csound->oparms->msglevel & 0x400)
856 csound->Message(csound, "%s", Str("rtaudio: coreaaudio-AuHAL module enabled\n"));
857 csound->SetPlayopenCallback(csound, playopen_);
858 csound->SetRecopenCallback(csound, recopen_);
859 csound->SetRtplayCallback(csound, rtplay_);
860 csound->SetRtrecordCallback(csound, rtrecord_);
861 csound->SetRtcloseCallback(csound, rtclose_);
862 csound->SetAudioDeviceListCallback(csound, listDevices);
863 return 0;
864 }
865
csoundModuleCreate(CSOUND * csound)866 int csoundModuleCreate(CSOUND *csound)
867 {
868 IGN(csound);
869 return 0;
870 }
871