Fix scvim regsitry file for updated filename (thanks Carlo Capocasa)
[supercollider.git] / server / scsynth / SC_CoreAudio.cpp
blob8c6b5812aad7c84270cfe2552de6c328ff703d22
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program 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 2 of the License, or
9 (at your option) any later version.
11 This program 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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "SC_CoreAudio.h"
22 #include "SC_Sem.h"
23 #include <stdarg.h>
24 #include "SC_SequencedCommand.h"
25 #include "SC_Prototypes.h"
26 #include "SC_HiddenWorld.h"
27 #include "SC_Endian.h"
28 #include "SC_Lib_Cintf.h"
29 #include <stdlib.h>
30 #include <pthread.h>
31 #include <algorithm>
33 #ifdef _WIN32
35 #else
36 #include <sys/time.h>
37 #endif
39 #ifdef SC_IPHONE
40 #include "SC_VFP11.h"
41 #endif
44 #ifdef _WIN32
45 #include "SC_Win32Utils.h"
46 #endif
48 int64 gStartupOSCTime = -1;
50 void sc_SetDenormalFlags();
52 void set_real_time_priority(pthread_t thread);
54 double gSampleRate, gSampleDur;
56 // =====================================================================
57 // Timing (CoreAudio)
59 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
61 int64 gOSCoffset = 0;
63 int32 server_timeseed()
65 static int32 count = 0;
66 int64 time = AudioGetCurrentHostTime();
67 return (int32)(time >> 32) ^ (int32)time ^ count--;
70 inline int64 CoreAudioHostTimeToOSC(int64 hostTime)
72 return (int64)((double)AudioConvertHostTimeToNanos(hostTime) * kNanosToOSCunits) + gOSCoffset;
75 int64 oscTimeNow()
77 return CoreAudioHostTimeToOSC(AudioGetCurrentHostTime());
80 static void syncOSCOffsetWithTimeOfDay()
82 // generate a value gOSCoffset such that
83 // (gOSCOffset + systemTimeInOSCunits)
84 // is equal to gettimeofday time in OSCunits.
85 // Then if this machine is synced via NTP, we are synced with the world.
86 // more accurate way to do this??
88 struct timeval tv;
90 int64 systemTimeBefore, systemTimeAfter, diff;
91 int64 minDiff = 0x7fffFFFFffffFFFFLL;
93 // take best of several tries
94 const int numberOfTries = 5;
95 int64 newOffset = gOSCoffset;
96 for (int i=0; i<numberOfTries; ++i) {
97 systemTimeBefore = AudioGetCurrentHostTime();
98 gettimeofday(&tv, 0);
99 systemTimeAfter = AudioGetCurrentHostTime();
101 diff = systemTimeAfter - systemTimeBefore;
102 if (diff < minDiff) {
103 minDiff = diff;
104 // assume that gettimeofday happens halfway between AudioGetCurrentHostTime calls
105 int64 systemTimeBetween = systemTimeBefore + diff/2;
106 int64 systemTimeInOSCunits = (int64)((double)AudioConvertHostTimeToNanos(systemTimeBetween) * kNanosToOSCunits);
107 int64 timeOfDayInOSCunits = ((int64)(tv.tv_sec + kSECONDS_FROM_1900_to_1970) << 32)
108 + (int64)(tv.tv_usec * kMicrosToOSCunits);
109 newOffset = timeOfDayInOSCunits - systemTimeInOSCunits;
113 gOSCoffset = newOffset;
114 //scprintf("gOSCoffset %016llX\n", gOSCoffset);
117 void* resyncThreadFunc(void* arg);
118 void* resyncThreadFunc(void* /*arg*/)
120 while (true) {
121 sleep(20);
122 syncOSCOffsetWithTimeOfDay();
124 return 0;
127 void initializeScheduler()
129 syncOSCOffsetWithTimeOfDay();
131 pthread_t resyncThread;
132 pthread_create (&resyncThread, NULL, resyncThreadFunc, (void*)0);
133 set_real_time_priority(resyncThread);
135 #endif // SC_AUDIO_API_COREAUDIO
138 // =====================================================================
139 // Timing (CoreAudioIPHONE)
141 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
143 int64 gOSCoffset = 0;
145 static inline int64 GetMicroseconds()
147 struct timeval tv;
148 gettimeofday(&tv, 0);
149 return (int64) tv.tv_sec * 1000000 + tv.tv_usec;
152 static inline int64 GetCurrentOSCTime()
154 struct timeval tv;
155 uint64 s, f;
156 gettimeofday(&tv, 0);
157 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
158 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
160 return (s << 32) + f;
163 int32 server_timeseed()
165 int64 time = GetCurrentOSCTime();
166 return Hash((int32)(time >> 32) + Hash((int32)time));
169 int64 oscTimeNow()
171 return GetCurrentOSCTime();
174 void initializeScheduler()
176 gOSCoffset = GetCurrentOSCTime();
178 #endif // SC_AUDIO_API_COREAUDIO
183 // =====================================================================
184 // Timing (PortAudio)
186 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
188 int64 gOSCoffset = 0;
190 static inline int64 GetCurrentOSCTime()
192 struct timeval tv;
193 uint64 s, f;
194 gettimeofday(&tv, 0);
195 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
196 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
198 return (s << 32) + f;
201 int32 server_timeseed()
203 int64 time = GetCurrentOSCTime();
204 return Hash((int32)(time >> 32) + Hash((int32)time));
207 int64 oscTimeNow()
209 return GetCurrentOSCTime();
212 int64 PaStreamTimeToOSC(PaTime pa_time) {
213 uint64 s, f;
214 s = (uint64)pa_time;
215 f = (uint64)((pa_time - s) * 1000000 * kMicrosToOSCunits);
217 return (s << 32) + f;
220 void initializeScheduler()
222 gOSCoffset = GetCurrentOSCTime();
224 #endif // SC_AUDIO_API_PORTAUDIO
227 // =====================================================================
228 // Packets (Common)
230 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket);
231 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket);
232 int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply);
233 PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc);
235 void Perform_ToEngine_Msg(FifoMsg *inMsg);
236 void FreeOSCPacket(FifoMsg *inMsg);
238 struct IsBundle
240 IsBundle() { str4cpy(s, "#bundle"); }
241 bool checkIsBundle(int32 *in) { return in[0] == s[0] && in[1] == s[1]; }
242 int32 s[2];
244 IsBundle gIsBundle;
246 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket)
248 //scprintf("ProcessOSCPacket %d, '%s'\n", inPacket->mSize, inPacket->mData);
249 if (!inPacket) return false;
250 bool result;
251 inWorld->mDriverLock->Lock();
252 SC_AudioDriver *driver = AudioDriver(inWorld);
253 if (!driver) {
254 inWorld->mDriverLock->Unlock();
255 return false;
257 inPacket->mIsBundle = gIsBundle.checkIsBundle((int32*)inPacket->mData);
258 FifoMsg fifoMsg;
259 fifoMsg.Set(inWorld, Perform_ToEngine_Msg, FreeOSCPacket, (void*)inPacket);
260 result = driver->SendOscPacketMsgToEngine(fifoMsg);
261 inWorld->mDriverLock->Unlock();
262 return result;
265 int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply)
267 // scprintf("->PerformOSCMessage %d\n", inData[0]);
268 SC_LibCmd *cmdObj;
269 int cmdNameLen;
270 if (inData[0] == 0) {
271 cmdNameLen = 4;
272 uint32 index = inData[3];
273 if (index >= NUMBER_OF_COMMANDS) cmdObj = 0;
274 else cmdObj = gCmdArray[index];
275 } else {
276 cmdNameLen = OSCstrlen(inData);
277 cmdObj = gCmdLib->Get((int32*)inData);
279 if (!cmdObj) {
280 CallSendFailureCommand(inWorld, inData, "Command not found", inReply);
281 scprintf("FAILURE IN SERVER: %s Command not found\n", inData);
282 return kSCErr_NoSuchCommand;
285 int err = cmdObj->Perform(inWorld, inSize - cmdNameLen, inData + cmdNameLen, inReply);
286 //scprintf("<-PerformOSCMessage %d\n", inData[0]);
287 return err;
290 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket)
292 //scprintf("->PerformOSCBundle %d\n", inPacket->mSize);
293 char *data = inPacket->mData + 16;
294 char* dataEnd = inPacket->mData + inPacket->mSize;
296 while (data < dataEnd) {
297 int32 msgSize = ntohl(*(int32*)data);
298 data += sizeof(int32);
299 //scprintf("msgSize %d\n", msgSize);
300 PerformOSCMessage(inWorld, msgSize, data, &inPacket->mReplyAddr);
301 data += msgSize;
304 // reset so next command uses permanent error notification status
305 inWorld->mLocalErrorNotification = 0;
307 // // 0 is a temporary change, so reset the local error flag
308 // if(!inWorld->mLocalErrorNotification) {
309 // inWorld->mLocalErrorNotification = inWorld->mErrorNotification;
310 // };
312 //scprintf("<-PerformOSCBundle %d\n", inPacket->mSize);
315 PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc freeFunc)
317 SC_AudioDriver *driver = world->hw->mAudioDriver;
319 if (!packet->mIsBundle) {
320 PerformOSCMessage(world, packet->mSize, packet->mData, &packet->mReplyAddr);
321 world->mLocalErrorNotification = 0;
322 // if(!world->mLocalErrorNotification) {
323 // world->mLocalErrorNotification = world->mErrorNotification;
324 // };
325 return PacketPerformed;
326 } else {
327 // in real time engine, schedule the packet
328 int64 time = OSCtime(packet->mData + 8);
329 if (time == 0 || time == 1) {
330 PerformOSCBundle(world, packet);
331 return PacketPerformed;
332 } else {
333 if ((time < driver->mOSCbuftime) && (world->mVerbosity >= 0)) {
334 double seconds = (driver->mOSCbuftime - time)*kOSCtoSecs;
335 scprintf("late %.9f\n", seconds);
336 //FifoMsg outMsg;
338 //ReportLateness(packet->mReply, seconds)
340 // DEBUG
341 // else
342 //scprintf("scheduled in %.6f at time %.6f\n",
343 // (time-driver->mOSCbuftime)*kOSCtoSecs,
344 // (time-gStartupOSCTime)*kOSCtoSecs);
346 SC_ScheduledEvent event(world, time, packet, freeFunc);
347 driver->AddEvent(event);
348 return PacketScheduled;
353 ////////////////////////////////////////////////////////////////////////////
355 void Perform_ToEngine_Msg(FifoMsg *inMsg)
357 World *world = inMsg->mWorld;
358 OSC_Packet *packet = (OSC_Packet*)inMsg->mData;
359 if (!packet) return;
361 PacketStatus status = PerformOSCPacket(world, packet, SC_ScheduledEvent::FreeInNRT);
362 if (status == PacketScheduled) {
363 // Transfer ownership
364 inMsg->mData = 0;
365 inMsg->mFreeFunc = 0;
369 PacketStatus PerformCompletionMsg(World *inWorld, const OSC_Packet& inPacket)
371 OSC_Packet* packet = (OSC_Packet*)World_Alloc(inWorld, sizeof(OSC_Packet));
372 *packet = inPacket;
373 packet->mIsBundle = gIsBundle.checkIsBundle((int32*)packet->mData);
374 PacketStatus status = PerformOSCPacket(inWorld, packet, SC_ScheduledEvent::FreeInRT);
375 if (status == PacketPerformed) {
376 World_Free(inWorld, packet);
378 return status;
381 void FreeOSCPacket(FifoMsg *inMsg)
383 OSC_Packet *packet = (OSC_Packet*)inMsg->mData;
384 if (packet) {
385 inMsg->mData = 0;
386 #ifdef _WIN32
387 #pragma message("$$$todo fixme hack for the 'uninitialized packet->mData ptr when using MSVC 7.1 debug")
388 if (packet->mData != reinterpret_cast<char*>(0xcdcdcdcd))
389 free(packet->mData);
390 #else //#ifdef _WIN32
391 free(packet->mData);
392 #endif //#ifdef _WIN32
393 free(packet);
397 void Free_FromEngine_Msg(FifoMsg *inMsg);
398 void Free_FromEngine_Msg(FifoMsg *inMsg)
400 World_Free(inMsg->mWorld, inMsg->mData);
403 // =====================================================================
404 // Audio driver (Common)
406 SC_AudioDriver::SC_AudioDriver(struct World *inWorld)
407 : mWorld(inWorld)
408 , mSampleTime(0)
409 , mNumSamplesPerCallback(0)
414 SC_AudioDriver::~SC_AudioDriver()
416 mRunThreadFlag = false;
417 mAudioSync.Signal();
418 pthread_join(mThread, 0);
421 void* audio_driver_thread_func(void* arg);
422 void* audio_driver_thread_func(void* arg)
424 SC_AudioDriver *ca = (SC_AudioDriver*)arg;
425 void* result = ca->RunThread();
426 return result;
429 void* SC_AudioDriver::RunThread()
431 TriggersFifo *trigfifo = &mWorld->hw->mTriggers;
432 NodeReplyFifo *nodereplyfifo = &mWorld->hw->mNodeMsgs;
433 NodeEndsFifo *nodeendfifo = &mWorld->hw->mNodeEnds;
434 DeleteGraphDefsFifo *deletegraphfifo = &mWorld->hw->mDeleteGraphDefs;
436 while (mRunThreadFlag) {
437 // wait for sync
438 mAudioSync.WaitNext();
440 mWorld->mNRTLock->Lock();
442 // send /tr messages
443 trigfifo->Perform();
445 // send node reply messages
446 nodereplyfifo->Perform();
448 // send node status messages
449 nodeendfifo->Perform();
451 // free GraphDefs
452 deletegraphfifo->Perform();
454 // perform messages
455 mFromEngine.Perform();
457 mWorld->mNRTLock->Unlock();
459 return 0;
462 bool SC_AudioDriver::SendMsgFromEngine(FifoMsg& inMsg)
464 return mFromEngine.Write(inMsg);
468 bool SC_AudioDriver::SendMsgToEngine(FifoMsg& inMsg)
470 mToEngine.Free();
471 return mToEngine.Write(inMsg);
474 bool SC_AudioDriver::SendOscPacketMsgToEngine(FifoMsg& inMsg)
476 mOscPacketsToEngine.Free();
477 return mOscPacketsToEngine.Write(inMsg);
480 void SC_ScheduledEvent::FreeInRT(struct World* world, OSC_Packet* packet)
482 World_Free(world, packet->mData);
483 World_Free(world, packet);
486 void SC_ScheduledEvent::FreeInNRT(struct World* world, OSC_Packet* packet)
488 FifoMsg msg;
489 msg.Set(world, FreeOSCPacket, 0, (void*)packet);
490 world->hw->mAudioDriver->SendMsgFromEngine(msg);
493 void SC_ScheduledEvent::Perform()
495 PerformOSCBundle(mWorld, mPacket);
496 (*mPacketFreeFunc)(mWorld, mPacket);
499 bool SC_AudioDriver::Setup()
501 mRunThreadFlag = true;
502 pthread_create (&mThread, NULL, audio_driver_thread_func, (void*)this);
503 set_real_time_priority(mThread);
505 int numSamples;
506 double sampleRate;
508 if (!DriverSetup(&numSamples, &sampleRate)) return false;
510 mNumSamplesPerCallback = numSamples;
511 //scprintf("mNumSamplesPerCallback %d\n", mNumSamplesPerCallback);
512 //scprintf("mHardwareBufferSize %lu\n", mHardwareBufferSize);
514 // compute a per sample increment to the OpenSoundControl Time
515 mOSCincrementNumerator = (double)mWorld->mBufLength * pow(2.,32.);
516 mOSCincrement = (int64)(mOSCincrementNumerator / sampleRate);
517 mOSCtoSamples = sampleRate / pow(2.,32.);
519 World_SetSampleRate(mWorld, sampleRate);
520 mSampleRate = mSmoothSampleRate = sampleRate;
521 mBuffersPerSecond = sampleRate / mNumSamplesPerCallback;
522 mMaxPeakCounter = (int)mBuffersPerSecond;
524 if(mWorld->mVerbosity >= 0){
525 scprintf("SC_AudioDriver: sample rate = %f, driver's block size = %d\n", sampleRate, mNumSamplesPerCallback);
528 return true;
531 bool SC_AudioDriver::Start()
533 mAvgCPU = 0.;
534 mPeakCPU = 0.;
535 mPeakCounter = 0;
537 mStartHostSecs = 0.;
538 mPrevHostSecs = 0.;
539 mStartSampleTime = 0.;
540 mPrevSampleTime = 0.;
542 World_Start(mWorld);
544 gStartupOSCTime = oscTimeNow();
546 return DriverStart();
549 bool SC_AudioDriver::Stop()
551 if (!DriverStop()) return false;
552 return true;
556 // =====================================================================
557 // Audio driver (CoreAudio)
558 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO
560 SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld)
562 return new SC_CoreAudioDriver(inWorld);
565 #endif
567 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
569 SC_CoreAudioDriver::SC_CoreAudioDriver(struct World *inWorld)
570 : SC_AudioDriver(inWorld)
571 , mInputBufList(0)
575 SC_CoreAudioDriver::~SC_CoreAudioDriver()
577 if (mInputBufList)
579 int i;
580 for (i=0; i<mInputBufList->mNumberBuffers; i++)
582 free(mInputBufList->mBuffers[i].mData);
584 free(mInputBufList);
588 bool SC_CoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
590 OSStatus err = kAudioHardwareNoError;
591 UInt32 count;
592 mOutputDevice = kAudioDeviceUnknown;
593 mInputDevice = kAudioDeviceUnknown;
595 //scprintf("SC_CoreAudioDriver::Setup world %p\n", mWorld);
597 ////////////////////////////////////////////////////////////////////////////////////////////////
599 do {
600 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0);
602 AudioDeviceID *devices = (AudioDeviceID*)malloc(count);
603 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
604 if (err != kAudioHardwareNoError) {
605 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
606 free(devices);
607 break;
610 int numdevices = count / sizeof(AudioDeviceID);
611 if(mWorld->mVerbosity >= 0){
612 scprintf("Number of Devices: %d\n", numdevices);
614 for (int i = 0; i < numdevices; ++i) {
615 err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
616 if (err != kAudioHardwareNoError) {
617 scprintf("info kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]);
618 break;
621 char *name = (char*)malloc(count);
622 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
623 if (err != kAudioHardwareNoError) {
624 scprintf("get kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]);
625 free(name);
626 break;
628 if(mWorld->mVerbosity >= 0){
629 scprintf(" %d : \"%s\"\n", i, name);
631 free(name);
633 free(devices);
634 if(mWorld->mVerbosity >= 0){
635 scprintf("\n");
637 } while (false);
639 if (mWorld->hw->mInDeviceName || mWorld->hw->mOutDeviceName) {
640 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0);
641 if (err != kAudioHardwareNoError) {
642 scprintf("info kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
643 return false;
646 AudioDeviceID *devices = (AudioDeviceID*)malloc(count);
647 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
648 if (err != kAudioHardwareNoError) {
649 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
650 return false;
653 int numdevices = count / sizeof(AudioDeviceID);
654 for (int i = 0; i < numdevices; ++i) {
655 err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
656 if (err != kAudioHardwareNoError) {
657 scprintf("info kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]);
658 break;
661 char *name = (char*)malloc(count);
662 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
663 if (err != kAudioHardwareNoError) {
664 scprintf("get kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]);
665 return false;
667 if (strcmp(name, mWorld->hw->mInDeviceName) == 0) {
668 mInputDevice = devices[i];
670 if (strcmp(name, mWorld->hw->mOutDeviceName) == 0) {
671 mOutputDevice = devices[i];
673 free(name);
674 if (mInputDevice!=kAudioDeviceUnknown && mOutputDevice!=kAudioDeviceUnknown) break;
676 free(devices);
677 if (mOutputDevice==kAudioDeviceUnknown || mInputDevice==kAudioDeviceUnknown) goto getDefault;
678 } else {
679 getDefault:
681 // get the default output device for the HAL
682 if (mOutputDevice==kAudioDeviceUnknown)
684 count = sizeof(mOutputDevice);
685 //get the output device:
686 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) & mOutputDevice);
687 if (err != kAudioHardwareNoError) {
688 scprintf("get kAudioHardwarePropertyDefaultOutputDevice error %4.4s\n", (char*)&err);
689 return false;
693 //get the input device
694 if (mInputDevice==kAudioDeviceUnknown)
696 count = sizeof(mInputDevice);
697 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &count, (void *) & mInputDevice);
698 //get the input device:
699 if (err != kAudioHardwareNoError) {
700 scprintf("get kAudioHardwarePropertyDefaultInputDevice error %4.4s\n", (char*)&err);
701 return false;
706 ////////////////////////////////////////////////////////////////////////////////////////////////
708 AudioTimeStamp now;
709 now.mFlags = kAudioTimeStampHostTimeValid;
710 now.mHostTime = AudioGetCurrentHostTime();
712 if (mPreferredHardwareBufferFrameSize)
715 count = sizeof(UInt32);
716 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize);
717 if (err != kAudioHardwareNoError) {
718 scprintf("set kAudioDevicePropertyBufferFrameSize error %4.4s\n", (char*)&err);
719 //return false;
721 if (UseSeparateIO())
723 count = sizeof(UInt32);
724 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize);
725 if (err != kAudioHardwareNoError) {
726 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
727 //return false;
732 if (mPreferredSampleRate)
734 Float64 sampleRate = mPreferredSampleRate;
735 count = sizeof(Float64);
736 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
737 if (err != kAudioHardwareNoError) {
738 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
739 //return false;
741 if (UseSeparateIO())
743 count = sizeof(Float64);
744 err = AudioDeviceSetProperty(mInputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
745 if (err != kAudioHardwareNoError) {
746 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
747 //return false;
752 // get the buffersize for the out device
753 count = sizeof(mHardwareBufferSize);
754 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyBufferSize, &count, &mHardwareBufferSize);
755 if (err != kAudioHardwareNoError) {
756 scprintf("get kAudioDevicePropertyBufferSize error %4.4s\n", (char*)&err);
757 return false;
759 //scprintf("mHardwareBufferSize = %ld\n", mHardwareBufferSize);
761 // get a description of the data format used by the output device
762 count = sizeof(AudioStreamBasicDescription);
763 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDesc);
764 if (err != kAudioHardwareNoError) {
765 scprintf("get kAudioDevicePropertyStreamFormat error %4.4s\n", (char*)&err);
766 return false;
769 if (mInputDevice != kAudioDeviceUnknown) {
770 // get a description of the data format used by the input device
771 count = sizeof(AudioStreamBasicDescription);
772 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamFormat, &count, &inputStreamDesc);
773 if (err != kAudioHardwareNoError) {
774 scprintf("get kAudioDevicePropertyStreamFormat error %4.4s\n", (char*)&err);
775 return false;
778 if (inputStreamDesc.mSampleRate != outputStreamDesc.mSampleRate) {
779 scprintf("input and output sample rates do not match. %g != %g\n", inputStreamDesc.mSampleRate, outputStreamDesc.mSampleRate);
780 return false;
784 ////////////////////////////////////////////////////////////////////////////////////////////////
786 do {
787 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
788 if (err != kAudioHardwareNoError) {
789 scprintf("info kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice);
790 break;
793 char *name = (char*)malloc(count);
794 err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name);
795 if (err != kAudioHardwareNoError) {
796 scprintf("get kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice);
797 free(name);
798 break;
801 if(mWorld->mVerbosity >= 0){
802 scprintf("\"%s\" Input Device\n", name);
804 free(name);
806 Boolean writeable;
807 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration,
808 &count, &writeable);
809 if (err != kAudioHardwareNoError) {
810 scprintf("info kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
811 break;
814 AudioBufferList *bufList = (AudioBufferList*)malloc(count);
815 err = AudioDeviceGetProperty(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration,
816 &count, bufList);
817 if (err != kAudioHardwareNoError) {
818 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
819 free(bufList);
820 break;
823 if(mWorld->mVerbosity >= 0){
824 scprintf(" Streams: %d\n", bufList->mNumberBuffers);
825 for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) {
826 scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels);
830 free(bufList);
831 } while (false);
832 if(mWorld->mVerbosity >= 0){
833 scprintf("\n");
836 ////////////////////////////////////////////////////////////////////////////////////////////////
838 do {
839 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
841 char *name = (char*)malloc(count);
842 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name);
843 if (err != kAudioHardwareNoError) {
844 scprintf("get kAudioDevicePropertyDeviceName error %4.4s\n", (char*)&err);
845 free(name);
846 break;
849 if(mWorld->mVerbosity >= 0){
850 scprintf("\"%s\" Output Device\n", name);
852 free(name);
854 Boolean writeable;
855 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration,
856 &count, &writeable);
857 if (err != kAudioHardwareNoError) {
858 scprintf("info kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
859 break;
862 AudioBufferList *bufList = (AudioBufferList*)malloc(count);
863 err = AudioDeviceGetProperty(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration,
864 &count, bufList);
865 if (err != kAudioHardwareNoError) {
866 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
867 free(bufList);
868 break;
871 if(mWorld->mVerbosity >= 0){
872 scprintf(" Streams: %d\n", bufList->mNumberBuffers);
873 for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) {
874 scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels);
877 free(bufList);
878 } while (false);
879 if(mWorld->mVerbosity >= 0){
880 scprintf("\n");
883 ////////////////////////////////////////////////////////////////////////////////////////////////
886 if (UseSeparateIO()) {
887 count = sizeof(UInt32);
888 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertySafetyOffset, &count, &mSafetyOffset);
889 if (err != kAudioHardwareNoError) {
890 scprintf("get kAudioDevicePropertySafetyOffset error %4.4s\n", (char*)&err);
891 return false;
893 if(mWorld->mVerbosity >= 1){
894 scprintf("mSafetyOffset %lu\n", mSafetyOffset);
897 Boolean writeable;
898 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, &writeable);
899 mInputBufList = (AudioBufferList*)malloc(count);
900 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, mInputBufList);
901 if (err != kAudioHardwareNoError) {
902 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
903 return false;
906 if(mWorld->mVerbosity >= 1){
907 scprintf("mNumberBuffers %lu\n", mInputBufList->mNumberBuffers);
909 for (uint32 i=0; i<mInputBufList->mNumberBuffers; ++i) {
910 if(mWorld->mVerbosity >= 1){
911 scprintf(" mDataByteSize %d %lu\n", i, mInputBufList->mBuffers[i].mDataByteSize);
913 mInputBufList->mBuffers[i].mData = zalloc(1, mInputBufList->mBuffers[i].mDataByteSize);
917 AudioTimeStamp now;
918 now.mFlags = kAudioTimeStampHostTimeValid;
919 now.mHostTime = AudioGetCurrentHostTime();
922 err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyRegisterBufferList, count, mInputBufList);
923 if (err != kAudioHardwareNoError) {
924 scprintf("get kAudioDevicePropertyRegisterBufferList error %4.4s\n", (char*)&err);
925 return false;
930 *outNumSamplesPerCallback = mHardwareBufferSize / outputStreamDesc.mBytesPerFrame;
931 *outSampleRate = outputStreamDesc.mSampleRate;
933 if(mWorld->mVerbosity >= 1){
934 scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld);
939 //check if using built-in output, and thus whether there could be headphone plug/un-plug issues
940 //our assumption otherwise is that we don't respond, and SC will stay with the pre-arranged or default device, and not restart just because headphones switched
942 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
943 if (err != kAudioHardwareNoError) {
944 scprintf("info kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice);
945 return false;
948 char *outputname = (char*)malloc(count);
949 const char *testname = "Built-in Output";
950 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, outputname);
951 if (err != kAudioHardwareNoError) {
952 scprintf("get kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice);
953 return false;
955 builtinoutputflag_ = 0;
957 if (strcmp(testname, outputname) == 0) {
958 builtinoutputflag_ = 1;
960 // else {
962 // //check for an Aggregate Devices with a subdevice which is Built-in Output
963 // //http://lists.apple.com/archives/coreaudio-api/2009/Oct/msg00182.html
966 // }
968 free(outputname);
971 return true;
975 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
976 const AudioBufferList* inInputData,
977 const AudioTimeStamp* inInputTime,
978 AudioBufferList* outOutputData,
979 const AudioTimeStamp* inOutputTime,
980 void* defptr);
981 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
982 const AudioBufferList* inInputData,
983 const AudioTimeStamp* inInputTime,
984 AudioBufferList* outOutputData,
985 const AudioTimeStamp* inOutputTime,
986 void* defptr)
988 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
990 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
992 AudioTimeStamp readTime;
993 readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback();
994 readTime.mFlags = kAudioTimeStampSampleTimeValid;
996 AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList());
998 def->Run(def->GetInputBufferList(), outOutputData, oscTime);
1000 return kAudioHardwareNoError;
1005 OSStatus appIOProcSeparateIn (AudioDeviceID device, const AudioTimeStamp* inNow,
1006 const AudioBufferList* inInputData,
1007 const AudioTimeStamp* inInputTime,
1008 AudioBufferList* outOutputData,
1009 const AudioTimeStamp* inOutputTime,
1010 void* defptr)
1012 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1014 // copy input data to driver's private buffer list
1015 int i;
1016 for (i=0; i<inInputData->mNumberBuffers; i++)
1018 memcpy(def->mInputBufList->mBuffers[i].mData, inInputData->mBuffers[i].mData, inInputData->mBuffers[i].mDataByteSize);
1021 return kAudioHardwareNoError;
1024 OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow,
1025 const AudioBufferList* inInputData,
1026 const AudioTimeStamp* inInputTime,
1027 AudioBufferList* outOutputData,
1028 const AudioTimeStamp* inOutputTime,
1029 void* defptr)
1031 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1032 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
1034 double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9;
1035 double sampleTime = inOutputTime->mSampleTime;
1036 if (def->mStartHostSecs == 0) {
1037 def->mStartHostSecs = hostSecs;
1038 def->mStartSampleTime = sampleTime;
1039 } else {
1040 double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs);
1041 double smoothSampleRate = def->mSmoothSampleRate;
1042 smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
1043 def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate);
1044 def->mSmoothSampleRate = smoothSampleRate;
1046 #if 0
1047 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs);
1048 double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime);
1049 double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs);
1050 //if (fabs(jitter) > 0.01) {
1051 scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n",
1052 avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement);
1054 #endif
1056 def->mPrevHostSecs = hostSecs;
1057 def->mPrevSampleTime = sampleTime;
1059 if (!def->UseSeparateIO())
1061 def->Run(inInputData, outOutputData, oscTime);
1062 return kAudioHardwareNoError;
1066 def->Run(def->mInputBufList, outOutputData, oscTime);
1067 return kAudioHardwareNoError;
1070 void SC_CoreAudioDriver::Run(const AudioBufferList* inInputData,
1071 AudioBufferList* outOutputData, int64 oscTime)
1073 int64 systemTimeBefore = AudioGetCurrentHostTime();
1074 World *world = mWorld;
1076 try {
1077 int numSamplesPerCallback = NumSamplesPerCallback();
1078 mOSCbuftime = oscTime;
1080 #ifdef __APPLE__
1081 sc_SetDenormalFlags();
1082 #endif
1084 mFromEngine.Free();
1085 /*if (mToEngine.HasData()) {
1086 scprintf("oscTime %.9f %.9f\n", oscTime*kOSCtoSecs, CoreAudioHostTimeToOSC(AudioGetCurrentHostTime())*kOSCtoSecs);
1088 mToEngine.Perform();
1089 mOscPacketsToEngine.Perform();
1091 int bufFrames = world->mBufLength;
1092 int numBufs = numSamplesPerCallback / bufFrames;
1094 int numInputBuses = world->mNumInputs;
1095 int numOutputBuses = world->mNumOutputs;
1096 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
1097 float* outputBuses = world->mAudioBus;
1098 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
1099 int32* outputTouched = world->mAudioBusTouched;
1100 int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0;
1101 int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0;
1103 //static int go = 0;
1105 int64 oscInc = mOSCincrement;
1106 double oscToSamples = mOSCtoSamples;
1108 int bufFramePos = 0;
1110 for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) {
1111 int32 bufCounter = world->mBufCounter;
1113 // de-interleave input
1114 if (inInputData) {
1115 const AudioBuffer* inInputDataBuffers = inInputData->mBuffers;
1116 for (int s = 0, b = 0; b<numInputBuses && s < numInputStreams; s++) {
1117 const AudioBuffer* buf = inInputDataBuffers + s;
1118 int nchan = buf->mNumberChannels;
1119 if (buf->mData) {
1120 float *busdata = inputBuses + b * bufFrames;
1121 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1122 if (nchan == 1) {
1123 for (int k=0; k<bufFrames; ++k) {
1124 busdata[k] = bufdata[k];
1126 inputTouched[b] = bufCounter;
1127 } else {
1128 int minchan = sc_min(nchan, numInputBuses - b);
1129 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1130 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1131 busdata[k] = bufdata[m];
1133 inputTouched[b+j] = bufCounter;
1136 b += nchan;
1140 //count++;
1142 int64 schedTime;
1143 int64 nextTime = oscTime + oscInc;
1145 /*if (mScheduler.Ready(nextTime)) {
1146 double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs;
1147 scprintf("rdy %.9f %.9f %.9f\n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff);
1150 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
1151 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
1152 float diffTimeFloor = floor(diffTime);
1153 world->mSampleOffset = (int)diffTimeFloor;
1154 world->mSubsampleOffset = diffTime - diffTimeFloor;
1156 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
1157 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
1159 SC_ScheduledEvent event = mScheduler.Remove();
1160 event.Perform();
1162 world->mSampleOffset = 0;
1163 world->mSubsampleOffset = 0.f;
1165 World_Run(world);
1167 // interleave output
1168 AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers;
1169 for (int s = 0, b = 0; b<numOutputBuses && s < numOutputStreams; s++) {
1170 AudioBuffer* buf = outOutputDataBuffers + s;
1171 int nchan = buf->mNumberChannels;
1172 if (buf->mData) {
1173 float *busdata = outputBuses + b * bufFrames;
1174 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1175 if (nchan == 1) {
1176 if (outputTouched[b] == bufCounter) {
1177 for (int k=0; k<bufFrames; ++k) {
1178 bufdata[k] = busdata[k];
1181 } else {
1182 int minchan = sc_min(nchan, numOutputBuses - b);
1183 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1184 if (outputTouched[b+j] == bufCounter) {
1185 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1186 bufdata[m] = busdata[k];
1191 b += nchan;
1194 oscTime = mOSCbuftime = nextTime;
1196 } catch (std::exception& exc) {
1197 scprintf("exception in real time: %s\n", exc.what());
1198 } catch (...) {
1199 scprintf("unknown exception in real time\n");
1201 int64 systemTimeAfter = AudioGetCurrentHostTime();
1202 double calcTime = (double)AudioConvertHostTimeToNanos(systemTimeAfter - systemTimeBefore) * 1e-9;
1203 double cpuUsage = calcTime * mBuffersPerSecond * 100.;
1204 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
1205 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
1207 mPeakCPU = cpuUsage;
1208 mPeakCounter = mMaxPeakCounter;
1211 mAudioSync.Signal();
1217 //////////////////////////////////////////////////////////////////////////////////////////
1218 //////////////////////////////////////////////////////////////////////////////////////////
1219 //////////////////////////////////////////////////////////////////////////////////////////
1220 // These are not linked in yet, but we'll need to listen for the properties and stop/restart synthesis
1221 // if sample-rate, format, or device change.
1223 OSStatus hardwareListenerProc ( AudioHardwarePropertyID inPropertyID,
1224 void* inClientData)
1226 OSStatus err = noErr;
1227 char cStr[255];
1228 UInt32 outSize;
1229 Boolean outWritable;
1230 AudioDeviceID deviceID;
1232 switch(inPropertyID)
1234 case kAudioHardwarePropertyDefaultOutputDevice:
1235 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultOutputDevice\r");
1236 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &outWritable);
1237 if (err) break;
1238 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &deviceID);
1239 if (err) break;
1240 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1241 if (err) break;
1242 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1243 if (err) break;
1245 // do something
1247 break;
1249 case kAudioHardwarePropertyDefaultInputDevice:
1250 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultInputDevice\r");
1251 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultInputDevice, &outSize, &outWritable);
1252 if (err) break;
1253 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &outSize, &deviceID);
1254 if (err) break;
1255 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1256 if (err) break;
1257 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1258 if (err) break;
1260 // do something
1262 break;
1264 case kAudioHardwarePropertyDefaultSystemOutputDevice:
1265 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultSystemOutputDevice\r");
1266 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &outWritable);
1267 if (err) break;
1268 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &deviceID);
1269 if (err) break;
1270 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1271 if (err) break;
1272 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1273 if (err) break;
1275 // do something
1277 break;
1279 case kAudioHardwarePropertyDevices:
1281 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDevices\r");
1283 break;
1284 default:
1285 scprintf("%s\n", "***** HARDWARE NOTIFICATION - %4.4s\r", &inPropertyID);
1288 fflush(stdout);
1289 return (noErr);
1295 OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData);
1297 OSStatus AddHardwareListeners(void* inClientData);
1298 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1299 OSStatus AddHardwareListeners(void* inClientData)
1301 OSStatus err = noErr;
1303 //non deprecated but requires AudiObject, bleargh
1304 //err= AudioObjectAddPropertyListener(AudioObject, kAudioHardwarePropertyDefaultOutputDevice, hardwareListenerProc, inClientData);
1306 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultOutputDevice, hardwareListenerProc, inClientData);
1307 if (err) return err;
1309 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultInputDevice, hardwareListenerProc, inClientData);
1310 if (err) return err;
1312 //doesn't matter? Only default looked at by SC?
1313 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultSystemOutputDevice, hardwareListenerProc, inClientData);
1314 if (err) return err;
1316 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, hardwareListenerProc, inClientData);
1317 if (err) return err;
1319 return (err);
1322 bool SC_CoreAudioDriver::DriverStart()
1324 if(mWorld->mVerbosity >= 1){
1325 scprintf("->SC_CoreAudioDriver::DriverStart\n");
1327 OSStatus err = kAudioHardwareNoError;
1328 AudioTimeStamp now;
1329 UInt32 propertySize;
1330 Boolean writable;
1332 if(mWorld->mVerbosity >= 1){
1333 scprintf("start UseSeparateIO?: %d\n", UseSeparateIO());
1336 try {
1337 if (UseSeparateIO()) {
1338 err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup Out device with an IO proc
1339 if (err != kAudioHardwareNoError) {
1340 scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err);
1341 return false;
1344 err = AudioDeviceAddIOProc(mInputDevice, appIOProcSeparateIn, (void *) this); // setup In device with an IO proc
1345 if (err != kAudioHardwareNoError) {
1346 scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err);
1347 return false;
1351 if (mWorld->hw->mInputStreamsEnabled) {
1352 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1353 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1354 su->mIOProc = (void*)appIOProcSeparateIn;
1355 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1356 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled));
1357 for (int i=0; i<len; ++i) {
1358 su->mStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1';
1360 err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1363 if (mWorld->hw->mOutputStreamsEnabled) {
1364 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1365 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1366 su->mIOProc = (void*)appIOProc;
1367 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1368 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled));
1369 for (int i=0; i<len; ++i) {
1370 su->mStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1';
1372 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1375 err = AudioDeviceStart(mInputDevice, appIOProcSeparateIn); // start playing sound through the device
1376 if (err != kAudioHardwareNoError) {
1377 scprintf("AudioDeviceStart failed %d\n", (int)err);
1378 return false;
1381 err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device
1382 if (err != kAudioHardwareNoError) {
1383 scprintf("AudioDeviceStart failed %d\n", (int)err);
1384 err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn); // stop playing sound through the device
1385 return false;
1387 } else {
1388 err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup our device with an IO proc
1389 if (err != kAudioHardwareNoError) {
1390 scprintf("AudioDeviceAddIOProc failed %d\n", (int)err);
1391 return false;
1394 if (mWorld->hw->mInputStreamsEnabled) {
1395 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1396 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1397 su->mIOProc = (void*)appIOProc;
1398 err = AudioDeviceGetProperty(mOutputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1399 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled));
1400 for (int i=0; i<len; ++i) {
1401 su->mStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1';
1403 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1406 if (mWorld->hw->mOutputStreamsEnabled) {
1407 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1408 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1409 su->mIOProc = (void*)appIOProc;
1410 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1411 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled));
1412 for (int i=0; i<len; ++i) {
1413 su->mStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1';
1415 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1418 err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device
1419 if (err != kAudioHardwareNoError) {
1420 scprintf("AudioDeviceStart failed %d\n", (int)err);
1421 return false;
1424 } catch (...) {
1425 scprintf("exception in SC_CoreAudioDriver::DriverStart\n");
1427 if(mWorld->mVerbosity >= 1){
1428 scprintf("<-SC_CoreAudioDriver::DriverStart\n");
1432 //http://lists.apple.com/archives/coreaudio-api/2010/Aug/msg00114.html
1433 CFRunLoopRef theRunLoop = NULL;
1434 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1435 AudioObjectSetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
1437 //for now no spotting of hardware changes, assumption is that ServerOptions inviolate. However, if a device was unplugged, could react to loss of that device
1438 //by switching to system default?
1439 //AddHardwareListeners(NULL);
1440 //note that the number of listeners is stripped down to only one for now, to react to headphone swaps in the case of Built-in Output
1441 AddDeviceListeners(mOutputDevice, this);
1443 return true;
1447 bool SC_CoreAudioDriver::StopStart() {
1449 bool test = DriverStop();
1451 bool test2 = DriverStart();
1452 return test && test2;
1456 bool SC_CoreAudioDriver::DriverStop()
1458 if(mWorld->mVerbosity >= 1){
1459 scprintf("->SC_CoreAudioDriver::DriverStop\n");
1461 OSStatus err = kAudioHardwareNoError;
1463 if (UseSeparateIO()) {
1464 err = AudioDeviceStop(mOutputDevice, appIOProc);
1465 if (err != kAudioHardwareNoError) {
1466 scprintf("AudioDeviceStop A failed %p\n", err);
1467 return false;
1469 err = AudioDeviceRemoveIOProc(mOutputDevice, appIOProc);
1470 if (err != kAudioHardwareNoError) {
1471 scprintf("AudioDeviceRemoveIOProc A failed %p\n", err);
1472 return false;
1475 err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn);
1476 if (err != kAudioHardwareNoError) {
1477 scprintf("AudioDeviceStop A failed %p\n", err);
1478 return false;
1481 err = AudioDeviceRemoveIOProc(mInputDevice, appIOProcSeparateIn);
1482 if (err != kAudioHardwareNoError) {
1483 scprintf("AudioDeviceRemoveIOProc A failed %p\n", err);
1484 return false;
1486 } else {
1487 err = AudioDeviceStop(mOutputDevice, appIOProc);
1488 if (err != kAudioHardwareNoError) {
1489 scprintf("AudioDeviceStop B failed %p\n", err);
1490 return false;
1493 err = AudioDeviceRemoveIOProc(mOutputDevice, appIOProc);
1494 if (err != kAudioHardwareNoError) {
1495 scprintf("AudioDeviceRemoveIOProc B failed %p\n", err);
1496 return false;
1499 if(mWorld->mVerbosity >= 1){
1500 scprintf("<-SC_CoreAudioDriver::DriverStop\n");
1502 return true;
1506 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1507 // Listen for Device Properties and update interface and globals
1508 OSStatus deviceListenerProc ( AudioDeviceID inDevice,
1509 UInt32 inLine,
1510 Boolean isInput,
1511 AudioDevicePropertyID inPropertyID,
1512 void* inClientData)
1514 OSStatus err = noErr;
1515 UInt32 outSize,
1516 theUIntData,
1517 mute,
1518 playThru;
1519 UInt32 tLong;
1520 Float32 vol;
1523 SC_CoreAudioDriver* coredriver = (SC_CoreAudioDriver*) inClientData;
1525 switch(inPropertyID)
1527 // case kAudioDevicePropertyBufferSize:
1528 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferSize\r");
1529 // outSize = sizeof(UInt32);
1530 // err = AudioDeviceGetProperty(inDevice, 0, 0, kAudioDevicePropertyBufferSize, &outSize, &theUIntData);
1532 // break;
1534 // case kAudioDevicePropertyBufferFrameSize:
1535 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferFrameSize\r");
1536 // outSize = sizeof(UInt32);
1537 // err = AudioDeviceGetProperty(inDevice, 0, 0, kAudioDevicePropertyBufferFrameSize, &outSize, &theUIntData);
1539 // break;
1541 // case kAudioDevicePropertyBufferSizeRange:
1542 // {
1543 // AudioValueRange range;
1545 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferSizeRange\r");
1546 // outSize = sizeof(AudioValueRange);
1547 // err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyBufferSizeRange, &outSize, &range);
1548 // }
1549 // break;
1551 // case kAudioDevicePropertyStreamFormat:
1552 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyStreamFormat\r");
1553 // break;
1555 // case kAudioDevicePropertyDeviceIsRunning:
1556 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDeviceIsRunning\r");
1557 // outSize = sizeof(UInt32);
1558 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyDeviceIsRunning, &outSize, &theUIntData);
1560 // //when change device get up to four messages:
1561 // //isInput ==NO or YES theUIntData= 0 or 1 from old and possibly new device (ieheadphone swap)
1565 // break;
1567 // case kAudioDevicePropertyVolumeScalar:
1568 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyVolumeScalar\r");
1569 // outSize = sizeof(Float32);
1570 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyVolumeScalar, &outSize, &vol);
1571 // break;
1573 // case kAudioDevicePropertyMute:
1574 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyMute\r");
1575 // outSize = sizeof(UInt32);
1576 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyMute, &outSize, &mute);
1577 // break;
1579 // case kAudioDevicePropertyPlayThru:
1580 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyPlayThru\r");
1581 // outSize = sizeof(UInt32);
1582 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyPlayThru, &outSize, &playThru);
1584 // break;
1586 // case kAudioDevicePropertyDeviceIsAlive:
1587 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDeviceIsAlive\r");
1588 // outSize = sizeof(UInt32);
1589 // err = AudioDeviceGetProperty(inDevice, 0, false, kAudioDevicePropertyDeviceIsAlive, &outSize, &tLong);
1591 // break;
1593 case kAudioDevicePropertyDataSource:
1594 //Don't print anything
1595 //scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDataSource\r");
1596 // get the source
1597 // match the source to one of the available sources and return the index of that source
1598 //SetControlValue(control, (chan->vol) * 100);
1600 //will get this message anyway even if don't have built-in output seleected.
1601 //so need to react based on whether current output IS built-in output. Annoyingly, headphone unplugging/plugging also sends default and system output + default input change hardware messages
1602 //swapping to new driver
1603 if (coredriver->builtinoutputflag_==1)
1604 coredriver->StopStart();
1607 break;
1609 //default:
1610 // scprintf("%s\n", "***** DEVICE NOTIFICATION - %4.4s\r", &inPropertyID);
1613 //fflush(stdout);
1614 return (err);
1617 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1618 OSStatus streamListenerProc ( AudioStreamID inStream,
1619 UInt32 inChannel,
1620 AudioDevicePropertyID inPropertyID,
1621 void* inClientData)
1623 OSStatus err = noErr;
1625 switch(inPropertyID)
1627 case kAudioStreamPropertyPhysicalFormat:
1628 scprintf("%s\n", "***** STREAM NOTIFICATION - kAudioStreamPropertyPhysicalFormat\r");
1629 break;
1631 case kAudioDevicePropertyStreamFormat:
1632 scprintf("%s\n", "***** STREAM NOTIFICATION - kAudioDevicePropertyStreamFormat\r");
1633 break;
1635 default:
1636 break;
1639 fflush(stdout);
1641 return (err);
1644 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1645 OSStatus AddStreamListeners (AudioDeviceID inDevice, AudioDevicePropertyID inPropertyID, Boolean isInput, void *inClientData);
1647 OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData)
1649 OSStatus err = noErr;
1651 //ONLY REACTING TO HEADPHONE SWAPS FOR NOW
1655 // // kAudioDevicePropertyBufferSize
1656 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferSize, deviceListenerProc, inClientData);
1657 // if (err) return err;
1659 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferSize, deviceListenerProc, inClientData);
1660 // if (err) return err;
1663 // // kAudioDevicePropertyBufferFrameSize
1664 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferFrameSize, deviceListenerProc, inClientData);
1665 // if (err) return err;
1667 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferFrameSize, deviceListenerProc, inClientData);
1668 // if (err) return err;
1670 // // kAudioDevicePropertyDeviceIsRunning
1671 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDeviceIsRunning, deviceListenerProc, inClientData);
1672 // if (err) return err;
1674 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDeviceIsRunning, deviceListenerProc, inClientData);
1675 // if (err) return err;
1677 ///*
1678 // for (i = 0; i <= deviceInfo->totalOutputChannels; i++)
1679 // {
1680 // // kAudioDevicePropertyVolumeScalar output
1681 // err = AudioDeviceAddPropertyListener(inDevice, i, false, kAudioDevicePropertyVolumeScalar, deviceListenerProc, inClientData);
1682 // if (err) return err;
1684 // // kAudioDevicePropertyVolumeMute output
1685 // err = AudioDeviceAddPropertyListener(inDevice, i, false, kAudioDevicePropertyMute, deviceListenerProc, inClientData);
1686 // if (err) return err;
1687 // }
1689 // for (i = 0; i <= deviceInfo->totalInputChannels; i++)
1690 // {
1691 // // kAudioDevicePropertyVolumeScalar input
1692 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyVolumeScalar, deviceListenerProc, inClientData);
1693 // if (err) return err;
1695 // // kAudioDevicePropertyVolumeMute input
1696 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyMute, deviceListenerProc, inClientData);
1697 // if (err) return err;
1699 // // kAudioDevicePropertyPlayThru input
1700 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyPlayThru, deviceListenerProc, inClientData);
1701 // if (err) return err;
1702 // }
1703 //*/
1705 // // kAudioDevicePropertyDeviceIsAlive
1706 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDeviceIsAlive, deviceListenerProc, inClientData);
1707 // if (err) return err;
1709 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDeviceIsAlive, deviceListenerProc, inClientData);
1710 // if (err) return err;
1713 // // kAudioDevicePropertyStreamFormat
1714 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyStreamFormat, deviceListenerProc, inClientData);
1715 // if (err) return err;
1717 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyStreamFormat, deviceListenerProc, inClientData);
1718 // if (err) return err;
1720 // // kAudioDevicePropertyBufferSizeRange
1721 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferSizeRange, deviceListenerProc, inClientData);
1722 // if (err) return err;
1724 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferSizeRange, deviceListenerProc, inClientData);
1725 // if (err) return err;
1727 //kAudioDevicePropertyDataSource
1728 err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDataSource, deviceListenerProc, inClientData);
1729 if (err) return err;
1731 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDataSource, deviceListenerProc, inClientData);
1732 // if (err) return err;
1735 //AddStreamListeners (inDevice, kAudioStreamPropertyPhysicalFormat, false, inClientData);
1737 //AddStreamListeners (inDevice, kAudioStreamPropertyPhysicalFormat, true, inClientData);
1739 return (err);
1744 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1745 OSStatus AddStreamListeners (AudioDeviceID inDevice, AudioDevicePropertyID inPropertyID, Boolean isInput, void *inClientData)
1747 OSStatus err = noErr;
1748 UInt32 count;
1749 UInt32 outSize;
1750 Boolean outWritable;
1751 AudioStreamID *streamList = nil;
1753 err = AudioDeviceGetPropertyInfo(inDevice, 0, isInput, kAudioDevicePropertyStreams, &outSize, &outWritable);
1754 if (err == noErr)
1756 streamList = (AudioStreamID*)malloc(outSize);
1757 err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyStreams, &outSize, streamList);
1758 if (err == noErr)
1760 for (count = 0; count < (outSize / sizeof(AudioStreamID)); count++)
1762 err = AudioStreamAddPropertyListener(streamList[count], 0, inPropertyID, streamListenerProc, inClientData);
1763 if (err) return err;
1766 if (streamList != nil)
1768 free(streamList);
1769 streamList = nil;
1774 return (noErr);
1776 #endif // SC_AUDIO_API_COREAUDIO
1781 // =====================================================================
1782 // Audio driver (CoreAudioIPHONE)
1784 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
1785 SC_iCoreAudioDriver::SC_iCoreAudioDriver(struct World *inWorld)
1786 : SC_AudioDriver(inWorld)
1788 receivedIn = 0;
1791 SC_iCoreAudioDriver::~SC_iCoreAudioDriver()
1796 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
1797 const AudioBufferList* inInputData,
1798 const AudioTimeStamp* inInputTime,
1799 AudioBufferList* outOutputData,
1800 const AudioTimeStamp* inOutputTime,
1801 void* defptr);
1802 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
1803 const AudioBufferList* inInputData,
1804 const AudioTimeStamp* inInputTime,
1805 AudioBufferList* outOutputData,
1806 const AudioTimeStamp* inOutputTime,
1807 void* defptr)
1809 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1811 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
1813 AudioTimeStamp readTime;
1814 readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback();
1815 readTime.mFlags = kAudioTimeStampSampleTimeValid;
1817 AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList());
1819 def->Run(def->GetInputBufferList(), outOutputData, oscTime);
1821 return kAudioHardwareNoError;
1826 OSStatus InputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
1828 SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon;
1830 if (driver->receivedIn)
1832 //printf("exit input with no data \n");
1833 return noErr;
1836 OSStatus ret = AudioUnitRender(driver->inputUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, driver->buflist);
1837 if (ret)
1839 //printf("no input !\n");
1840 return noErr;
1842 driver->receivedIn = 1;
1844 return noErr;
1847 OSStatus RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
1849 SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon;
1851 #ifndef SC_IPHONE
1852 if (!driver->receivedIn)
1854 //printf("exit output with no data \n");
1855 return noErr;
1857 #endif
1859 //float *fbuffer = (float *) driver->converter_buffer;
1861 int i;
1862 for (i=0; i<inNumberFrames; i++)
1864 signed short s = ((signed short *)driver->buflist->mBuffers[0].mData)[i];
1865 int k = s + 0x43c00000;
1866 float f = *((float *) &k);
1867 ((float *)driver->floatInputList->mBuffers[0].mData)[i] = f - 384.0f;
1870 int64 oscTime = GetCurrentOSCTime();
1871 //driver->Run(driver->floatInputList, driver->floatOutputList, oscTime);
1872 driver->Run(driver->floatInputList, ioData, oscTime);
1874 for (i=0; i<inNumberFrames; i++)
1876 float f1 = ((float *)ioData->mBuffers[0].mData)[i];
1877 float f2 = ((float *)ioData->mBuffers[1].mData)[i];
1878 ((int *) ioData->mBuffers[0].mData)[i] = (int) (f1*16777216);
1879 ((int *) ioData->mBuffers[1].mData)[i] = (int) (f2*16777216);
1884 unsigned long size = 2*1024*sizeof(unsigned long);
1885 OSStatus ret = AudioConverterConvertBuffer(driver->converter_in_to_F32, driver->buflist->mBuffers[0].mDataByteSize, driver->buflist->mBuffers[0].mData, &size, driver->converter_buffer);
1886 if (ret)
1888 printf("couldn't convert !\n");
1889 return noErr;
1892 int i;
1893 for (i=0; i<inNumberFrames; i++)
1895 ((int *)ioData->mBuffers[0].mData)[i] = ((int *)ioData->mBuffers[1].mData)[i] = driver->converter_buffer[2*i];
1898 driver->receivedIn = 0;
1899 return noErr;
1904 void SC_iCoreAudioDriver::Run(const AudioBufferList* inInputData,
1905 AudioBufferList* outOutputData, int64 oscTime)
1907 int64 systemTimeBefore = GetMicroseconds();
1909 World *world = mWorld;
1911 try {
1912 int numSamplesPerCallback = NumSamplesPerCallback();
1913 mOSCbuftime = oscTime;
1915 #ifdef __APPLE__
1916 sc_SetDenormalFlags();
1917 #endif
1919 mFromEngine.Free();
1921 mToEngine.Perform();
1922 mOscPacketsToEngine.Perform();
1923 //printf("mOscPacketsToEngine : %d micros\n", (int) (GetMicroseconds()-systemTimeBefore));
1925 int bufFrames = world->mBufLength;
1926 int numBufs = numSamplesPerCallback / bufFrames;
1928 int numInputBuses = world->mNumInputs;
1929 int numOutputBuses = world->mNumOutputs;
1930 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
1931 float* outputBuses = world->mAudioBus;
1932 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
1933 int32* outputTouched = world->mAudioBusTouched;
1934 int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0;
1935 int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0;
1937 //static int go = 0;
1939 int64 oscInc = mOSCincrement;
1940 double oscToSamples = mOSCtoSamples;
1942 int bufFramePos = 0;
1944 for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) {
1945 int32 bufCounter = world->mBufCounter;
1947 // de-interleave input
1948 if (inInputData) {
1949 const AudioBuffer* inInputDataBuffers = inInputData->mBuffers;
1950 for (int s = 0, b = 0; b<numInputBuses && s < numInputStreams; s++) {
1951 const AudioBuffer* buf = inInputDataBuffers + s;
1952 int nchan = buf->mNumberChannels;
1953 if (buf->mData) {
1954 float *busdata = inputBuses + b * bufFrames;
1955 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1956 if (nchan == 1)
1958 #ifdef IPHONE_VEC
1959 vcopy(busdata, bufdata, bufFrames);
1960 #else
1961 for (int k=0; k<bufFrames; ++k)
1963 busdata[k] = bufdata[k];
1965 #endif
1966 inputTouched[b] = bufCounter;
1967 } else {
1968 int minchan = sc_min(nchan, numInputBuses - b);
1969 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1970 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1971 busdata[k] = bufdata[m];
1973 inputTouched[b+j] = bufCounter;
1976 b += nchan;
1980 //count++;
1982 int64 schedTime;
1983 int64 nextTime = oscTime + oscInc;
1985 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
1986 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
1987 float diffTimeFloor = floor(diffTime);
1988 world->mSampleOffset = (int)diffTimeFloor;
1989 world->mSubsampleOffset = diffTime - diffTimeFloor;
1991 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
1992 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
1994 SC_ScheduledEvent event = mScheduler.Remove();
1995 event.Perform();
1997 world->mSampleOffset = 0;
1998 world->mSubsampleOffset = 0.f;
2000 //int64 now = GetMicroseconds();
2002 World_Run(world);
2004 //printf("world run : %fms\n", (float) (GetMicroseconds()-now)/1000);
2007 // interleave output
2008 AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers;
2009 for (int s = 0, b = 0; b<numOutputBuses && s < numOutputStreams; s++) {
2010 AudioBuffer* buf = outOutputDataBuffers + s;
2011 int nchan = buf->mNumberChannels;
2012 if (buf->mData) {
2013 float *busdata = outputBuses + b * bufFrames;
2014 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
2015 if (nchan == 1)
2017 if (outputTouched[b] == bufCounter)
2019 #ifdef IPHONE_VEC
2020 vcopy(bufdata, busdata, bufFrames);
2021 #else
2022 for (int k=0; k<bufFrames; ++k)
2024 bufdata[k] = busdata[k];
2026 #endif
2028 } else {
2029 int minchan = sc_min(nchan, numOutputBuses - b);
2030 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
2031 if (outputTouched[b+j] == bufCounter) {
2032 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
2033 bufdata[m] = busdata[k];
2038 b += nchan;
2041 oscTime = mOSCbuftime = nextTime;
2043 } catch (std::exception& exc) {
2044 scprintf("exception in real time: %s\n", exc.what());
2045 } catch (...) {
2046 scprintf("unknown exception in real time\n");
2049 int64 systemTimeAfter = GetMicroseconds();
2050 double calcTime = (double)(systemTimeAfter - systemTimeBefore) * 1e-6;
2051 double cpuUsage = calcTime * mBuffersPerSecond * 100.;
2052 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2053 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2055 mPeakCPU = cpuUsage;
2056 mPeakCounter = mMaxPeakCounter;
2059 mAudioSync.Signal();
2066 OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow,
2067 const AudioBufferList* inInputData,
2068 const AudioTimeStamp* inInputTime,
2069 AudioBufferList* outOutputData,
2070 const AudioTimeStamp* inOutputTime,
2071 void* defptr)
2073 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
2074 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
2076 double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9;
2077 double sampleTime = inOutputTime->mSampleTime;
2078 if (def->mStartHostSecs == 0) {
2079 def->mStartHostSecs = hostSecs;
2080 def->mStartSampleTime = sampleTime;
2081 } else {
2082 double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs);
2083 double smoothSampleRate = def->mSmoothSampleRate;
2084 smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
2085 def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate);
2086 def->mSmoothSampleRate = smoothSampleRate;
2088 #if 0
2089 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs);
2090 double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime);
2091 double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs);
2092 //if (fabs(jitter) > 0.01) {
2093 scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n",
2094 avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement);
2096 #endif
2098 def->mPrevHostSecs = hostSecs;
2099 def->mPrevSampleTime = sampleTime;
2101 if (!def->UseSeparateIO())
2103 def->Run(inInputData, outOutputData, oscTime);
2104 return kAudioHardwareNoError;
2108 def->Run(lastInputData, outOutputData, oscTime);
2109 lastInputData = 0;
2111 return kAudioHardwareNoError;
2116 void AudioSessionInterruptionCbk(void *inClientData, UInt32 inInterruptionState)
2121 bool SC_iCoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
2123 AudioSessionInitialize(0, 0, AudioSessionInterruptionCbk, 0);
2124 unsigned long category = kAudioSessionCategory_PlayAndRecord;
2125 #ifdef SC_IPHONE
2126 UInt32 micInput, micInputSize = sizeof(&micInput);
2127 AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &micInputSize, &micInput);
2128 if(!micInput) {
2129 category = kAudioSessionCategory_MediaPlayback;
2130 scprintf("SC_IPHONE: WARNING - no audio input available\n");
2132 #endif
2133 AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
2135 if (mPreferredHardwareBufferFrameSize)
2137 Float32 preferredBufferSize = (float) mPreferredHardwareBufferFrameSize/44100.f;
2138 AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
2141 AudioSessionSetActive(true);
2143 float actualBufferDuration;
2144 UInt32 size = sizeof(actualBufferDuration);
2145 AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &actualBufferDuration);
2147 *outNumSamplesPerCallback = (int) (actualBufferDuration*44100.f+0.5f);
2148 *outSampleRate = 44100;
2150 AudioComponentDescription desc;
2151 desc.componentType = kAudioUnitType_Output;
2152 desc.componentSubType = kAudioUnitSubType_RemoteIO;
2153 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
2155 NewAUGraph(&graph);
2156 AUNode node;
2157 AudioUnit unit;
2158 OSStatus ret = AUGraphAddNode(graph, &desc, &node);
2159 //printf("node : %d\n", node);
2160 AUGraphOpen(graph);
2162 ret = AUGraphNodeInfo(graph, node, &desc, &unit);
2163 //printf("%d\n", unit);
2167 AudioComponent remoteIOComp = AudioComponentFindNext(0, &desc);
2168 if (AudioComponentInstanceNew(remoteIOComp, &inputUnit)!=noErr)
2170 //printf("error instantiating RemoteIO\n");
2171 return false;
2173 //printf("instantiated : %d\n", inputUnit);
2175 int enableIO = 1;
2176 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
2177 if (ret!=noErr)
2179 //printf("can't set input : %d\n", ret);
2180 return false;
2182 enableIO = 0;
2183 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
2184 if (ret!=noErr)
2186 //printf("can't set output : %d\n", ret);
2187 return false;
2190 AudioUnitInitialize(inputUnit);
2192 unsigned long bufferSizeBytes = 1024 * sizeof(unsigned long);
2193 buflist = (AudioBufferList *) malloc(sizeof(AudioBufferList));
2194 buflist->mNumberBuffers = 1;
2195 buflist->mBuffers[0].mDataByteSize = bufferSizeBytes;
2196 buflist->mBuffers[0].mData = malloc(bufferSizeBytes);
2197 buflist->mBuffers[0].mNumberChannels = 1;
2199 floatInputList = (AudioBufferList *) malloc(sizeof(AudioBufferList));
2200 floatInputList->mNumberBuffers = 1;
2201 floatInputList->mBuffers[0].mDataByteSize = bufferSizeBytes;
2202 floatInputList->mBuffers[0].mData = malloc(bufferSizeBytes);
2203 floatInputList->mBuffers[0].mNumberChannels = 1;
2206 floatOutputList = (AudioBufferList *) malloc(sizeof(AudioBufferList)+sizeof(AudioBuffer));
2207 floatOutputList->mNumberBuffers = 2;
2208 floatOutputList->mBuffers[0].mDataByteSize = bufferSizeBytes;
2209 floatOutputList->mBuffers[0].mData = malloc(bufferSizeBytes);
2210 floatOutputList->mBuffers[0].mNumberChannels = 1;
2211 floatOutputList->mBuffers[1].mDataByteSize = bufferSizeBytes;
2212 floatOutputList->mBuffers[1].mData = malloc(bufferSizeBytes);
2213 floatOutputList->mBuffers[1].mNumberChannels = 1;
2216 AURenderCallbackStruct inputStruct;
2217 inputStruct.inputProc = InputCallback;
2218 inputStruct.inputProcRefCon = this;
2219 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &inputStruct, sizeof(inputStruct));
2221 AURenderCallbackStruct renderStruct;
2222 renderStruct.inputProc = RenderCallback;
2223 renderStruct.inputProcRefCon = this;
2224 ret = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderStruct, sizeof(renderStruct));
2226 AudioStreamBasicDescription streamFormat;
2227 streamFormat.mFormatID = kAudioFormatLinearPCM;
2228 streamFormat.mFormatFlags =
2229 kAudioFormatFlagIsSignedInteger
2230 | kAudioFormatFlagsNativeEndian
2231 | kLinearPCMFormatFlagIsNonInterleaved
2232 | (24 << kLinearPCMFormatFlagsSampleFractionShift);
2233 streamFormat.mSampleRate = 44100;
2234 streamFormat.mBitsPerChannel = 32;
2235 streamFormat.mChannelsPerFrame = 2;
2236 streamFormat.mFramesPerPacket = 1;
2237 streamFormat.mBytesPerFrame = ( streamFormat.mBitsPerChannel / 8 );
2238 streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame *
2239 streamFormat.mFramesPerPacket;
2241 ret = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(streamFormat));
2244 AudioStreamBasicDescription audioFormat;
2245 audioFormat.mSampleRate = 44100.00;
2246 audioFormat.mFormatID = kAudioFormatLinearPCM;
2247 audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
2248 audioFormat.mFramesPerPacket = 1;
2249 audioFormat.mChannelsPerFrame = 1;
2250 audioFormat.mBitsPerChannel = 16;
2251 audioFormat.mBytesPerPacket = 2;
2252 audioFormat.mBytesPerFrame = 2;
2253 ret = AudioUnitSetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &audioFormat, sizeof(audioFormat));
2257 AudioStreamBasicDescription d;
2258 size = sizeof(d);
2259 ret = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &d, &size);
2261 AudioStreamBasicDescription inputFormat;
2262 AudioStreamBasicDescription outputFormat;
2263 AudioStreamBasicDescription f32Format;
2265 size = sizeof(AudioStreamBasicDescription);
2266 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &inputFormat, &size);
2267 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &inputFormat, &size);
2268 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outputFormat, &size);
2269 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outputFormat, &size);
2271 outputFormat.mChannelsPerFrame = 1;
2273 f32Format.mSampleRate = inputFormat.mSampleRate;
2274 f32Format.mFormatID = inputFormat.mFormatID;
2275 f32Format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
2276 f32Format.mBytesPerPacket = 4;
2277 f32Format.mFramesPerPacket = 1;
2278 f32Format.mBytesPerFrame = 4;
2279 f32Format.mChannelsPerFrame = 1;
2280 f32Format.mBitsPerChannel = 32;
2281 f32Format.mReserved = 0;
2283 ret = AudioConverterNew(&inputFormat, &f32Format, &converter_in_to_F32);
2284 ret = AudioConverterNew(&f32Format, &outputFormat, &converter_F32_to_out);
2285 ret = AudioConverterNew(&inputFormat, &outputFormat, &converter_in_to_out);
2287 AUGraphInitialize(graph);
2289 if(mWorld->mVerbosity >= 0){
2290 scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld);
2292 return true;
2295 bool SC_iCoreAudioDriver::DriverStart()
2297 if(mWorld->mVerbosity >= 0){
2298 scprintf("->SC_CoreAudioDriver::DriverStart\n");
2303 OSStatus ret = AUGraphStart(graph);
2304 AudioOutputUnitStart(inputUnit);
2305 } catch (...) {
2306 scprintf("exception in SC_CoreAudioDriver::DriverStart\n");
2308 if(mWorld->mVerbosity >= 0){
2309 scprintf("<-SC_CoreAudioDriver::DriverStart\n");
2311 return true;
2314 bool SC_iCoreAudioDriver::DriverStop()
2316 if(mWorld->mVerbosity >= 0){
2317 scprintf("->SC_CoreAudioDriver::DriverStop\n");
2320 AUGraphStop(graph);
2321 AudioOutputUnitStop(inputUnit);
2323 if(mWorld->mVerbosity >= 0){
2324 scprintf("<-SC_CoreAudioDriver::DriverStop\n");
2326 return true;
2329 #endif // SC_AUDIO_API_COREAUDIOIPHONE
2334 // =====================================================================
2335 // Audio driver (PortAudio)
2337 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
2339 // =====================================================================
2340 // SC_PortAudioDriver (PortAudio)
2342 #define PRINT_PORTAUDIO_ERROR( function, errorcode )\
2343 scprintf( "SC_PortAudioDriver: PortAudio failed at %s with error: '%s'\n",\
2344 #function, Pa_GetErrorText( errorcode ) )
2346 SC_PortAudioDriver::SC_PortAudioDriver(struct World *inWorld)
2347 : SC_AudioDriver(inWorld)
2348 , mStream(0)
2350 PaError paerror = Pa_Initialize();
2351 if( paerror != paNoError )
2352 PRINT_PORTAUDIO_ERROR( Pa_Initialize, paerror );
2355 SC_PortAudioDriver::~SC_PortAudioDriver()
2357 if( mStream ){
2358 PaError paerror = Pa_CloseStream( mStream );
2359 if( paerror != paNoError )
2360 PRINT_PORTAUDIO_ERROR( Pa_CloseStream, paerror );
2362 Pa_Terminate();
2365 static int SC_PortAudioStreamCallback( const void *input, void *output,
2366 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
2367 PaStreamCallbackFlags statusFlags, void *userData )
2369 SC_PortAudioDriver *driver = (SC_PortAudioDriver*)userData;
2371 return driver->PortAudioCallback( input, output, frameCount, timeInfo, statusFlags );
2374 int SC_PortAudioDriver::PortAudioCallback( const void *input, void *output,
2375 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
2376 PaStreamCallbackFlags statusFlags )
2378 World *world = mWorld;
2379 (void) frameCount, timeInfo, statusFlags; // suppress unused parameter warnings
2381 try {
2382 // synchronise against the output buffer - timeInfo->currentTime is 0.0 bug in PA?
2383 if (mPaStreamStartupTime==0 && mPaStreamStartupTimeOSC==0) {
2384 mPaStreamStartupTimeOSC = GetCurrentOSCTime();
2385 mPaStreamStartupTime = timeInfo->outputBufferDacTime;
2387 mOSCbuftime = PaStreamTimeToOSC(timeInfo->outputBufferDacTime - mPaStreamStartupTime) + mPaStreamStartupTimeOSC;
2389 mFromEngine.Free();
2390 mToEngine.Perform();
2391 mOscPacketsToEngine.Perform();
2393 int numInputs = mInputChannelCount;
2394 int numOutputs = mOutputChannelCount;
2395 const float **inBuffers = (const float**)input;
2396 float **outBuffers = (float**)output;
2398 int numSamples = NumSamplesPerCallback();
2399 int bufFrames = mWorld->mBufLength;
2400 int numBufs = numSamples / bufFrames;
2402 float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
2403 float *outBuses = mWorld->mAudioBus;
2404 int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
2405 int32 *outTouched = mWorld->mAudioBusTouched;
2407 int minInputs = std::min<size_t>(numInputs, mWorld->mNumInputs);
2408 int minOutputs = std::min<size_t>(numOutputs, mWorld->mNumOutputs);
2410 int bufFramePos = 0;
2412 int64 oscTime = mOSCbuftime;
2413 int64 oscInc = mOSCincrement;
2414 double oscToSamples = mOSCtoSamples;
2416 // main loop
2417 for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames)
2419 int32 bufCounter = mWorld->mBufCounter;
2420 int32 *tch;
2422 // copy+touch inputs
2423 tch = inTouched;
2424 for (int k = 0; k < minInputs; ++k)
2426 const float *src = inBuffers[k] + bufFramePos;
2427 float *dst = inBuses + k * bufFrames;
2428 for (int n = 0; n < bufFrames; ++n) *dst++ = *src++;
2429 *tch++ = bufCounter;
2432 // run engine
2433 int64 schedTime;
2434 int64 nextTime = oscTime + oscInc;
2435 // DEBUG
2437 if (mScheduler.Ready(nextTime)) {
2438 double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs;
2439 scprintf("rdy %.6f %.6f %.6f %.6f \n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff, (nextTime-gStartupOSCTime)*kOSCtoSecs);
2442 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
2443 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
2444 float diffTimeFloor = floor(diffTime);
2445 world->mSampleOffset = (int)diffTimeFloor;
2446 world->mSubsampleOffset = diffTime - diffTimeFloor;
2448 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
2449 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
2451 SC_ScheduledEvent event = mScheduler.Remove();
2452 event.Perform();
2454 world->mSampleOffset = 0;
2455 world->mSubsampleOffset = 0.f;
2457 World_Run(world);
2459 // copy touched outputs
2460 tch = outTouched;
2461 for (int k = 0; k < minOutputs; ++k) {
2462 float *dst = outBuffers[k] + bufFramePos;
2463 if (*tch++ == bufCounter) {
2464 float *src = outBuses + k * bufFrames;
2465 for (int n = 0; n < bufFrames; ++n) *dst++ = *src++;
2466 } else {
2467 for (int n = 0; n < bufFrames; ++n) *dst++ = 0.0f;
2471 // update buffer time
2472 oscTime = mOSCbuftime = nextTime;
2474 } catch (std::exception& exc) {
2475 scprintf("SC_PortAudioDriver: exception in real time: %s\n", exc.what());
2476 } catch (...) {
2477 scprintf("SC_PortAudioDriver: unknown exception in real time\n");
2480 double cpuUsage = (double)Pa_GetStreamCpuLoad(mStream);
2481 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2482 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2484 mPeakCPU = cpuUsage;
2485 mPeakCounter = mMaxPeakCounter;
2488 mAudioSync.Signal();
2490 return paContinue;
2493 void SC_PortAudioDriver::GetPaDeviceFromName(const char* device, int* mInOut) {
2495 const PaDeviceInfo *pdi;
2496 const PaHostApiInfo *apiInfo;
2497 char devString[256];
2498 PaDeviceIndex numDevices = Pa_GetDeviceCount();
2499 mInOut[0] = paNoDevice;
2500 mInOut[1] = paNoDevice;
2502 // This tries to find one or two devices that match the given name (substring)
2503 // might cause problems for some names...
2504 for( int i=0; i<numDevices; i++ ) {
2505 pdi = Pa_GetDeviceInfo( i );
2506 apiInfo = Pa_GetHostApiInfo(pdi->hostApi);
2507 strcpy(devString, apiInfo->name);
2508 strcat(devString, " : ");
2509 strcat(devString, pdi->name);
2510 if (strstr(devString, device)) {
2511 if (pdi->maxInputChannels > 0) mInOut[0] = i;
2512 if (pdi->maxOutputChannels > 0) mInOut[1] = i;
2517 // ====================================================================
2520 bool SC_PortAudioDriver::DriverSetup(int* outNumSamples, double* outSampleRate)
2522 int mDeviceInOut[2];
2523 PaError paerror;
2524 const PaDeviceInfo *pdi;
2525 const PaHostApiInfo *apiInfo;
2526 const PaStreamInfo *psi;
2527 PaTime suggestedLatencyIn, suggestedLatencyOut;
2528 PaDeviceIndex numDevices = Pa_GetDeviceCount();
2530 // print out all options:
2531 fprintf(stdout, "\nDevice options:\n");
2532 for( int i=0; i<numDevices; i++ ) {
2533 pdi = Pa_GetDeviceInfo( i );
2534 apiInfo = Pa_GetHostApiInfo(pdi->hostApi);
2535 fprintf(stdout, " - %s : %s (device #%d with %d ins %d outs)\n",apiInfo->name,pdi->name, i, pdi->maxInputChannels, pdi->maxOutputChannels);
2538 mDeviceInOut[0] = paNoDevice;
2539 mDeviceInOut[1] = paNoDevice;
2540 if (mWorld->hw->mInDeviceName)
2541 GetPaDeviceFromName(mWorld->hw->mInDeviceName, mDeviceInOut);
2542 if (mDeviceInOut[0] == paNoDevice) mDeviceInOut[0] = Pa_GetDefaultInputDevice();
2543 if (mDeviceInOut[1] == paNoDevice) mDeviceInOut[1] = Pa_GetDefaultOutputDevice();
2545 *outNumSamples = mWorld->mBufLength;
2546 if (mPreferredSampleRate)
2547 *outSampleRate = mPreferredSampleRate;
2548 else
2549 *outSampleRate = 44100.;
2552 if (mDeviceInOut[0]!=paNoDevice && mDeviceInOut[1]!=paNoDevice) {
2554 if (mPreferredHardwareBufferFrameSize)
2555 // controls the suggested latency by hardwareBufferSize switch -Z
2556 suggestedLatencyIn = suggestedLatencyOut = mPreferredHardwareBufferFrameSize / (*outSampleRate);
2557 else {
2558 suggestedLatencyIn = Pa_GetDeviceInfo( mDeviceInOut[0] )->defaultLowInputLatency;
2559 suggestedLatencyOut = Pa_GetDeviceInfo( mDeviceInOut[1] )->defaultLowOutputLatency;
2562 PaSampleFormat fmt = paFloat32 | paNonInterleaved;
2563 mInputChannelCount = Pa_GetDeviceInfo( mDeviceInOut[0] )->maxInputChannels;
2564 mOutputChannelCount = Pa_GetDeviceInfo( mDeviceInOut[1] )->maxOutputChannels;
2565 fprintf(stdout, "\nBooting with:\n In: %s : %s \n",
2566 Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[0] )->hostApi)->name,
2567 Pa_GetDeviceInfo( mDeviceInOut[0] )->name);
2568 fprintf(stdout, " Out: %s : %s \n",
2569 Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[1] )->hostApi)->name,
2570 Pa_GetDeviceInfo( mDeviceInOut[1] )->name);
2572 PaStreamParameters inStreamParams;
2573 inStreamParams.device = mDeviceInOut[0];
2574 inStreamParams.channelCount = mInputChannelCount;
2575 inStreamParams.sampleFormat = fmt;
2576 inStreamParams.suggestedLatency = suggestedLatencyIn;
2577 inStreamParams.hostApiSpecificStreamInfo = NULL;
2579 PaStreamParameters outStreamParams;
2580 outStreamParams.device = mDeviceInOut[1];
2581 outStreamParams.channelCount = mOutputChannelCount;
2582 outStreamParams.sampleFormat = fmt;
2583 outStreamParams.suggestedLatency = suggestedLatencyOut;
2584 outStreamParams.hostApiSpecificStreamInfo = NULL;
2586 paerror = Pa_OpenStream(&mStream, &inStreamParams, &outStreamParams, *outSampleRate, *outNumSamples, paNoFlag, SC_PortAudioStreamCallback, this );
2587 if( paerror != paNoError )
2588 PRINT_PORTAUDIO_ERROR( Pa_OpenStream, paerror );
2589 else {
2590 psi = Pa_GetStreamInfo(mStream);
2591 if (!psi)
2592 fprintf(stdout," Could not obtain further info from portaudio stream\n");
2593 else {
2594 fprintf(stdout," Sample rate: %.3f\n", psi->sampleRate);
2595 fprintf(stdout," Latency (in/out): %.3f / %.3f sec\n", psi->inputLatency, psi->outputLatency);
2598 return paerror == paNoError;
2601 // should not be necessary, but a last try with OpenDefaultStream...
2602 paerror = Pa_OpenDefaultStream( &mStream, 2, 2,
2603 paFloat32 | paNonInterleaved, *outSampleRate, *outNumSamples, SC_PortAudioStreamCallback, this );
2604 if( paerror != paNoError )
2605 PRINT_PORTAUDIO_ERROR( Pa_OpenDefaultStream, paerror );
2606 return paerror == paNoError;
2609 bool SC_PortAudioDriver::DriverStart()
2611 if (!mStream)
2612 return false;
2614 PaError paerror = Pa_StartStream( mStream );
2615 if( paerror != paNoError )
2616 PRINT_PORTAUDIO_ERROR( Pa_StartStream, paerror );
2618 // sync times
2619 mPaStreamStartupTimeOSC = 0;
2620 mPaStreamStartupTime = 0;
2621 // it would be better to do the sync here, but the timeInfo in the callback is incomplete
2622 //mPaStreamStartupTimeOSC = GetCurrentOSCTime();
2623 //mPaStreamStartupTime = Pa_GetStreamTime(mStream);
2625 return paerror == paNoError;
2628 bool SC_PortAudioDriver::DriverStop()
2630 if (!mStream)
2631 return false;
2633 PaError paerror = Pa_StopStream(mStream);
2634 if( paerror != paNoError )
2635 PRINT_PORTAUDIO_ERROR( Pa_StopStream, paerror );
2637 return paerror == paNoError;
2640 #endif // SC_AUDIO_API_PORTAUDIO