Merge branch 'master' of https://scm.cri.ensmp.fr/git/Faustine
[Faustine.git] / interpretor / faust-0.9.47mr3 / architecture / iphone-cocoa.cpp
1 /************************************************************************
2
3 IMPORTANT NOTE : this file contains two clearly delimited sections :
4 the ARCHITECTURE section (in two parts) and the USER section. Each section
5 is governed by its own copyright and license. Please check individually
6 each section for license and copyright information.
7 *************************************************************************/
8
9 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
10
11 /************************************************************************
12 FAUST Architecture File
13 Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
14 ---------------------------------------------------------------------
15 This Architecture section is free software; you can redistribute it
16 and/or modify it under the terms of the GNU General Public License
17 as published by the Free Software Foundation; either version 3 of
18 the License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; If not, see <http://www.gnu.org/licenses/>.
27
28 EXCEPTION : As a special exception, you may create a larger work
29 that contains this FAUST architecture section and distribute
30 that work under terms of your choice, so long as this FAUST
31 architecture section is not modified.
32
33
34 ************************************************************************
35 ************************************************************************/
36
37 /* link with */
38 #include <math.h>
39 /* link with */
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <limits.h>
44 #include <math.h>
45 #include <errno.h>
46 #include <time.h>
47 #include <sys/ioctl.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <pwd.h>
51 #include <sys/types.h>
52 #include <assert.h>
53 #include <pthread.h>
54 #include <sys/wait.h>
55
56 #include <list>
57 #include <vector>
58 #include <iostream>
59 #include <fstream>
60 #include <stack>
61 #include <list>
62 #include <map>
63 #include <libgen.h>
64
65 #include <AudioToolbox/AudioConverter.h>
66 #include <AudioToolbox/AudioServices.h>
67 #include <AudioUnit/AudioUnit.h>
68
69 using namespace std;
70
71 /******************************************************************************
72 *******************************************************************************
73
74 VECTOR INTRINSICS
75
76 *******************************************************************************
77 *******************************************************************************/
78
79 <<includeIntrinsic>>
80
81 /******************************************************************************
82 *******************************************************************************
83
84 USER INTERFACE
85
86 *******************************************************************************
87 *******************************************************************************/
88
89 #include "CocoaUI.h"
90 #include "audio/dsp.h"
91 #include "misc.h"
92
93 /********************END ARCHITECTURE SECTION (part 1/2)****************/
94
95 /**************************BEGIN USER SECTION **************************/
96
97 <<includeclass>>
98
99 /***************************END USER SECTION ***************************/
100
101 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
102
103 mydsp DSP;
104
105 /******************************************************************************
106 *******************************************************************************
107
108 COREAUDIO INTERFACE
109
110 *******************************************************************************
111 *******************************************************************************/
112
113 #define MAX_CHANNELS 256
114 #define OPEN_ERR -1
115 #define NO_ERR 0
116
117 class TiPhoneCoreAudioRenderer
118 {
119
120 private:
121
122 AudioUnit fAUHAL;
123
124 int fDevNumInChans;
125 int fDevNumOutChans;
126
127 int fHWNumInChans;
128 int fHWNumOutChans;
129
130 AudioBufferList* fCAInputData;
131
132 float* fInChannel[MAX_CHANNELS];
133 float* fOutChannel[MAX_CHANNELS];
134
135 static OSStatus Render(void *inRefCon,
136 AudioUnitRenderActionFlags *ioActionFlags,
137 const AudioTimeStamp *inTimeStamp,
138 UInt32 inBusNumber,
139 UInt32 inNumberFrames,
140 AudioBufferList *ioData);
141
142 static void InterruptionListener(void *inClientData, UInt32 inInterruption);
143
144 public:
145
146 TiPhoneCoreAudioRenderer(int input, int output)
147 :fDevNumInChans(input), fDevNumOutChans(output), fCAInputData(NULL)
148 {
149 memset(fInChannel, 0, sizeof(float*) * MAX_CHANNELS);
150 memset(fOutChannel, 0, sizeof(float*) * MAX_CHANNELS);
151
152 for (int i = 0; i < fDevNumInChans; i++) {
153 fInChannel[i] = new float[8192];
154 }
155
156 for (int i = 0; i < fDevNumOutChans; i++) {
157 fOutChannel[i] = new float[8192];
158 }
159 }
160
161 virtual ~TiPhoneCoreAudioRenderer()
162 {
163 for (int i = 0; i < fDevNumInChans; i++) {
164 delete[] fInChannel[i];
165 }
166
167 for (int i = 0; i < fDevNumOutChans; i++) {
168 delete[] fOutChannel[i];
169 }
170
171 if (fCAInputData) {
172 for (int i = 0; i < fDevNumInChans; i++) {
173 free(fCAInputData->mBuffers[i].mData);
174 }
175 free(fCAInputData);
176 }
177 }
178
179 int Open(int bufferSize, int sampleRate);
180 int Close();
181
182 int Start();
183 int Stop();
184
185 };
186
187 typedef TiPhoneCoreAudioRenderer * TiPhoneCoreAudioRendererPtr;
188
189 static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
190 {
191 printf("- - - - - - - - - - - - - - - - - - - -\n");
192 printf(" Sample Rate:%f\n", inDesc->mSampleRate);
193 printf(" Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
194 printf(" Format Flags:%lX\n", inDesc->mFormatFlags);
195 printf(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
196 printf(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
197 printf(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
198 printf(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
199 printf(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
200 printf("- - - - - - - - - - - - - - - - - - - -\n");
201 }
202
203 static void printError(OSStatus err)
204 {
205 switch (err) {
206 case kAudioConverterErr_FormatNotSupported:
207 printf("error code : kAudioConverterErr_FormatNotSupported\n");
208 break;
209 case kAudioConverterErr_OperationNotSupported:
210 printf("error code : kAudioConverterErr_OperationNotSupported\n");
211 break;
212 case kAudioConverterErr_PropertyNotSupported:
213 printf("error code : kAudioConverterErr_PropertyNotSupported\n");
214 break;
215 case kAudioConverterErr_InvalidInputSize:
216 printf("error code : kAudioConverterErr_InvalidInputSize\n");
217 break;
218 case kAudioConverterErr_InvalidOutputSize:
219 printf("error code : kAudioConverterErr_InvalidOutputSize\n");
220 break;
221 case kAudioConverterErr_UnspecifiedError:
222 printf("error code : kAudioConverterErr_UnspecifiedError\n");
223 break;
224 case kAudioConverterErr_BadPropertySizeError:
225 printf("error code : kAudioConverterErr_BadPropertySizeError\n");
226 break;
227 case kAudioConverterErr_RequiresPacketDescriptionsError:
228 printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
229 break;
230 case kAudioConverterErr_InputSampleRateOutOfRange:
231 printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
232 break;
233 case kAudioConverterErr_OutputSampleRateOutOfRange:
234 printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
235 break;
236 default:
237 printf("error code : unknown\n");
238 break;
239 }
240 }
241
242 OSStatus TiPhoneCoreAudioRenderer::Render(void *inRefCon,
243 AudioUnitRenderActionFlags *ioActionFlags,
244 const AudioTimeStamp *inTimeStamp,
245 UInt32,
246 UInt32 inNumberFrames,
247 AudioBufferList *ioData)
248 {
249 TiPhoneCoreAudioRendererPtr renderer = (TiPhoneCoreAudioRendererPtr)inRefCon;
250 AudioUnitRender(renderer->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, renderer->fCAInputData);
251
252 float coef = float(LONG_MAX);
253 float inv_coef = 1.f/float(LONG_MAX);
254
255 if (renderer->fHWNumInChans == 1) {
256 // Mono ==> stereo
257 for (int chan = 0; chan < renderer->fDevNumInChans; chan++) {
258 for (int frame = 0; frame < inNumberFrames; frame++) {
259 renderer->fInChannel[chan][frame] = float(((int*)renderer->fCAInputData->mBuffers[0].mData)[frame]) * inv_coef;
260 }
261 }
262 } else {
263 for (int chan = 0; chan < renderer->fDevNumInChans; chan++) {
264 for (int frame = 0; frame < inNumberFrames; frame++) {
265 renderer->fInChannel[chan][frame] = float(((int*)renderer->fCAInputData->mBuffers[chan].mData)[frame]) * inv_coef;
266 }
267 }
268 }
269
270 DSP.compute((int)inNumberFrames, renderer->fInChannel, renderer->fOutChannel);
271
272 for (int chan = 0; chan < renderer->fDevNumOutChans; chan++) {
273 for (int frame = 0; frame < inNumberFrames; frame++) {
274 ((long*)ioData->mBuffers[chan].mData)[frame] = long(renderer->fOutChannel[chan][frame] * coef);
275 }
276 }
277
278 return 0;
279 }
280
281 void TiPhoneCoreAudioRenderer::InterruptionListener(void *inClientData, UInt32 inInterruption)
282 {
283 TiPhoneCoreAudioRenderer *obj = (TiPhoneCoreAudioRenderer*)inClientData;
284 printf("Session interrupted! --- %s ---", inInterruption == kAudioSessionBeginInterruption ? "Begin Interruption" : "End Interruption");
285
286 if (inInterruption == kAudioSessionEndInterruption) {
287 // make sure we are again the active session
288 AudioSessionSetActive(true);
289 AudioOutputUnitStart(obj->fAUHAL);
290 }
291
292 if (inInterruption == kAudioSessionBeginInterruption) {
293 AudioOutputUnitStop(obj->fAUHAL);
294 }
295 }
296
297 int TiPhoneCoreAudioRenderer::Open(int bufferSize, int samplerate)
298 {
299 OSStatus err1;
300 UInt32 outSize;
301 UInt32 enableIO;
302 AudioStreamBasicDescription srcFormat, dstFormat;
303
304 printf("OpenDefault fDevNumInChans = %ld fDevNumOutChans = %ld bufferSize = %ld samplerate = %ld\n", fDevNumInChans, fDevNumOutChans, bufferSize, samplerate);
305
306 // Initialize and configure the audio session
307 err1 = AudioSessionInitialize(NULL, NULL, InterruptionListener, this);
308 if (err1 != noErr) {
309 printf("Couldn't initialize audio session\n");
310 printError(err1);
311 return OPEN_ERR;
312 }
313
314 err1 = AudioSessionSetActive(true);
315 if (err1 != noErr) {
316 printf("Couldn't set audio session active\n");
317 printError(err1);
318 return OPEN_ERR;
319 }
320
321 UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
322 err1 = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
323 if (err1 != noErr) {
324 printf("Couldn't set audio category\n");
325 printError(err1);
326 return OPEN_ERR;
327 }
328
329 //err1 = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self), "couldn't set property listener");
330
331 Float64 hwSampleRate;
332 outSize = sizeof(hwSampleRate);
333 err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &outSize, &hwSampleRate);
334 if (err1 != noErr) {
335 printf("Couldn't get hw sample rate\n");
336 printError(err1);
337 return OPEN_ERR;
338 } else {
339 printf("Get hw sample rate %f\n", hwSampleRate);
340 }
341
342 Float32 hwBufferSize;
343 outSize = sizeof(hwBufferSize);
344 err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &outSize, &hwBufferSize);
345 if (err1 != noErr) {
346 printf("Couldn't get hw buffer duration\n");
347 printError(err1);
348 return OPEN_ERR;
349 } else {
350 printf("Get hw buffer duration %f\n", hwBufferSize);
351 }
352
353 outSize = sizeof(fHWNumInChans);
354 err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &outSize, &fHWNumInChans);
355 if (err1 != noErr) {
356 printf("Couldn't get hw input channels\n");
357 printError(err1);
358 return OPEN_ERR;
359 } else {
360 printf("Get hw input channels %d\n", fHWNumInChans);
361 }
362
363 outSize = sizeof(fHWNumOutChans);
364 err1 = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &outSize, &fHWNumOutChans);
365 if (err1 != noErr) {
366 printf("Couldn't get hw output channels\n");
367 printError(err1);
368 return OPEN_ERR;
369 } else {
370 printf("Get hw output channels %d\n", fHWNumOutChans);
371 }
372
373 Float32 preferredBufferSize = float(bufferSize) / float(samplerate);
374 printf("preferredBufferSize %f \n", preferredBufferSize);
375
376 err1 = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
377 if (err1 != noErr) {
378 printf("Couldn't set i/o buffer duration\n");
379 printError(err1);
380 return OPEN_ERR;
381 }
382
383 Float64 preferredSamplerate = float(samplerate);
384 err1 = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate, sizeof(preferredSamplerate), &preferredSamplerate);
385 if (err1 != noErr) {
386 printf("Couldn't set i/o sample rate\n");
387 printError(err1);
388 return OPEN_ERR;
389 }
390
391 // AUHAL
392 AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, kAudioUnitManufacturer_Apple, 0, 0};
393 AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
394
395 err1 = AudioComponentInstanceNew(HALOutput, &fAUHAL);
396 if (err1 != noErr) {
397 printf("Error calling OpenAComponent\n");
398 printError(err1);
399 goto error;
400 }
401
402 enableIO = 1;
403 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
404 if (err1 != noErr) {
405 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
406 printError(err1);
407 goto error;
408 }
409
410 enableIO = 1;
411 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
412 if (err1 != noErr) {
413 printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
414 printError(err1);
415 goto error;
416 }
417
418 UInt32 maxFPS;
419 outSize = sizeof(maxFPS);
420 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFPS, &outSize);
421 if (err1 != noErr) {
422 printf("Couldn't get kAudioUnitProperty_MaximumFramesPerSlice\n");
423 printError(err1);
424 goto error;
425 } else {
426 printf("Get kAudioUnitProperty_MaximumFramesPerSlice %d\n", maxFPS);
427 }
428
429 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&bufferSize, sizeof(UInt32));
430 if (err1 != noErr) {
431 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
432 printError(err1);
433 goto error;
434 }
435
436 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&bufferSize, sizeof(UInt32));
437 if (err1 != noErr) {
438 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
439 printError(err1);
440 goto error;
441 }
442
443 err1 = AudioUnitInitialize(fAUHAL);
444 if (err1 != noErr) {
445 printf("Cannot initialize AUHAL unit\n");
446 printError(err1);
447 goto error;
448 }
449
450 // Setting format
451
452 if (fDevNumInChans > 0) {
453 outSize = sizeof(AudioStreamBasicDescription);
454 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize);
455 if (err1 != noErr) {
456 printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
457 printError(err1);
458 }
459 PrintStreamDesc(&srcFormat);
460
461 srcFormat.mFormatID = kAudioFormatLinearPCM;
462 srcFormat.mFormatFlags = kAudioFormatFlagsCanonical | kLinearPCMFormatFlagIsNonInterleaved;
463 srcFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
464 srcFormat.mFramesPerPacket = 1;
465 srcFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
466 srcFormat.mChannelsPerFrame = fDevNumInChans;
467 srcFormat.mBitsPerChannel = 32;
468
469 PrintStreamDesc(&srcFormat);
470
471 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
472 if (err1 != noErr) {
473 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
474 printError(err1);
475 }
476 }
477
478 if (fDevNumOutChans > 0) {
479 outSize = sizeof(AudioStreamBasicDescription);
480 err1 = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize);
481 if (err1 != noErr) {
482 printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
483 printError(err1);
484 }
485 PrintStreamDesc(&dstFormat);
486
487 dstFormat.mFormatID = kAudioFormatLinearPCM;
488 dstFormat.mFormatFlags = kAudioFormatFlagsCanonical | kLinearPCMFormatFlagIsNonInterleaved;
489 dstFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
490 dstFormat.mFramesPerPacket = 1;
491 dstFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
492 dstFormat.mChannelsPerFrame = fDevNumOutChans;
493 dstFormat.mBitsPerChannel = 32;
494
495 PrintStreamDesc(&dstFormat);
496
497 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
498 if (err1 != noErr) {
499 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
500 printError(err1);
501 }
502 }
503
504 if (fDevNumInChans > 0 && fDevNumOutChans == 0) {
505 AURenderCallbackStruct output;
506 output.inputProc = Render;
507 output.inputProcRefCon = this;
508 err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
509 if (err1 != noErr) {
510 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
511 printError(err1);
512 goto error;
513 }
514 } else {
515 AURenderCallbackStruct output;
516 output.inputProc = Render;
517 output.inputProcRefCon = this;
518 err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
519 if (err1 != noErr) {
520 printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
521 printError(err1);
522 goto error;
523 }
524 }
525
526 // Prepare buffers
527 fCAInputData = (AudioBufferList*)malloc(sizeof(UInt32) + fDevNumInChans * sizeof(AudioBuffer));
528 fCAInputData->mNumberBuffers = fDevNumInChans;
529 for (int i = 0; i < fDevNumInChans; i++) {
530 fCAInputData->mBuffers[i].mNumberChannels = 1;
531 fCAInputData->mBuffers[i].mDataByteSize = bufferSize * sizeof(int);
532 fCAInputData->mBuffers[i].mData = malloc(bufferSize * sizeof(int));
533 }
534
535 return NO_ERR;
536
537 error:
538 AudioUnitUninitialize(fAUHAL);
539 AudioComponentInstanceDispose(fAUHAL);
540 return OPEN_ERR;
541 }
542
543 int TiPhoneCoreAudioRenderer::Close()
544 {
545 AudioUnitUninitialize(fAUHAL);
546 AudioComponentInstanceDispose(fAUHAL);
547 return NO_ERR;
548 }
549
550 int TiPhoneCoreAudioRenderer::Start()
551 {
552 AudioSessionSetActive(true);
553 OSStatus err = AudioOutputUnitStart(fAUHAL);
554
555 if (err != noErr) {
556 printf("Error while opening device : device open error \n");
557 return OPEN_ERR;
558 } else {
559 return NO_ERR;
560 }
561 }
562
563 int TiPhoneCoreAudioRenderer::Stop()
564 {
565 OSStatus err = AudioOutputUnitStop(fAUHAL);
566
567 if (err != noErr) {
568 printf("Error while closing device : device close error \n");
569 return OPEN_ERR;
570 } else {
571 return NO_ERR;
572 }
573 }
574
575
576 /********************END ARCHITECTURE SECTION (part 2/2)****************/
577
578