Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / server / scsynth / SC_CoreAudio.cpp
blob8b8358927283d165956381bc5bb5cc7da5c9d348
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_WorldOptions.h"
28 #include "SC_Endian.h"
29 #include "SC_Lib_Cintf.h"
30 #include <stdlib.h>
31 #include <pthread.h>
32 #include <algorithm>
34 #ifdef _WIN32
36 #else
37 #include <sys/time.h>
38 #endif
40 #ifdef SC_IPHONE
41 #include "SC_VFP11.h"
42 #endif
45 #ifdef _WIN32
46 #include "SC_Win32Utils.h"
47 #endif
49 int64 gStartupOSCTime = -1;
51 void sc_SetDenormalFlags();
53 void set_real_time_priority(pthread_t thread);
55 double gSampleRate, gSampleDur;
57 // =====================================================================
58 // Timing (CoreAudio)
60 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
62 int64 gOSCoffset = 0;
64 int32 server_timeseed()
66 static int32 count = 0;
67 int64 time = AudioGetCurrentHostTime();
68 return (int32)(time >> 32) ^ (int32)time ^ count--;
71 inline int64 CoreAudioHostTimeToOSC(int64 hostTime)
73 return (int64)((double)AudioConvertHostTimeToNanos(hostTime) * kNanosToOSCunits) + gOSCoffset;
76 int64 oscTimeNow()
78 return CoreAudioHostTimeToOSC(AudioGetCurrentHostTime());
81 static void syncOSCOffsetWithTimeOfDay()
83 // generate a value gOSCoffset such that
84 // (gOSCOffset + systemTimeInOSCunits)
85 // is equal to gettimeofday time in OSCunits.
86 // Then if this machine is synced via NTP, we are synced with the world.
87 // more accurate way to do this??
89 struct timeval tv;
91 int64 systemTimeBefore, systemTimeAfter, diff;
92 int64 minDiff = 0x7fffFFFFffffFFFFLL;
94 // take best of several tries
95 const int numberOfTries = 5;
96 int64 newOffset = gOSCoffset;
97 for (int i=0; i<numberOfTries; ++i) {
98 systemTimeBefore = AudioGetCurrentHostTime();
99 gettimeofday(&tv, 0);
100 systemTimeAfter = AudioGetCurrentHostTime();
102 diff = systemTimeAfter - systemTimeBefore;
103 if (diff < minDiff) {
104 minDiff = diff;
105 // assume that gettimeofday happens halfway between AudioGetCurrentHostTime calls
106 int64 systemTimeBetween = systemTimeBefore + diff/2;
107 int64 systemTimeInOSCunits = (int64)((double)AudioConvertHostTimeToNanos(systemTimeBetween) * kNanosToOSCunits);
108 int64 timeOfDayInOSCunits = ((int64)(tv.tv_sec + kSECONDS_FROM_1900_to_1970) << 32)
109 + (int64)(tv.tv_usec * kMicrosToOSCunits);
110 newOffset = timeOfDayInOSCunits - systemTimeInOSCunits;
114 gOSCoffset = newOffset;
115 //scprintf("gOSCoffset %016llX\n", gOSCoffset);
118 void* resyncThreadFunc(void* arg);
119 void* resyncThreadFunc(void* /*arg*/)
121 while (true) {
122 sleep(20);
123 syncOSCOffsetWithTimeOfDay();
125 return 0;
128 void initializeScheduler()
130 syncOSCOffsetWithTimeOfDay();
132 pthread_t resyncThread;
133 pthread_create (&resyncThread, NULL, resyncThreadFunc, (void*)0);
134 set_real_time_priority(resyncThread);
136 #endif // SC_AUDIO_API_COREAUDIO
139 // =====================================================================
140 // Timing (CoreAudioIPHONE)
142 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
144 int64 gOSCoffset = 0;
146 static inline int64 GetMicroseconds()
148 struct timeval tv;
149 gettimeofday(&tv, 0);
150 return (int64) tv.tv_sec * 1000000 + tv.tv_usec;
153 static inline int64 GetCurrentOSCTime()
155 struct timeval tv;
156 uint64 s, f;
157 gettimeofday(&tv, 0);
158 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
159 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
161 return (s << 32) + f;
164 int32 server_timeseed()
166 int64 time = GetCurrentOSCTime();
167 return Hash((int32)(time >> 32) + Hash((int32)time));
170 int64 oscTimeNow()
172 return GetCurrentOSCTime();
175 void initializeScheduler()
177 gOSCoffset = GetCurrentOSCTime();
179 #endif // SC_AUDIO_API_COREAUDIO
184 // =====================================================================
185 // Timing (PortAudio)
187 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
189 int64 gOSCoffset = 0;
191 static inline int64 GetCurrentOSCTime()
193 struct timeval tv;
194 uint64 s, f;
195 gettimeofday(&tv, 0);
196 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
197 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
199 return (s << 32) + f;
202 int32 server_timeseed()
204 int64 time = GetCurrentOSCTime();
205 return Hash((int32)(time >> 32) + Hash((int32)time));
208 int64 oscTimeNow()
210 return GetCurrentOSCTime();
213 int64 PaStreamTimeToOSC(PaTime pa_time) {
214 uint64 s, f;
215 s = (uint64)pa_time;
216 f = (uint64)((pa_time - s) * 1000000 * kMicrosToOSCunits);
218 return (s << 32) + f;
221 void initializeScheduler()
223 gOSCoffset = GetCurrentOSCTime();
225 #endif // SC_AUDIO_API_PORTAUDIO
228 // =====================================================================
229 // Packets (Common)
231 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket);
232 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket);
233 int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply);
234 PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc);
236 void Perform_ToEngine_Msg(FifoMsg *inMsg);
237 void FreeOSCPacket(FifoMsg *inMsg);
239 struct IsBundle
241 IsBundle() { str4cpy(s, "#bundle"); }
242 bool checkIsBundle(int32 *in) { return in[0] == s[0] && in[1] == s[1]; }
243 int32 s[2];
245 IsBundle gIsBundle;
247 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket)
249 //scprintf("ProcessOSCPacket %d, '%s'\n", inPacket->mSize, inPacket->mData);
250 if (!inPacket) return false;
251 bool result;
252 inWorld->mDriverLock->Lock();
253 SC_AudioDriver *driver = AudioDriver(inWorld);
254 if (!driver) {
255 inWorld->mDriverLock->Unlock();
256 return false;
258 inPacket->mIsBundle = gIsBundle.checkIsBundle((int32*)inPacket->mData);
259 FifoMsg fifoMsg;
260 fifoMsg.Set(inWorld, Perform_ToEngine_Msg, FreeOSCPacket, (void*)inPacket);
261 result = driver->SendOscPacketMsgToEngine(fifoMsg);
262 inWorld->mDriverLock->Unlock();
263 return result;
266 int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply)
268 // scprintf("->PerformOSCMessage %d\n", inData[0]);
269 SC_LibCmd *cmdObj;
270 int cmdNameLen;
271 if (inData[0] == 0) {
272 cmdNameLen = 4;
273 uint32 index = inData[3];
274 if (index >= NUMBER_OF_COMMANDS) cmdObj = 0;
275 else cmdObj = gCmdArray[index];
276 } else {
277 cmdNameLen = OSCstrlen(inData);
278 cmdObj = gCmdLib->Get((int32*)inData);
280 if (!cmdObj) {
281 CallSendFailureCommand(inWorld, inData, "Command not found", inReply);
282 scprintf("FAILURE IN SERVER: %s Command not found\n", inData);
283 return kSCErr_NoSuchCommand;
286 int err = cmdObj->Perform(inWorld, inSize - cmdNameLen, inData + cmdNameLen, inReply);
287 //scprintf("<-PerformOSCMessage %d\n", inData[0]);
288 return err;
291 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket)
293 //scprintf("->PerformOSCBundle %d\n", inPacket->mSize);
294 char *data = inPacket->mData + 16;
295 char* dataEnd = inPacket->mData + inPacket->mSize;
297 while (data < dataEnd) {
298 int32 msgSize = ntohl(*(int32*)data);
299 data += sizeof(int32);
300 //scprintf("msgSize %d\n", msgSize);
301 PerformOSCMessage(inWorld, msgSize, data, &inPacket->mReplyAddr);
302 data += msgSize;
305 // reset so next command uses permanent error notification status
306 inWorld->mLocalErrorNotification = 0;
308 // // 0 is a temporary change, so reset the local error flag
309 // if(!inWorld->mLocalErrorNotification) {
310 // inWorld->mLocalErrorNotification = inWorld->mErrorNotification;
311 // };
313 //scprintf("<-PerformOSCBundle %d\n", inPacket->mSize);
316 PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc freeFunc)
318 SC_AudioDriver *driver = world->hw->mAudioDriver;
320 if (!packet->mIsBundle) {
321 PerformOSCMessage(world, packet->mSize, packet->mData, &packet->mReplyAddr);
322 world->mLocalErrorNotification = 0;
323 // if(!world->mLocalErrorNotification) {
324 // world->mLocalErrorNotification = world->mErrorNotification;
325 // };
326 return PacketPerformed;
327 } else {
328 // in real time engine, schedule the packet
329 int64 time = OSCtime(packet->mData + 8);
330 if (time == 0 || time == 1) {
331 PerformOSCBundle(world, packet);
332 return PacketPerformed;
333 } else {
334 if ((time < driver->mOSCbuftime) && (world->mVerbosity >= 0)) {
335 double seconds = (driver->mOSCbuftime - time)*kOSCtoSecs;
336 scprintf("late %.9f\n", seconds);
337 //FifoMsg outMsg;
339 //ReportLateness(packet->mReply, seconds)
341 // DEBUG
342 // else
343 //scprintf("scheduled in %.6f at time %.6f\n",
344 // (time-driver->mOSCbuftime)*kOSCtoSecs,
345 // (time-gStartupOSCTime)*kOSCtoSecs);
347 SC_ScheduledEvent event(world, time, packet, freeFunc);
348 driver->AddEvent(event);
349 return PacketScheduled;
354 ////////////////////////////////////////////////////////////////////////////
356 void Perform_ToEngine_Msg(FifoMsg *inMsg)
358 World *world = inMsg->mWorld;
359 OSC_Packet *packet = (OSC_Packet*)inMsg->mData;
360 if (!packet) return;
362 PacketStatus status = PerformOSCPacket(world, packet, SC_ScheduledEvent::FreeInNRT);
363 if (status == PacketScheduled) {
364 // Transfer ownership
365 inMsg->mData = 0;
366 inMsg->mFreeFunc = 0;
370 PacketStatus PerformCompletionMsg(World *inWorld, const OSC_Packet& inPacket)
372 OSC_Packet* packet = (OSC_Packet*)World_Alloc(inWorld, sizeof(OSC_Packet));
373 *packet = inPacket;
374 packet->mIsBundle = gIsBundle.checkIsBundle((int32*)packet->mData);
375 PacketStatus status = PerformOSCPacket(inWorld, packet, SC_ScheduledEvent::FreeInRT);
376 if (status == PacketPerformed) {
377 World_Free(inWorld, packet);
379 return status;
382 void FreeOSCPacket(FifoMsg *inMsg)
384 OSC_Packet *packet = (OSC_Packet*)inMsg->mData;
385 if (packet) {
386 inMsg->mData = 0;
387 #ifdef _WIN32
388 #pragma message("$$$todo fixme hack for the 'uninitialized packet->mData ptr when using MSVC 7.1 debug")
389 if (packet->mData != reinterpret_cast<char*>(0xcdcdcdcd))
390 free(packet->mData);
391 #else //#ifdef _WIN32
392 free(packet->mData);
393 #endif //#ifdef _WIN32
394 free(packet);
398 void Free_FromEngine_Msg(FifoMsg *inMsg);
399 void Free_FromEngine_Msg(FifoMsg *inMsg)
401 World_Free(inMsg->mWorld, inMsg->mData);
404 // =====================================================================
405 // Audio driver (Common)
407 SC_AudioDriver::SC_AudioDriver(struct World *inWorld)
408 : mWorld(inWorld)
409 , mSampleTime(0)
410 , mNumSamplesPerCallback(0)
415 SC_AudioDriver::~SC_AudioDriver()
417 mRunThreadFlag = false;
418 mAudioSync.Signal();
419 pthread_join(mThread, 0);
422 void* audio_driver_thread_func(void* arg);
423 void* audio_driver_thread_func(void* arg)
425 SC_AudioDriver *ca = (SC_AudioDriver*)arg;
426 void* result = ca->RunThread();
427 return result;
430 void* SC_AudioDriver::RunThread()
432 TriggersFifo *trigfifo = &mWorld->hw->mTriggers;
433 NodeReplyFifo *nodereplyfifo = &mWorld->hw->mNodeMsgs;
434 NodeEndsFifo *nodeendfifo = &mWorld->hw->mNodeEnds;
435 DeleteGraphDefsFifo *deletegraphfifo = &mWorld->hw->mDeleteGraphDefs;
437 while (mRunThreadFlag) {
438 // wait for sync
439 mAudioSync.WaitNext();
441 mWorld->mNRTLock->Lock();
443 // send /tr messages
444 trigfifo->Perform();
446 // send node reply messages
447 nodereplyfifo->Perform();
449 // send node status messages
450 nodeendfifo->Perform();
452 // free GraphDefs
453 deletegraphfifo->Perform();
455 // perform messages
456 mFromEngine.Perform();
458 mWorld->mNRTLock->Unlock();
460 return 0;
463 bool SC_AudioDriver::SendMsgFromEngine(FifoMsg& inMsg)
465 return mFromEngine.Write(inMsg);
469 bool SC_AudioDriver::SendMsgToEngine(FifoMsg& inMsg)
471 mToEngine.Free();
472 return mToEngine.Write(inMsg);
475 bool SC_AudioDriver::SendOscPacketMsgToEngine(FifoMsg& inMsg)
477 mOscPacketsToEngine.Free();
478 return mOscPacketsToEngine.Write(inMsg);
481 void SC_ScheduledEvent::FreeInRT(struct World* world, OSC_Packet* packet)
483 World_Free(world, packet->mData);
484 World_Free(world, packet);
487 void SC_ScheduledEvent::FreeInNRT(struct World* world, OSC_Packet* packet)
489 FifoMsg msg;
490 msg.Set(world, FreeOSCPacket, 0, (void*)packet);
491 world->hw->mAudioDriver->SendMsgFromEngine(msg);
494 void SC_ScheduledEvent::Perform()
496 PerformOSCBundle(mWorld, mPacket);
497 (*mPacketFreeFunc)(mWorld, mPacket);
500 bool SC_AudioDriver::Setup()
502 mRunThreadFlag = true;
503 pthread_create (&mThread, NULL, audio_driver_thread_func, (void*)this);
504 set_real_time_priority(mThread);
506 int numSamples;
507 double sampleRate;
509 if (!DriverSetup(&numSamples, &sampleRate)) return false;
511 mNumSamplesPerCallback = numSamples;
512 //scprintf("mNumSamplesPerCallback %d\n", mNumSamplesPerCallback);
513 //scprintf("mHardwareBufferSize %lu\n", mHardwareBufferSize);
515 // compute a per sample increment to the OpenSoundControl Time
516 mOSCincrementNumerator = (double)mWorld->mBufLength * pow(2.,32.);
517 mOSCincrement = (int64)(mOSCincrementNumerator / sampleRate);
518 mOSCtoSamples = sampleRate / pow(2.,32.);
520 World_SetSampleRate(mWorld, sampleRate);
521 mSampleRate = mSmoothSampleRate = sampleRate;
522 mBuffersPerSecond = sampleRate / mNumSamplesPerCallback;
523 mMaxPeakCounter = (int)mBuffersPerSecond;
525 if(mWorld->mVerbosity >= 0){
526 scprintf("SC_AudioDriver: sample rate = %f, driver's block size = %d\n", sampleRate, mNumSamplesPerCallback);
529 return true;
532 bool SC_AudioDriver::Start()
534 mAvgCPU = 0.;
535 mPeakCPU = 0.;
536 mPeakCounter = 0;
538 mStartHostSecs = 0.;
539 mPrevHostSecs = 0.;
540 mStartSampleTime = 0.;
541 mPrevSampleTime = 0.;
543 World_Start(mWorld);
545 gStartupOSCTime = oscTimeNow();
547 return DriverStart();
550 bool SC_AudioDriver::Stop()
552 if (!DriverStop()) return false;
553 return true;
557 // =====================================================================
558 // Audio driver (CoreAudio)
559 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO
561 SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld)
563 return new SC_CoreAudioDriver(inWorld);
566 #endif
568 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
570 SC_CoreAudioDriver::SC_CoreAudioDriver(struct World *inWorld)
571 : SC_AudioDriver(inWorld)
572 , mInputBufList(0)
576 SC_CoreAudioDriver::~SC_CoreAudioDriver()
578 if (mInputBufList)
580 int i;
581 for (i=0; i<mInputBufList->mNumberBuffers; i++)
583 free(mInputBufList->mBuffers[i].mData);
585 free(mInputBufList);
589 bool SC_CoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
591 OSStatus err = kAudioHardwareNoError;
592 UInt32 count;
593 mOutputDevice = kAudioDeviceUnknown;
594 mInputDevice = kAudioDeviceUnknown;
595 AudioObjectPropertyAddress propertyAddress;
597 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
598 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
599 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
601 //scprintf("SC_CoreAudioDriver::Setup world %p\n", mWorld);
603 ////////////////////////////////////////////////////////////////////////////////////////////////
605 do {
606 // err = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &count, 0);
608 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
610 err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count);
612 if (err != noErr) {
613 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
614 break;
617 AudioDeviceID *devices = (AudioDeviceID*)malloc(count);
619 // err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
621 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, devices);
623 if (err != kAudioHardwareNoError) {
624 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
625 free(devices);
626 break;
629 int numdevices = count / sizeof(AudioDeviceID);
630 if(mWorld->mVerbosity >= 0){
631 scprintf("Number of Devices: %d\n", numdevices);
633 for (int i = 0; i < numdevices; ++i) {
634 propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
636 // err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
638 err = AudioObjectGetPropertyDataSize(devices[i], &propertyAddress, 0, NULL, &count);
640 if (err != kAudioHardwareNoError) {
641 scprintf("info kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]);
642 break;
645 char *name = (char*)malloc(count);
646 // err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
648 err = AudioObjectGetPropertyData(devices[i], &propertyAddress, 0, NULL, &count, name);
650 if (err != kAudioHardwareNoError) {
651 scprintf("get kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]);
652 free(name);
653 break;
655 if(mWorld->mVerbosity >= 0){
656 scprintf(" %d : \"%s\"\n", i, name);
658 free(name);
660 free(devices);
661 if(mWorld->mVerbosity >= 0){
662 scprintf("\n");
664 } while (false);
666 if (mWorld->hw->mInDeviceName || mWorld->hw->mOutDeviceName) {
667 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
669 // err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0);
671 err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count);
673 if (err != kAudioHardwareNoError) {
674 scprintf("info kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
675 return false;
678 AudioDeviceID *devices = (AudioDeviceID*)malloc(count);
680 // err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
681 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, devices);
683 if (err != kAudioHardwareNoError) {
684 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
685 return false;
688 int numdevices = count / sizeof(AudioDeviceID);
689 for (int i = 0; i < numdevices; ++i) {
691 // err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
692 propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
693 err = AudioObjectGetPropertyDataSize(devices[i], &propertyAddress, 0, NULL, &count);
695 if (err != kAudioHardwareNoError) {
696 scprintf("info kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]);
697 break;
700 char *name = (char*)malloc(count);
702 // err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
704 err = AudioObjectGetPropertyData(devices[i], &propertyAddress, 0, NULL, &count, name);
706 if (err != kAudioHardwareNoError) {
707 scprintf("get kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]);
708 return false;
710 if (strcmp(name, mWorld->hw->mInDeviceName) == 0) {
711 mInputDevice = devices[i];
713 if (strcmp(name, mWorld->hw->mOutDeviceName) == 0) {
714 mOutputDevice = devices[i];
716 free(name);
717 if (mInputDevice!=kAudioDeviceUnknown && mOutputDevice!=kAudioDeviceUnknown) break;
719 free(devices);
720 if (mOutputDevice==kAudioDeviceUnknown || mInputDevice==kAudioDeviceUnknown) goto getDefault;
721 } else {
722 getDefault:
724 // get the default output device for the HAL
725 if (mOutputDevice==kAudioDeviceUnknown)
727 count = sizeof(mOutputDevice);
728 //get the output device:
729 // err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) & mOutputDevice);
731 propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
733 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, (void*) & mOutputDevice);
735 if (err != kAudioHardwareNoError) {
736 scprintf("get kAudioHardwarePropertyDefaultOutputDevice error %4.4s\n", (char*)&err);
737 return false;
741 //get the input device
742 if (mInputDevice==kAudioDeviceUnknown)
744 count = sizeof(mInputDevice);
745 // err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &count, (void *) & mInputDevice);
747 propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
749 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, (void*) & mInputDevice);
752 //get the input device:
753 if (err != kAudioHardwareNoError) {
754 scprintf("get kAudioHardwarePropertyDefaultInputDevice error %4.4s\n", (char*)&err);
755 return false;
760 ////////////////////////////////////////////////////////////////////////////////////////////////
762 AudioTimeStamp now;
763 now.mFlags = kAudioTimeStampHostTimeValid;
764 now.mHostTime = AudioGetCurrentHostTime();
765 if (mPreferredHardwareBufferFrameSize)
768 count = sizeof(UInt32);
769 // err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize);
771 propertyAddress.mSelector = kAudioDevicePropertyBufferFrameSize;
772 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
774 err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, count, &mPreferredHardwareBufferFrameSize);
776 if (err != kAudioHardwareNoError) {
777 scprintf("set kAudioDevicePropertyBufferFrameSize error %4.4s\n", (char*)&err);
778 //return false;
780 if (UseSeparateIO())
782 count = sizeof(UInt32);
783 //err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize);
785 propertyAddress.mSelector = kAudioDevicePropertyBufferFrameSize;
786 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
788 err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, count, &mPreferredHardwareBufferFrameSize);
790 if (err != kAudioHardwareNoError) {
791 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
792 //return false;
796 if (mPreferredSampleRate)
798 Float64 sampleRate = mPreferredSampleRate;
799 count = sizeof(Float64);
800 //err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
802 propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
803 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
805 err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, count, &sampleRate);
807 if (err != kAudioHardwareNoError) {
808 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
809 //return false;
811 if (UseSeparateIO())
813 count = sizeof(Float64);
814 //err = AudioDeviceSetProperty(mInputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
815 propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
816 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
818 err = AudioObjectSetPropertyData(mInputDevice, &propertyAddress, 0, NULL, count, &sampleRate);
819 if (err != kAudioHardwareNoError) {
820 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
821 //return false;
826 // get the buffersize for the out device
827 count = sizeof(mHardwareBufferSize);
828 // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyBufferSize, &count, &mHardwareBufferSize);
829 propertyAddress.mSelector = kAudioDevicePropertyBufferSize;
830 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
832 err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, &mHardwareBufferSize);
834 if (err != kAudioHardwareNoError) {
835 scprintf("get kAudioDevicePropertyBufferSize error %4.4s\n", (char*)&err);
836 return false;
838 //scprintf("mHardwareBufferSize = %ld\n", mHardwareBufferSize);
840 // get a description of the data format used by the output device
841 count = sizeof(AudioStreamBasicDescription);
842 // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDesc);
843 propertyAddress.mSelector = kAudioDevicePropertyStreamFormat;
844 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
846 err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, &outputStreamDesc);
848 if (err != kAudioHardwareNoError) {
849 scprintf("get kAudioDevicePropertyStreamFormat error %4.4s\n", (char*)&err);
850 return false;
853 if (mInputDevice != kAudioDeviceUnknown) {
854 // get a description of the data format used by the input device
855 count = sizeof(AudioStreamBasicDescription);
856 // err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamFormat, &count, &inputStreamDesc);
857 propertyAddress.mSelector = kAudioDevicePropertyStreamFormat;
858 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
860 err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, &inputStreamDesc);
862 if (err != kAudioHardwareNoError) {
863 scprintf("get kAudioDevicePropertyStreamFormat error on input %4.4s\n", (char*)&err);
864 return false;
867 if (inputStreamDesc.mSampleRate != outputStreamDesc.mSampleRate) {
868 scprintf("input and output sample rates do not match. %g != %g\n", inputStreamDesc.mSampleRate, outputStreamDesc.mSampleRate);
869 return false;
872 ////////////////////////////////////////////////////////////////////////////////////////////////
874 do {
876 // err = AudioDeviceGetPropertyInfo(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
877 propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
878 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
880 err = AudioObjectGetPropertyDataSize(mInputDevice, &propertyAddress, 0, NULL, &count);
882 if (err != kAudioHardwareNoError) {
883 scprintf("info kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice);
884 break;
887 char *name = (char*)malloc(count);
888 //err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name);
890 err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, name);
892 if (err != kAudioHardwareNoError) {
893 scprintf("get kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice);
894 free(name);
895 break;
898 if(mWorld->mVerbosity >= 0){
899 scprintf("\"%s\" Input Device\n", name);
901 free(name);
903 Boolean writeable;
905 // err = AudioDeviceGetPropertyInfo(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration, &count, &writeable);
906 propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
907 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
909 err = AudioObjectIsPropertySettable(mInputDevice, &propertyAddress, &writeable);
911 if (err != kAudioHardwareNoError) {
912 scprintf("info kAudioDevicePropertyStreamConfiguration settable error %4.4s\n", (char*)&err);
913 break;
916 err = AudioObjectGetPropertyDataSize(mInputDevice, &propertyAddress, 0, NULL, &count);
918 if (err != kAudioHardwareNoError) {
919 scprintf("info kAudioDevicePropertyStreamConfiguration size error %4.4s\n", (char*)&err);
920 break;
923 AudioBufferList *bufList = (AudioBufferList*)malloc(count);
924 // err = AudioDeviceGetProperty(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration, &count, bufList);
925 propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
926 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
928 err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, bufList);
930 if (err != kAudioHardwareNoError) {
931 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
932 free(bufList);
933 break;
936 if(mWorld->mVerbosity >= 0){
937 scprintf(" Streams: %d\n", bufList->mNumberBuffers);
938 for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) {
939 scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels);
943 free(bufList);
944 } while (false);
945 if(mWorld->mVerbosity >= 0){
946 scprintf("\n");
948 ////////////////////////////////////////////////////////////////////////////////////////////////
950 do {
951 // err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
952 propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
953 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
955 err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &count);
957 char *name = (char*)malloc(count);
958 // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name);
959 err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, name);
960 if (err != kAudioHardwareNoError) {
961 scprintf("get kAudioDevicePropertyDeviceName error %4.4s\n", (char*)&err);
962 free(name);
963 break;
966 if(mWorld->mVerbosity >= 0){
967 scprintf("\"%s\" Output Device\n", name);
969 free(name);
971 Boolean writeable;
972 // err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration, &count, &writeable);
974 propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
975 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
977 err = AudioObjectIsPropertySettable(mOutputDevice, &propertyAddress, &writeable);
979 if (err != kAudioHardwareNoError) {
980 scprintf("info kAudioDevicePropertyStreamConfiguration settable error %4.4s\n", (char*)&err);
981 break;
984 err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &count);
986 if (err != kAudioHardwareNoError) {
987 scprintf("info kAudioDevicePropertyStreamConfiguration size error %4.4s\n", (char*)&err);
988 break;
991 AudioBufferList *bufList = (AudioBufferList*)malloc(count);
992 // err = AudioDeviceGetProperty(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration, &count, bufList);
994 propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration ;
995 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
997 err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, bufList);
998 if (err != kAudioHardwareNoError) {
999 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
1000 free(bufList);
1001 break;
1003 if(mWorld->mVerbosity >= 0){
1004 scprintf(" Streams: %d\n", bufList->mNumberBuffers);
1005 for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) {
1006 scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels);
1009 free(bufList);
1010 } while (false);
1011 if(mWorld->mVerbosity >= 0){
1012 scprintf("\n");
1014 ////////////////////////////////////////////////////////////////////////////////////////////////
1017 if (UseSeparateIO()) {
1018 count = sizeof(UInt32);
1019 //err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertySafetyOffset, &count, &mSafetyOffset);
1020 propertyAddress.mSelector = kAudioDevicePropertySafetyOffset;
1021 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
1023 err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, &mSafetyOffset);
1025 if (err != kAudioHardwareNoError) {
1026 scprintf("get kAudioDevicePropertySafetyOffset error %4.4s\n", (char*)&err);
1027 return false;
1029 if(mWorld->mVerbosity >= 1){
1030 scprintf("mSafetyOffset %lu\n", mSafetyOffset);
1033 Boolean writeable;
1034 // err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, &writeable);
1036 propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
1037 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
1039 err = AudioObjectIsPropertySettable(mInputDevice, &propertyAddress, &writeable);
1041 if (err != kAudioHardwareNoError) {
1042 scprintf("get kAudioDevicePropertyStreamConfiguration writeable error %4.4s\n", (char*)&err);
1043 return false;
1046 err = AudioObjectGetPropertyDataSize(mInputDevice, &propertyAddress, 0, NULL, &count);
1048 if (err != kAudioHardwareNoError) {
1049 scprintf("get kAudioDevicePropertyStreamConfiguration size error %4.4s\n", (char*)&err);
1050 return false;
1053 mInputBufList = (AudioBufferList*)malloc(count);
1055 //err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, mInputBufList);
1057 err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, mInputBufList);
1059 if (err != kAudioHardwareNoError) {
1060 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
1061 return false;
1064 if(mWorld->mVerbosity >= 1){
1065 scprintf("mNumberBuffers %lu\n", mInputBufList->mNumberBuffers);
1067 for (uint32 i=0; i<mInputBufList->mNumberBuffers; ++i) {
1068 if(mWorld->mVerbosity >= 1){
1069 scprintf(" mDataByteSize %d %lu\n", i, mInputBufList->mBuffers[i].mDataByteSize);
1071 mInputBufList->mBuffers[i].mData = zalloc(1, mInputBufList->mBuffers[i].mDataByteSize);
1075 AudioTimeStamp now;
1076 now.mFlags = kAudioTimeStampHostTimeValid;
1077 now.mHostTime = AudioGetCurrentHostTime();
1080 err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyRegisterBufferList, count, mInputBufList);
1081 if (err != kAudioHardwareNoError) {
1082 scprintf("get kAudioDevicePropertyRegisterBufferList error %4.4s\n", (char*)&err);
1083 return false;
1088 *outNumSamplesPerCallback = mHardwareBufferSize / outputStreamDesc.mBytesPerFrame;
1089 *outSampleRate = outputStreamDesc.mSampleRate;
1091 if(mWorld->mVerbosity >= 1){
1092 scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld);
1097 //check if using built-in output, and thus whether there could be headphone plug/un-plug issues
1098 //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
1100 // err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
1102 propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
1103 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
1105 err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &count);
1107 if (err != kAudioHardwareNoError) {
1108 scprintf("info kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice);
1109 return false;
1112 char *outputname = (char*)malloc(count);
1113 const char *testname = "Built-in Output";
1115 // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, outputname);
1116 err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, outputname);
1118 if (err != kAudioHardwareNoError) {
1119 scprintf("get kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice);
1120 return false;
1122 builtinoutputflag_ = 0;
1124 if (strcmp(testname, outputname) == 0) {
1125 builtinoutputflag_ = 1;
1127 // else {
1129 // //check for an Aggregate Devices with a subdevice which is Built-in Output
1130 // //http://lists.apple.com/archives/coreaudio-api/2009/Oct/msg00182.html
1133 // }
1135 free(outputname);
1138 return true;
1142 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
1143 const AudioBufferList* inInputData,
1144 const AudioTimeStamp* inInputTime,
1145 AudioBufferList* outOutputData,
1146 const AudioTimeStamp* inOutputTime,
1147 void* defptr);
1148 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
1149 const AudioBufferList* inInputData,
1150 const AudioTimeStamp* inInputTime,
1151 AudioBufferList* outOutputData,
1152 const AudioTimeStamp* inOutputTime,
1153 void* defptr)
1155 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1157 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
1159 AudioTimeStamp readTime;
1160 readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback();
1161 readTime.mFlags = kAudioTimeStampSampleTimeValid;
1163 AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList());
1165 def->Run(def->GetInputBufferList(), outOutputData, oscTime);
1167 return kAudioHardwareNoError;
1172 OSStatus appIOProcSeparateIn (AudioDeviceID device, const AudioTimeStamp* inNow,
1173 const AudioBufferList* inInputData,
1174 const AudioTimeStamp* inInputTime,
1175 AudioBufferList* outOutputData,
1176 const AudioTimeStamp* inOutputTime,
1177 void* defptr)
1179 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1181 // copy input data to driver's private buffer list
1182 int i;
1183 for (i=0; i<inInputData->mNumberBuffers; i++)
1185 memcpy(def->mInputBufList->mBuffers[i].mData, inInputData->mBuffers[i].mData, inInputData->mBuffers[i].mDataByteSize);
1188 return kAudioHardwareNoError;
1191 OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow,
1192 const AudioBufferList* inInputData,
1193 const AudioTimeStamp* inInputTime,
1194 AudioBufferList* outOutputData,
1195 const AudioTimeStamp* inOutputTime,
1196 void* defptr)
1198 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1199 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
1201 double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9;
1202 double sampleTime = inOutputTime->mSampleTime;
1203 if (def->mStartHostSecs == 0) {
1204 def->mStartHostSecs = hostSecs;
1205 def->mStartSampleTime = sampleTime;
1206 } else {
1207 double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs);
1208 double smoothSampleRate = def->mSmoothSampleRate;
1209 smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
1210 def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate);
1211 def->mSmoothSampleRate = smoothSampleRate;
1213 #if 0
1214 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs);
1215 double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime);
1216 double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs);
1217 //if (fabs(jitter) > 0.01) {
1218 scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n",
1219 avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement);
1221 #endif
1223 def->mPrevHostSecs = hostSecs;
1224 def->mPrevSampleTime = sampleTime;
1226 if (!def->UseSeparateIO())
1228 def->Run(inInputData, outOutputData, oscTime);
1229 return kAudioHardwareNoError;
1233 def->Run(def->mInputBufList, outOutputData, oscTime);
1234 return kAudioHardwareNoError;
1237 void SC_CoreAudioDriver::Run(const AudioBufferList* inInputData,
1238 AudioBufferList* outOutputData, int64 oscTime)
1240 int64 systemTimeBefore = AudioGetCurrentHostTime();
1241 World *world = mWorld;
1243 try {
1244 int numSamplesPerCallback = NumSamplesPerCallback();
1245 mOSCbuftime = oscTime;
1247 #ifdef __APPLE__
1248 sc_SetDenormalFlags();
1249 #endif
1251 mFromEngine.Free();
1252 /*if (mToEngine.HasData()) {
1253 scprintf("oscTime %.9f %.9f\n", oscTime*kOSCtoSecs, CoreAudioHostTimeToOSC(AudioGetCurrentHostTime())*kOSCtoSecs);
1255 mToEngine.Perform();
1256 mOscPacketsToEngine.Perform();
1258 int bufFrames = world->mBufLength;
1259 int numBufs = numSamplesPerCallback / bufFrames;
1261 int numInputBuses = world->mNumInputs;
1262 int numOutputBuses = world->mNumOutputs;
1263 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
1264 float* outputBuses = world->mAudioBus;
1265 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
1266 int32* outputTouched = world->mAudioBusTouched;
1267 int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0;
1268 int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0;
1270 //static int go = 0;
1272 int64 oscInc = mOSCincrement;
1273 double oscToSamples = mOSCtoSamples;
1275 int bufFramePos = 0;
1277 for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) {
1278 int32 bufCounter = world->mBufCounter;
1280 // de-interleave input
1281 if (inInputData) {
1282 const AudioBuffer* inInputDataBuffers = inInputData->mBuffers;
1283 for (int s = 0, b = 0; b<numInputBuses && s < numInputStreams; s++) {
1284 const AudioBuffer* buf = inInputDataBuffers + s;
1285 int nchan = buf->mNumberChannels;
1286 if (buf->mData) {
1287 float *busdata = inputBuses + b * bufFrames;
1288 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1289 if (nchan == 1) {
1290 for (int k=0; k<bufFrames; ++k) {
1291 busdata[k] = bufdata[k];
1293 inputTouched[b] = bufCounter;
1294 } else {
1295 int minchan = sc_min(nchan, numInputBuses - b);
1296 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1297 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1298 busdata[k] = bufdata[m];
1300 inputTouched[b+j] = bufCounter;
1303 b += nchan;
1307 //count++;
1309 int64 schedTime;
1310 int64 nextTime = oscTime + oscInc;
1312 /*if (mScheduler.Ready(nextTime)) {
1313 double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs;
1314 scprintf("rdy %.9f %.9f %.9f\n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff);
1317 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
1318 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
1319 float diffTimeFloor = floor(diffTime);
1320 world->mSampleOffset = (int)diffTimeFloor;
1321 world->mSubsampleOffset = diffTime - diffTimeFloor;
1323 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
1324 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
1326 SC_ScheduledEvent event = mScheduler.Remove();
1327 event.Perform();
1329 world->mSampleOffset = 0;
1330 world->mSubsampleOffset = 0.f;
1332 World_Run(world);
1334 // interleave output
1335 AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers;
1336 for (int s = 0, b = 0; b<numOutputBuses && s < numOutputStreams; s++) {
1337 AudioBuffer* buf = outOutputDataBuffers + s;
1338 int nchan = buf->mNumberChannels;
1339 if (buf->mData) {
1340 float *busdata = outputBuses + b * bufFrames;
1341 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1342 if (nchan == 1) {
1343 if (outputTouched[b] == bufCounter) {
1344 for (int k=0; k<bufFrames; ++k) {
1345 bufdata[k] = busdata[k];
1348 } else {
1349 int minchan = sc_min(nchan, numOutputBuses - b);
1350 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1351 if (outputTouched[b+j] == bufCounter) {
1352 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1353 bufdata[m] = busdata[k];
1358 b += nchan;
1361 oscTime = mOSCbuftime = nextTime;
1363 } catch (std::exception& exc) {
1364 scprintf("exception in real time: %s\n", exc.what());
1365 } catch (...) {
1366 scprintf("unknown exception in real time\n");
1368 int64 systemTimeAfter = AudioGetCurrentHostTime();
1369 double calcTime = (double)AudioConvertHostTimeToNanos(systemTimeAfter - systemTimeBefore) * 1e-9;
1370 double cpuUsage = calcTime * mBuffersPerSecond * 100.;
1371 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
1372 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
1374 mPeakCPU = cpuUsage;
1375 mPeakCounter = mMaxPeakCounter;
1378 mAudioSync.Signal();
1384 //////////////////////////////////////////////////////////////////////////////////////////
1385 //////////////////////////////////////////////////////////////////////////////////////////
1386 //////////////////////////////////////////////////////////////////////////////////////////
1387 // These are not linked in yet, but we'll need to listen for the properties and stop/restart synthesis
1388 // if sample-rate, format, or device change.
1390 OSStatus hardwareListenerProc ( AudioHardwarePropertyID inPropertyID,
1391 void* inClientData)
1393 OSStatus err = noErr;
1394 char cStr[255];
1395 UInt32 outSize;
1396 Boolean outWritable;
1397 AudioDeviceID deviceID;
1399 AudioObjectPropertyAddress propertyAddress;
1401 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
1402 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
1403 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
1405 switch(inPropertyID)
1407 case kAudioHardwarePropertyDefaultOutputDevice:
1408 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultOutputDevice\r");
1410 //err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &outWritable);
1412 propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
1414 err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize);
1416 if (err) break;
1418 err = AudioObjectIsPropertySettable(kAudioObjectSystemObject, &propertyAddress, &outWritable);
1420 if (err) break;
1422 //err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &deviceID);
1424 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize, &deviceID);
1426 if (err) break;
1427 // err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1429 propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
1431 err = AudioObjectGetPropertyDataSize(deviceID, &propertyAddress, 0, NULL, &outSize);
1433 if (err) break;
1435 err = AudioObjectIsPropertySettable(deviceID, &propertyAddress, &outWritable);
1437 if (err) break;
1439 //err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1441 err = AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, NULL, &outSize, cStr);
1443 if (err) break;
1445 // do something
1447 break;
1449 case kAudioHardwarePropertyDefaultInputDevice:
1450 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultInputDevice\r");
1451 // err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultInputDevice, &outSize, &outWritable);
1453 propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
1455 err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize);
1457 if (err) break;
1459 err = AudioObjectIsPropertySettable(kAudioObjectSystemObject, &propertyAddress, &outWritable);
1461 if (err) break;
1463 // err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &outSize, &deviceID);
1465 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize, &deviceID);
1467 if (err) break;
1469 // err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1472 propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
1474 err = AudioObjectGetPropertyDataSize(deviceID, &propertyAddress, 0, NULL, &outSize);
1476 if (err) break;
1478 err = AudioObjectIsPropertySettable(deviceID, &propertyAddress, &outWritable);
1480 if (err) break;
1482 // err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1485 err = AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, NULL, &outSize, cStr);
1487 if (err) break;
1489 // do something
1491 break;
1493 case kAudioHardwarePropertyDefaultSystemOutputDevice:
1494 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultSystemOutputDevice\r");
1495 //err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &outWritable);
1497 propertyAddress.mSelector = kAudioHardwarePropertyDefaultSystemOutputDevice;
1499 err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize);
1501 if (err) break;
1503 err = AudioObjectIsPropertySettable(kAudioObjectSystemObject, &propertyAddress, &outWritable);
1505 if (err) break;
1507 // err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &deviceID);
1509 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize, &deviceID);
1511 if (err) break;
1513 // err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1515 propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
1517 err = AudioObjectGetPropertyDataSize(deviceID, &propertyAddress, 0, NULL, &outSize);
1519 if (err) break;
1521 err = AudioObjectIsPropertySettable(deviceID, &propertyAddress, &outWritable);
1523 if (err) break;
1525 // err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1527 err = AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, NULL, &outSize, cStr);
1529 if (err) break;
1531 // do something
1533 break;
1535 case kAudioHardwarePropertyDevices:
1537 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDevices\r");
1539 break;
1540 default:
1541 scprintf("%s\n", "***** HARDWARE NOTIFICATION - %4.4s\r", &inPropertyID);
1544 fflush(stdout);
1545 return (noErr);
1551 OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData);
1553 OSStatus AddHardwareListeners(void* inClientData);
1554 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1555 OSStatus AddHardwareListeners(void* inClientData)
1557 OSStatus err = noErr;
1559 //non deprecated but requires AudiObject, bleargh
1560 //err= AudioObjectAddPropertyListener(AudioObject, kAudioHardwarePropertyDefaultOutputDevice, hardwareListenerProc, inClientData);
1562 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultOutputDevice, hardwareListenerProc, inClientData);
1564 if (err) return err;
1566 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultInputDevice, hardwareListenerProc, inClientData);
1567 if (err) return err;
1569 //doesn't matter? Only default looked at by SC?
1570 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultSystemOutputDevice, hardwareListenerProc, inClientData);
1571 if (err) return err;
1573 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, hardwareListenerProc, inClientData);
1574 if (err) return err;
1576 return (err);
1579 bool SC_CoreAudioDriver::DriverStart()
1581 if(mWorld->mVerbosity >= 1){
1582 scprintf("->SC_CoreAudioDriver::DriverStart\n");
1584 OSStatus err = kAudioHardwareNoError;
1585 // AudioTimeStamp now;
1586 UInt32 propertySize;
1587 Boolean writable;
1588 AudioObjectPropertyAddress propertyAddress;
1590 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
1591 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
1592 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
1594 if(mWorld->mVerbosity >= 1){
1595 scprintf("start UseSeparateIO?: %d\n", UseSeparateIO());
1598 try {
1599 if (UseSeparateIO()) {
1600 // err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup Out device with an IO proc
1602 err = AudioDeviceCreateIOProcID(mOutputDevice, appIOProc, (void*) this, &mOutputID);
1603 if (err != kAudioHardwareNoError) {
1604 scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err);
1605 return false;
1607 // err = AudioDeviceAddIOProc(mInputDevice, appIOProcSeparateIn, (void *) this); // setup In device with an IO proc
1608 err = AudioDeviceCreateIOProcID(mInputDevice, appIOProcSeparateIn , (void *)this, &mInputID);
1610 if (err != kAudioHardwareNoError) {
1611 scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err);
1612 return false;
1616 if (mWorld->hw->mInputStreamsEnabled) {
1617 //err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1618 propertyAddress.mSelector = kAudioDevicePropertyIOProcStreamUsage;
1619 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
1621 err = AudioObjectGetPropertyDataSize(mInputDevice, 0, NULL, &propertyAddress, &propertySize);
1622 err = AudioObjectIsPropertySettable(mInputDevice, &propertyAddress, &writable);
1624 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1625 su->mIOProc = (void*)appIOProcSeparateIn;
1626 // err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1627 err = AudioObjectGetPropertyData(mInputDevice, 0, NULL, &propertyAddress, &propertySize, su);
1629 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled));
1630 for (int i=0; i<len; ++i) {
1631 su->mStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1';
1633 // err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1635 err = AudioObjectSetPropertyData(mInputDevice, &propertyAddress, 0, NULL, propertySize, su);
1638 if (mWorld->hw->mOutputStreamsEnabled) {
1639 //err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1641 propertyAddress.mSelector = kAudioDevicePropertyIOProcStreamUsage;
1642 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
1644 err = AudioObjectGetPropertyDataSize(mInputDevice, 0, NULL, &propertyAddress, &propertySize);
1645 err = AudioObjectIsPropertySettable(mInputDevice, &propertyAddress, &writable);
1647 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1648 su->mIOProc = (void*)appIOProc;
1649 // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1650 err = AudioObjectGetPropertyData(mOutputDevice, 0, NULL, &propertyAddress, &propertySize, su);
1652 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled));
1653 for (int i=0; i<len; ++i) {
1654 su->mStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1';
1656 // err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1658 err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, propertySize, su);
1661 err = AudioDeviceStart(mInputDevice, appIOProcSeparateIn); // start playing sound through the device
1662 if (err != kAudioHardwareNoError) {
1663 scprintf("AudioDeviceStart failed %d\n", (int)err);
1664 return false;
1667 err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device
1668 if (err != kAudioHardwareNoError) {
1669 scprintf("AudioDeviceStart failed %d\n", (int)err);
1670 err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn); // stop playing sound through the device
1671 return false;
1673 } else {
1674 // err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup our device with an IO proc
1675 err = AudioDeviceCreateIOProcID(mOutputDevice, appIOProc, (void *) this, &mOutputID);
1677 if (err != kAudioHardwareNoError) {
1678 scprintf("AudioDeviceAddIOProc failed %d\n", (int)err);
1679 return false;
1682 if (mWorld->hw->mInputStreamsEnabled) {
1683 //err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1684 propertyAddress.mSelector = kAudioDevicePropertyIOProcStreamUsage;
1685 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
1687 err = AudioObjectGetPropertyDataSize(mOutputDevice, 0, NULL, &propertyAddress, &propertySize);
1688 err = AudioObjectIsPropertySettable(mOutputDevice, &propertyAddress, &writable);
1690 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1691 su->mIOProc = (void*)appIOProc;
1692 //err = AudioDeviceGetProperty(mOutputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1693 err = AudioObjectGetPropertyData(mOutputDevice, 0, NULL, &propertyAddress, &propertySize, su);
1695 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled));
1696 for (int i=0; i<len; ++i) {
1697 su->mStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1';
1699 //err = AudioDeviceSetProperty(mOutputDevice, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1701 err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, propertySize, su);
1704 if (mWorld->hw->mOutputStreamsEnabled) {
1705 // err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1706 propertyAddress.mSelector = kAudioDevicePropertyIOProcStreamUsage;
1707 propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
1709 err = AudioObjectGetPropertyDataSize(mOutputDevice, 0, NULL, &propertyAddress, &propertySize);
1710 err = AudioObjectIsPropertySettable(mOutputDevice, &propertyAddress, &writable);
1712 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1713 su->mIOProc = (void*)appIOProc;
1714 //err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1715 err = AudioObjectGetPropertyData(mOutputDevice, 0, NULL, &propertyAddress, &propertySize, su);
1717 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled));
1718 for (int i=0; i<len; ++i) {
1719 su->mStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1';
1721 //err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1723 err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, propertySize, su);
1726 err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device
1727 if (err != kAudioHardwareNoError) {
1728 scprintf("AudioDeviceStart failed %d\n", (int)err);
1729 return false;
1732 } catch (...) {
1733 scprintf("exception in SC_CoreAudioDriver::DriverStart\n");
1735 if(mWorld->mVerbosity >= 1){
1736 scprintf("<-SC_CoreAudioDriver::DriverStart\n");
1740 //http://lists.apple.com/archives/coreaudio-api/2010/Aug/msg00114.html
1741 CFRunLoopRef theRunLoop = NULL;
1742 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1743 AudioObjectSetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
1745 //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
1746 //by switching to system default?
1747 //AddHardwareListeners(NULL);
1748 //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
1749 AddDeviceListeners(mOutputDevice, this);
1751 return true;
1755 bool SC_CoreAudioDriver::StopStart() {
1757 bool test = DriverStop();
1759 bool test2 = DriverStart();
1760 return test && test2;
1764 bool SC_CoreAudioDriver::DriverStop()
1766 if(mWorld->mVerbosity >= 1){
1767 scprintf("->SC_CoreAudioDriver::DriverStop\n");
1769 OSStatus err = kAudioHardwareNoError;
1771 if (UseSeparateIO()) {
1772 err = AudioDeviceStop(mOutputDevice, appIOProc);
1773 if (err != kAudioHardwareNoError) {
1774 scprintf("AudioDeviceStop A failed %p\n", err);
1775 return false;
1777 // err = AudioDeviceRemoveIOProc(mOutputDevice, appIOProc);
1778 err = AudioDeviceDestroyIOProcID(mOutputDevice, mOutputID);
1779 if (err != kAudioHardwareNoError) {
1780 scprintf("AudioDeviceRemoveIOProc A failed %p\n", err);
1781 return false;
1784 err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn);
1785 if (err != kAudioHardwareNoError) {
1786 scprintf("AudioDeviceStop A failed %p\n", err);
1787 return false;
1790 // err = AudioDeviceRemoveIOProc(mInputDevice, appIOProcSeparateIn);
1791 err = AudioDeviceDestroyIOProcID(mOutputDevice, mInputID);
1793 if (err != kAudioHardwareNoError) {
1794 scprintf("AudioDeviceRemoveIOProc A failed %p\n", err);
1795 return false;
1797 } else {
1798 err = AudioDeviceStop(mOutputDevice, appIOProc);
1799 if (err != kAudioHardwareNoError) {
1800 scprintf("AudioDeviceStop B failed %p\n", err);
1801 return false;
1804 // err = AudioDeviceRemoveIOProc(mOutputDevice, appIOProc);
1805 err = AudioDeviceDestroyIOProcID(mOutputDevice, mOutputID);
1807 if (err != kAudioHardwareNoError) {
1808 scprintf("AudioDeviceRemoveIOProc B failed %p\n", err);
1809 return false;
1812 if(mWorld->mVerbosity >= 1){
1813 scprintf("<-SC_CoreAudioDriver::DriverStop\n");
1815 return true;
1819 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1820 // Listen for Device Properties and update interface and globals
1821 OSStatus deviceListenerProc ( AudioDeviceID inDevice,
1822 UInt32 inLine,
1823 Boolean isInput,
1824 AudioDevicePropertyID inPropertyID,
1825 void* inClientData)
1827 OSStatus err = noErr;
1829 SC_CoreAudioDriver* coredriver = (SC_CoreAudioDriver*) inClientData;
1831 switch(inPropertyID)
1833 // case kAudioDevicePropertyBufferSize:
1834 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferSize\r");
1835 // outSize = sizeof(UInt32);
1836 // err = AudioDeviceGetProperty(inDevice, 0, 0, kAudioDevicePropertyBufferSize, &outSize, &theUIntData);
1838 // break;
1840 // case kAudioDevicePropertyBufferFrameSize:
1841 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferFrameSize\r");
1842 // outSize = sizeof(UInt32);
1843 // err = AudioDeviceGetProperty(inDevice, 0, 0, kAudioDevicePropertyBufferFrameSize, &outSize, &theUIntData);
1845 // break;
1847 // case kAudioDevicePropertyBufferSizeRange:
1848 // {
1849 // AudioValueRange range;
1851 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferSizeRange\r");
1852 // outSize = sizeof(AudioValueRange);
1853 // err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyBufferSizeRange, &outSize, &range);
1854 // }
1855 // break;
1857 // case kAudioDevicePropertyStreamFormat:
1858 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyStreamFormat\r");
1859 // break;
1861 // case kAudioDevicePropertyDeviceIsRunning:
1862 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDeviceIsRunning\r");
1863 // outSize = sizeof(UInt32);
1864 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyDeviceIsRunning, &outSize, &theUIntData);
1866 // //when change device get up to four messages:
1867 // //isInput ==NO or YES theUIntData= 0 or 1 from old and possibly new device (ieheadphone swap)
1871 // break;
1873 // case kAudioDevicePropertyVolumeScalar:
1874 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyVolumeScalar\r");
1875 // outSize = sizeof(Float32);
1876 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyVolumeScalar, &outSize, &vol);
1877 // break;
1879 // case kAudioDevicePropertyMute:
1880 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyMute\r");
1881 // outSize = sizeof(UInt32);
1882 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyMute, &outSize, &mute);
1883 // break;
1885 // case kAudioDevicePropertyPlayThru:
1886 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyPlayThru\r");
1887 // outSize = sizeof(UInt32);
1888 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyPlayThru, &outSize, &playThru);
1890 // break;
1892 // case kAudioDevicePropertyDeviceIsAlive:
1893 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDeviceIsAlive\r");
1894 // outSize = sizeof(UInt32);
1895 // err = AudioDeviceGetProperty(inDevice, 0, false, kAudioDevicePropertyDeviceIsAlive, &outSize, &tLong);
1897 // break;
1899 case kAudioDevicePropertyDataSource:
1900 //Don't print anything
1901 //scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDataSource\r");
1902 // get the source
1903 // match the source to one of the available sources and return the index of that source
1904 //SetControlValue(control, (chan->vol) * 100);
1906 //will get this message anyway even if don't have built-in output seleected.
1907 //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
1908 //swapping to new driver
1909 if (coredriver->builtinoutputflag_==1)
1910 coredriver->StopStart();
1913 break;
1915 //default:
1916 // scprintf("%s\n", "***** DEVICE NOTIFICATION - %4.4s\r", &inPropertyID);
1919 //fflush(stdout);
1920 return (err);
1923 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1924 OSStatus streamListenerProc ( AudioStreamID inStream,
1925 UInt32 inChannel,
1926 AudioDevicePropertyID inPropertyID,
1927 void* inClientData)
1929 OSStatus err = noErr;
1931 switch(inPropertyID)
1933 case kAudioStreamPropertyPhysicalFormat:
1934 scprintf("%s\n", "***** STREAM NOTIFICATION - kAudioStreamPropertyPhysicalFormat\r");
1935 break;
1937 case kAudioDevicePropertyStreamFormat:
1938 scprintf("%s\n", "***** STREAM NOTIFICATION - kAudioDevicePropertyStreamFormat\r");
1939 break;
1941 default:
1942 break;
1945 fflush(stdout);
1947 return (err);
1950 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1951 OSStatus AddStreamListeners (AudioDeviceID inDevice, AudioDevicePropertyID inPropertyID, Boolean isInput, void *inClientData);
1953 OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData)
1955 OSStatus err = noErr;
1957 //ONLY REACTING TO HEADPHONE SWAPS FOR NOW
1961 // // kAudioDevicePropertyBufferSize
1962 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferSize, deviceListenerProc, inClientData);
1963 // if (err) return err;
1965 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferSize, deviceListenerProc, inClientData);
1966 // if (err) return err;
1969 // // kAudioDevicePropertyBufferFrameSize
1970 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferFrameSize, deviceListenerProc, inClientData);
1971 // if (err) return err;
1973 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferFrameSize, deviceListenerProc, inClientData);
1974 // if (err) return err;
1976 // // kAudioDevicePropertyDeviceIsRunning
1977 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDeviceIsRunning, deviceListenerProc, inClientData);
1978 // if (err) return err;
1980 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDeviceIsRunning, deviceListenerProc, inClientData);
1981 // if (err) return err;
1983 ///*
1984 // for (i = 0; i <= deviceInfo->totalOutputChannels; i++)
1985 // {
1986 // // kAudioDevicePropertyVolumeScalar output
1987 // err = AudioDeviceAddPropertyListener(inDevice, i, false, kAudioDevicePropertyVolumeScalar, deviceListenerProc, inClientData);
1988 // if (err) return err;
1990 // // kAudioDevicePropertyVolumeMute output
1991 // err = AudioDeviceAddPropertyListener(inDevice, i, false, kAudioDevicePropertyMute, deviceListenerProc, inClientData);
1992 // if (err) return err;
1993 // }
1995 // for (i = 0; i <= deviceInfo->totalInputChannels; i++)
1996 // {
1997 // // kAudioDevicePropertyVolumeScalar input
1998 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyVolumeScalar, deviceListenerProc, inClientData);
1999 // if (err) return err;
2001 // // kAudioDevicePropertyVolumeMute input
2002 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyMute, deviceListenerProc, inClientData);
2003 // if (err) return err;
2005 // // kAudioDevicePropertyPlayThru input
2006 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyPlayThru, deviceListenerProc, inClientData);
2007 // if (err) return err;
2008 // }
2009 //*/
2011 // // kAudioDevicePropertyDeviceIsAlive
2012 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDeviceIsAlive, deviceListenerProc, inClientData);
2013 // if (err) return err;
2015 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDeviceIsAlive, deviceListenerProc, inClientData);
2016 // if (err) return err;
2019 // // kAudioDevicePropertyStreamFormat
2020 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyStreamFormat, deviceListenerProc, inClientData);
2021 // if (err) return err;
2023 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyStreamFormat, deviceListenerProc, inClientData);
2024 // if (err) return err;
2026 // // kAudioDevicePropertyBufferSizeRange
2027 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferSizeRange, deviceListenerProc, inClientData);
2028 // if (err) return err;
2030 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferSizeRange, deviceListenerProc, inClientData);
2031 // if (err) return err;
2033 //kAudioDevicePropertyDataSource
2034 err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDataSource, deviceListenerProc, inClientData);
2035 if (err) return err;
2037 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDataSource, deviceListenerProc, inClientData);
2038 // if (err) return err;
2041 //AddStreamListeners (inDevice, kAudioStreamPropertyPhysicalFormat, false, inClientData);
2043 //AddStreamListeners (inDevice, kAudioStreamPropertyPhysicalFormat, true, inClientData);
2045 return (err);
2050 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2051 OSStatus AddStreamListeners (AudioDeviceID inDevice, AudioDevicePropertyID inPropertyID, Boolean isInput, void *inClientData)
2053 OSStatus err = noErr;
2054 UInt32 count;
2055 UInt32 outSize;
2056 Boolean outWritable;
2057 AudioStreamID *streamList = nil;
2059 err = AudioDeviceGetPropertyInfo(inDevice, 0, isInput, kAudioDevicePropertyStreams, &outSize, &outWritable);
2060 if (err == noErr)
2062 streamList = (AudioStreamID*)malloc(outSize);
2063 err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyStreams, &outSize, streamList);
2064 if (err == noErr)
2066 for (count = 0; count < (outSize / sizeof(AudioStreamID)); count++)
2068 err = AudioStreamAddPropertyListener(streamList[count], 0, inPropertyID, streamListenerProc, inClientData);
2069 if (err) return err;
2072 if (streamList != nil)
2074 free(streamList);
2075 streamList = nil;
2080 return (noErr);
2082 #endif // SC_AUDIO_API_COREAUDIO
2087 // =====================================================================
2088 // Audio driver (CoreAudioIPHONE)
2090 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
2091 SC_iCoreAudioDriver::SC_iCoreAudioDriver(struct World *inWorld)
2092 : SC_AudioDriver(inWorld)
2094 receivedIn = 0;
2097 SC_iCoreAudioDriver::~SC_iCoreAudioDriver()
2102 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
2103 const AudioBufferList* inInputData,
2104 const AudioTimeStamp* inInputTime,
2105 AudioBufferList* outOutputData,
2106 const AudioTimeStamp* inOutputTime,
2107 void* defptr);
2108 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
2109 const AudioBufferList* inInputData,
2110 const AudioTimeStamp* inInputTime,
2111 AudioBufferList* outOutputData,
2112 const AudioTimeStamp* inOutputTime,
2113 void* defptr)
2115 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
2117 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
2119 AudioTimeStamp readTime;
2120 readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback();
2121 readTime.mFlags = kAudioTimeStampSampleTimeValid;
2123 AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList());
2125 def->Run(def->GetInputBufferList(), outOutputData, oscTime);
2127 return kAudioHardwareNoError;
2132 OSStatus InputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
2134 SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon;
2136 if (driver->receivedIn)
2138 //printf("exit input with no data \n");
2139 return noErr;
2142 OSStatus ret = AudioUnitRender(driver->inputUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, driver->buflist);
2143 if (ret)
2145 //printf("no input !\n");
2146 return noErr;
2148 driver->receivedIn = 1;
2150 return noErr;
2153 OSStatus RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
2155 SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon;
2157 #ifndef SC_IPHONE
2158 if (!driver->receivedIn)
2160 //printf("exit output with no data \n");
2161 return noErr;
2163 #endif
2165 //float *fbuffer = (float *) driver->converter_buffer;
2167 int i;
2168 for (i=0; i<inNumberFrames; i++)
2170 signed short s = ((signed short *)driver->buflist->mBuffers[0].mData)[i];
2171 int k = s + 0x43c00000;
2172 float f = *((float *) &k);
2173 ((float *)driver->floatInputList->mBuffers[0].mData)[i] = f - 384.0f;
2176 int64 oscTime = GetCurrentOSCTime();
2177 //driver->Run(driver->floatInputList, driver->floatOutputList, oscTime);
2178 driver->Run(driver->floatInputList, ioData, oscTime);
2180 for (i=0; i<inNumberFrames; i++)
2182 float f1 = ((float *)ioData->mBuffers[0].mData)[i];
2183 float f2 = ((float *)ioData->mBuffers[1].mData)[i];
2184 ((int *) ioData->mBuffers[0].mData)[i] = (int) (f1*16777216);
2185 ((int *) ioData->mBuffers[1].mData)[i] = (int) (f2*16777216);
2190 unsigned long size = 2*1024*sizeof(unsigned long);
2191 OSStatus ret = AudioConverterConvertBuffer(driver->converter_in_to_F32, driver->buflist->mBuffers[0].mDataByteSize, driver->buflist->mBuffers[0].mData, &size, driver->converter_buffer);
2192 if (ret)
2194 printf("couldn't convert !\n");
2195 return noErr;
2198 int i;
2199 for (i=0; i<inNumberFrames; i++)
2201 ((int *)ioData->mBuffers[0].mData)[i] = ((int *)ioData->mBuffers[1].mData)[i] = driver->converter_buffer[2*i];
2204 driver->receivedIn = 0;
2205 return noErr;
2210 void SC_iCoreAudioDriver::Run(const AudioBufferList* inInputData,
2211 AudioBufferList* outOutputData, int64 oscTime)
2213 int64 systemTimeBefore = GetMicroseconds();
2215 World *world = mWorld;
2217 try {
2218 int numSamplesPerCallback = NumSamplesPerCallback();
2219 mOSCbuftime = oscTime;
2221 #ifdef __APPLE__
2222 sc_SetDenormalFlags();
2223 #endif
2225 mFromEngine.Free();
2227 mToEngine.Perform();
2228 mOscPacketsToEngine.Perform();
2229 //printf("mOscPacketsToEngine : %d micros\n", (int) (GetMicroseconds()-systemTimeBefore));
2231 int bufFrames = world->mBufLength;
2232 int numBufs = numSamplesPerCallback / bufFrames;
2234 int numInputBuses = world->mNumInputs;
2235 int numOutputBuses = world->mNumOutputs;
2236 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
2237 float* outputBuses = world->mAudioBus;
2238 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
2239 int32* outputTouched = world->mAudioBusTouched;
2240 int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0;
2241 int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0;
2243 //static int go = 0;
2245 int64 oscInc = mOSCincrement;
2246 double oscToSamples = mOSCtoSamples;
2248 int bufFramePos = 0;
2250 for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) {
2251 int32 bufCounter = world->mBufCounter;
2253 // de-interleave input
2254 if (inInputData) {
2255 const AudioBuffer* inInputDataBuffers = inInputData->mBuffers;
2256 for (int s = 0, b = 0; b<numInputBuses && s < numInputStreams; s++) {
2257 const AudioBuffer* buf = inInputDataBuffers + s;
2258 int nchan = buf->mNumberChannels;
2259 if (buf->mData) {
2260 float *busdata = inputBuses + b * bufFrames;
2261 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
2262 if (nchan == 1)
2264 #ifdef IPHONE_VEC
2265 vcopy(busdata, bufdata, bufFrames);
2266 #else
2267 for (int k=0; k<bufFrames; ++k)
2269 busdata[k] = bufdata[k];
2271 #endif
2272 inputTouched[b] = bufCounter;
2273 } else {
2274 int minchan = sc_min(nchan, numInputBuses - b);
2275 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
2276 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
2277 busdata[k] = bufdata[m];
2279 inputTouched[b+j] = bufCounter;
2282 b += nchan;
2286 //count++;
2288 int64 schedTime;
2289 int64 nextTime = oscTime + oscInc;
2291 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
2292 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
2293 float diffTimeFloor = floor(diffTime);
2294 world->mSampleOffset = (int)diffTimeFloor;
2295 world->mSubsampleOffset = diffTime - diffTimeFloor;
2297 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
2298 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
2300 SC_ScheduledEvent event = mScheduler.Remove();
2301 event.Perform();
2303 world->mSampleOffset = 0;
2304 world->mSubsampleOffset = 0.f;
2306 //int64 now = GetMicroseconds();
2308 World_Run(world);
2310 //printf("world run : %fms\n", (float) (GetMicroseconds()-now)/1000);
2313 // interleave output
2314 AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers;
2315 for (int s = 0, b = 0; b<numOutputBuses && s < numOutputStreams; s++) {
2316 AudioBuffer* buf = outOutputDataBuffers + s;
2317 int nchan = buf->mNumberChannels;
2318 if (buf->mData) {
2319 float *busdata = outputBuses + b * bufFrames;
2320 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
2321 if (nchan == 1)
2323 if (outputTouched[b] == bufCounter)
2325 #ifdef IPHONE_VEC
2326 vcopy(bufdata, busdata, bufFrames);
2327 #else
2328 for (int k=0; k<bufFrames; ++k)
2330 bufdata[k] = busdata[k];
2332 #endif
2334 } else {
2335 int minchan = sc_min(nchan, numOutputBuses - b);
2336 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
2337 if (outputTouched[b+j] == bufCounter) {
2338 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
2339 bufdata[m] = busdata[k];
2344 b += nchan;
2347 oscTime = mOSCbuftime = nextTime;
2349 } catch (std::exception& exc) {
2350 scprintf("exception in real time: %s\n", exc.what());
2351 } catch (...) {
2352 scprintf("unknown exception in real time\n");
2355 int64 systemTimeAfter = GetMicroseconds();
2356 double calcTime = (double)(systemTimeAfter - systemTimeBefore) * 1e-6;
2357 double cpuUsage = calcTime * mBuffersPerSecond * 100.;
2358 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2359 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2361 mPeakCPU = cpuUsage;
2362 mPeakCounter = mMaxPeakCounter;
2365 mAudioSync.Signal();
2372 OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow,
2373 const AudioBufferList* inInputData,
2374 const AudioTimeStamp* inInputTime,
2375 AudioBufferList* outOutputData,
2376 const AudioTimeStamp* inOutputTime,
2377 void* defptr)
2379 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
2380 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
2382 double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9;
2383 double sampleTime = inOutputTime->mSampleTime;
2384 if (def->mStartHostSecs == 0) {
2385 def->mStartHostSecs = hostSecs;
2386 def->mStartSampleTime = sampleTime;
2387 } else {
2388 double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs);
2389 double smoothSampleRate = def->mSmoothSampleRate;
2390 smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
2391 def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate);
2392 def->mSmoothSampleRate = smoothSampleRate;
2394 #if 0
2395 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs);
2396 double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime);
2397 double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs);
2398 //if (fabs(jitter) > 0.01) {
2399 scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n",
2400 avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement);
2402 #endif
2404 def->mPrevHostSecs = hostSecs;
2405 def->mPrevSampleTime = sampleTime;
2407 if (!def->UseSeparateIO())
2409 def->Run(inInputData, outOutputData, oscTime);
2410 return kAudioHardwareNoError;
2414 def->Run(lastInputData, outOutputData, oscTime);
2415 lastInputData = 0;
2417 return kAudioHardwareNoError;
2422 void AudioSessionInterruptionCbk(void *inClientData, UInt32 inInterruptionState)
2427 bool SC_iCoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
2429 AudioSessionInitialize(0, 0, AudioSessionInterruptionCbk, 0);
2430 unsigned long category = kAudioSessionCategory_PlayAndRecord;
2431 #ifdef SC_IPHONE
2432 UInt32 micInput, micInputSize = sizeof(&micInput);
2433 AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &micInputSize, &micInput);
2434 if(!micInput) {
2435 category = kAudioSessionCategory_MediaPlayback;
2436 scprintf("SC_IPHONE: WARNING - no audio input available\n");
2438 #endif
2439 AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
2441 if (mPreferredHardwareBufferFrameSize)
2443 Float32 preferredBufferSize = (float) mPreferredHardwareBufferFrameSize/44100.f;
2444 AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
2447 AudioSessionSetActive(true);
2449 float actualBufferDuration;
2450 UInt32 size = sizeof(actualBufferDuration);
2451 AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &actualBufferDuration);
2453 *outNumSamplesPerCallback = (int) (actualBufferDuration*44100.f+0.5f);
2454 *outSampleRate = 44100;
2456 AudioComponentDescription desc;
2457 desc.componentType = kAudioUnitType_Output;
2458 desc.componentSubType = kAudioUnitSubType_RemoteIO;
2459 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
2461 NewAUGraph(&graph);
2462 AUNode node;
2463 AudioUnit unit;
2464 OSStatus ret = AUGraphAddNode(graph, &desc, &node);
2465 //printf("node : %d\n", node);
2466 AUGraphOpen(graph);
2468 ret = AUGraphNodeInfo(graph, node, &desc, &unit);
2469 //printf("%d\n", unit);
2473 AudioComponent remoteIOComp = AudioComponentFindNext(0, &desc);
2474 if (AudioComponentInstanceNew(remoteIOComp, &inputUnit)!=noErr)
2476 //printf("error instantiating RemoteIO\n");
2477 return false;
2479 //printf("instantiated : %d\n", inputUnit);
2481 int enableIO = 1;
2482 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
2483 if (ret!=noErr)
2485 //printf("can't set input : %d\n", ret);
2486 return false;
2488 enableIO = 0;
2489 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
2490 if (ret!=noErr)
2492 //printf("can't set output : %d\n", ret);
2493 return false;
2496 AudioUnitInitialize(inputUnit);
2498 unsigned long bufferSizeBytes = 1024 * sizeof(unsigned long);
2499 buflist = (AudioBufferList *) malloc(sizeof(AudioBufferList));
2500 buflist->mNumberBuffers = 1;
2501 buflist->mBuffers[0].mDataByteSize = bufferSizeBytes;
2502 buflist->mBuffers[0].mData = malloc(bufferSizeBytes);
2503 buflist->mBuffers[0].mNumberChannels = 1;
2505 floatInputList = (AudioBufferList *) malloc(sizeof(AudioBufferList));
2506 floatInputList->mNumberBuffers = 1;
2507 floatInputList->mBuffers[0].mDataByteSize = bufferSizeBytes;
2508 floatInputList->mBuffers[0].mData = malloc(bufferSizeBytes);
2509 floatInputList->mBuffers[0].mNumberChannels = 1;
2512 floatOutputList = (AudioBufferList *) malloc(sizeof(AudioBufferList)+sizeof(AudioBuffer));
2513 floatOutputList->mNumberBuffers = 2;
2514 floatOutputList->mBuffers[0].mDataByteSize = bufferSizeBytes;
2515 floatOutputList->mBuffers[0].mData = malloc(bufferSizeBytes);
2516 floatOutputList->mBuffers[0].mNumberChannels = 1;
2517 floatOutputList->mBuffers[1].mDataByteSize = bufferSizeBytes;
2518 floatOutputList->mBuffers[1].mData = malloc(bufferSizeBytes);
2519 floatOutputList->mBuffers[1].mNumberChannels = 1;
2522 AURenderCallbackStruct inputStruct;
2523 inputStruct.inputProc = InputCallback;
2524 inputStruct.inputProcRefCon = this;
2525 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &inputStruct, sizeof(inputStruct));
2527 AURenderCallbackStruct renderStruct;
2528 renderStruct.inputProc = RenderCallback;
2529 renderStruct.inputProcRefCon = this;
2530 ret = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderStruct, sizeof(renderStruct));
2532 AudioStreamBasicDescription streamFormat;
2533 streamFormat.mFormatID = kAudioFormatLinearPCM;
2534 streamFormat.mFormatFlags =
2535 kAudioFormatFlagIsSignedInteger
2536 | kAudioFormatFlagsNativeEndian
2537 | kLinearPCMFormatFlagIsNonInterleaved
2538 | (24 << kLinearPCMFormatFlagsSampleFractionShift);
2539 streamFormat.mSampleRate = 44100;
2540 streamFormat.mBitsPerChannel = 32;
2541 streamFormat.mChannelsPerFrame = 2;
2542 streamFormat.mFramesPerPacket = 1;
2543 streamFormat.mBytesPerFrame = ( streamFormat.mBitsPerChannel / 8 );
2544 streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame *
2545 streamFormat.mFramesPerPacket;
2547 ret = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(streamFormat));
2550 AudioStreamBasicDescription audioFormat;
2551 audioFormat.mSampleRate = 44100.00;
2552 audioFormat.mFormatID = kAudioFormatLinearPCM;
2553 audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
2554 audioFormat.mFramesPerPacket = 1;
2555 audioFormat.mChannelsPerFrame = 1;
2556 audioFormat.mBitsPerChannel = 16;
2557 audioFormat.mBytesPerPacket = 2;
2558 audioFormat.mBytesPerFrame = 2;
2559 ret = AudioUnitSetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &audioFormat, sizeof(audioFormat));
2563 AudioStreamBasicDescription d;
2564 size = sizeof(d);
2565 ret = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &d, &size);
2567 AudioStreamBasicDescription inputFormat;
2568 AudioStreamBasicDescription outputFormat;
2569 AudioStreamBasicDescription f32Format;
2571 size = sizeof(AudioStreamBasicDescription);
2572 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &inputFormat, &size);
2573 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &inputFormat, &size);
2574 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outputFormat, &size);
2575 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outputFormat, &size);
2577 outputFormat.mChannelsPerFrame = 1;
2579 f32Format.mSampleRate = inputFormat.mSampleRate;
2580 f32Format.mFormatID = inputFormat.mFormatID;
2581 f32Format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
2582 f32Format.mBytesPerPacket = 4;
2583 f32Format.mFramesPerPacket = 1;
2584 f32Format.mBytesPerFrame = 4;
2585 f32Format.mChannelsPerFrame = 1;
2586 f32Format.mBitsPerChannel = 32;
2587 f32Format.mReserved = 0;
2589 ret = AudioConverterNew(&inputFormat, &f32Format, &converter_in_to_F32);
2590 ret = AudioConverterNew(&f32Format, &outputFormat, &converter_F32_to_out);
2591 ret = AudioConverterNew(&inputFormat, &outputFormat, &converter_in_to_out);
2593 AUGraphInitialize(graph);
2595 if(mWorld->mVerbosity >= 0){
2596 scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld);
2598 return true;
2601 bool SC_iCoreAudioDriver::DriverStart()
2603 if(mWorld->mVerbosity >= 0){
2604 scprintf("->SC_CoreAudioDriver::DriverStart\n");
2609 OSStatus ret = AUGraphStart(graph);
2610 AudioOutputUnitStart(inputUnit);
2611 } catch (...) {
2612 scprintf("exception in SC_CoreAudioDriver::DriverStart\n");
2614 if(mWorld->mVerbosity >= 0){
2615 scprintf("<-SC_CoreAudioDriver::DriverStart\n");
2617 return true;
2620 bool SC_iCoreAudioDriver::DriverStop()
2622 if(mWorld->mVerbosity >= 0){
2623 scprintf("->SC_CoreAudioDriver::DriverStop\n");
2626 AUGraphStop(graph);
2627 AudioOutputUnitStop(inputUnit);
2629 if(mWorld->mVerbosity >= 0){
2630 scprintf("<-SC_CoreAudioDriver::DriverStop\n");
2632 return true;
2635 #endif // SC_AUDIO_API_COREAUDIOIPHONE
2640 // =====================================================================
2641 // Audio driver (PortAudio)
2643 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
2645 // =====================================================================
2646 // SC_PortAudioDriver (PortAudio)
2648 #define PRINT_PORTAUDIO_ERROR( function, errorcode )\
2649 scprintf( "SC_PortAudioDriver: PortAudio failed at %s with error: '%s'\n",\
2650 #function, Pa_GetErrorText( errorcode ) )
2652 SC_PortAudioDriver::SC_PortAudioDriver(struct World *inWorld)
2653 : SC_AudioDriver(inWorld)
2654 , mStream(0)
2656 PaError paerror = Pa_Initialize();
2657 if( paerror != paNoError )
2658 PRINT_PORTAUDIO_ERROR( Pa_Initialize, paerror );
2661 SC_PortAudioDriver::~SC_PortAudioDriver()
2663 if( mStream ){
2664 PaError paerror = Pa_CloseStream( mStream );
2665 if( paerror != paNoError )
2666 PRINT_PORTAUDIO_ERROR( Pa_CloseStream, paerror );
2668 Pa_Terminate();
2671 static int SC_PortAudioStreamCallback( const void *input, void *output,
2672 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
2673 PaStreamCallbackFlags statusFlags, void *userData )
2675 SC_PortAudioDriver *driver = (SC_PortAudioDriver*)userData;
2677 return driver->PortAudioCallback( input, output, frameCount, timeInfo, statusFlags );
2680 int SC_PortAudioDriver::PortAudioCallback( const void *input, void *output,
2681 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
2682 PaStreamCallbackFlags statusFlags )
2684 World *world = mWorld;
2685 (void) frameCount, timeInfo, statusFlags; // suppress unused parameter warnings
2687 try {
2688 // synchronise against the output buffer - timeInfo->currentTime is 0.0 bug in PA?
2689 if (mPaStreamStartupTime==0 && mPaStreamStartupTimeOSC==0) {
2690 mPaStreamStartupTimeOSC = GetCurrentOSCTime();
2691 mPaStreamStartupTime = timeInfo->outputBufferDacTime;
2693 mOSCbuftime = PaStreamTimeToOSC(timeInfo->outputBufferDacTime - mPaStreamStartupTime) + mPaStreamStartupTimeOSC;
2695 mFromEngine.Free();
2696 mToEngine.Perform();
2697 mOscPacketsToEngine.Perform();
2699 int numInputs = mInputChannelCount;
2700 int numOutputs = mOutputChannelCount;
2701 const float **inBuffers = (const float**)input;
2702 float **outBuffers = (float**)output;
2704 int numSamples = NumSamplesPerCallback();
2705 int bufFrames = mWorld->mBufLength;
2706 int numBufs = numSamples / bufFrames;
2708 float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
2709 float *outBuses = mWorld->mAudioBus;
2710 int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
2711 int32 *outTouched = mWorld->mAudioBusTouched;
2713 int minInputs = std::min<size_t>(numInputs, mWorld->mNumInputs);
2714 int minOutputs = std::min<size_t>(numOutputs, mWorld->mNumOutputs);
2716 int bufFramePos = 0;
2718 int64 oscTime = mOSCbuftime;
2719 int64 oscInc = mOSCincrement;
2720 double oscToSamples = mOSCtoSamples;
2722 // main loop
2723 for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames)
2725 int32 bufCounter = mWorld->mBufCounter;
2726 int32 *tch;
2728 // copy+touch inputs
2729 tch = inTouched;
2730 for (int k = 0; k < minInputs; ++k)
2732 const float *src = inBuffers[k] + bufFramePos;
2733 float *dst = inBuses + k * bufFrames;
2734 for (int n = 0; n < bufFrames; ++n) *dst++ = *src++;
2735 *tch++ = bufCounter;
2738 // run engine
2739 int64 schedTime;
2740 int64 nextTime = oscTime + oscInc;
2741 // DEBUG
2743 if (mScheduler.Ready(nextTime)) {
2744 double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs;
2745 scprintf("rdy %.6f %.6f %.6f %.6f \n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff, (nextTime-gStartupOSCTime)*kOSCtoSecs);
2748 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
2749 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
2750 float diffTimeFloor = floor(diffTime);
2751 world->mSampleOffset = (int)diffTimeFloor;
2752 world->mSubsampleOffset = diffTime - diffTimeFloor;
2754 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
2755 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
2757 SC_ScheduledEvent event = mScheduler.Remove();
2758 event.Perform();
2760 world->mSampleOffset = 0;
2761 world->mSubsampleOffset = 0.f;
2763 World_Run(world);
2765 // copy touched outputs
2766 tch = outTouched;
2767 for (int k = 0; k < minOutputs; ++k) {
2768 float *dst = outBuffers[k] + bufFramePos;
2769 if (*tch++ == bufCounter) {
2770 float *src = outBuses + k * bufFrames;
2771 for (int n = 0; n < bufFrames; ++n) *dst++ = *src++;
2772 } else {
2773 for (int n = 0; n < bufFrames; ++n) *dst++ = 0.0f;
2777 // update buffer time
2778 oscTime = mOSCbuftime = nextTime;
2780 } catch (std::exception& exc) {
2781 scprintf("SC_PortAudioDriver: exception in real time: %s\n", exc.what());
2782 } catch (...) {
2783 scprintf("SC_PortAudioDriver: unknown exception in real time\n");
2786 double cpuUsage = (double)Pa_GetStreamCpuLoad(mStream);
2787 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2788 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2790 mPeakCPU = cpuUsage;
2791 mPeakCounter = mMaxPeakCounter;
2794 mAudioSync.Signal();
2796 return paContinue;
2799 void SC_PortAudioDriver::GetPaDeviceFromName(const char* device, int* mInOut) {
2801 const PaDeviceInfo *pdi;
2802 const PaHostApiInfo *apiInfo;
2803 char devString[256];
2804 PaDeviceIndex numDevices = Pa_GetDeviceCount();
2805 mInOut[0] = paNoDevice;
2806 mInOut[1] = paNoDevice;
2808 // This tries to find one or two devices that match the given name (substring)
2809 // might cause problems for some names...
2810 for( int i=0; i<numDevices; i++ ) {
2811 pdi = Pa_GetDeviceInfo( i );
2812 apiInfo = Pa_GetHostApiInfo(pdi->hostApi);
2813 strcpy(devString, apiInfo->name);
2814 strcat(devString, " : ");
2815 strcat(devString, pdi->name);
2816 if (strstr(devString, device)) {
2817 if (pdi->maxInputChannels > 0) mInOut[0] = i;
2818 if (pdi->maxOutputChannels > 0) mInOut[1] = i;
2823 // ====================================================================
2826 bool SC_PortAudioDriver::DriverSetup(int* outNumSamples, double* outSampleRate)
2828 int mDeviceInOut[2];
2829 PaError paerror;
2830 const PaDeviceInfo *pdi;
2831 const PaHostApiInfo *apiInfo;
2832 const PaStreamInfo *psi;
2833 PaTime suggestedLatencyIn, suggestedLatencyOut;
2834 PaDeviceIndex numDevices = Pa_GetDeviceCount();
2836 // print out all options:
2837 fprintf(stdout, "\nDevice options:\n");
2838 for( int i=0; i<numDevices; i++ ) {
2839 pdi = Pa_GetDeviceInfo( i );
2840 apiInfo = Pa_GetHostApiInfo(pdi->hostApi);
2841 fprintf(stdout, " - %s : %s (device #%d with %d ins %d outs)\n",apiInfo->name,pdi->name, i, pdi->maxInputChannels, pdi->maxOutputChannels);
2844 mDeviceInOut[0] = paNoDevice;
2845 mDeviceInOut[1] = paNoDevice;
2846 if (mWorld->hw->mInDeviceName)
2847 GetPaDeviceFromName(mWorld->hw->mInDeviceName, mDeviceInOut);
2848 if (mDeviceInOut[0] == paNoDevice) mDeviceInOut[0] = Pa_GetDefaultInputDevice();
2849 if (mDeviceInOut[1] == paNoDevice) mDeviceInOut[1] = Pa_GetDefaultOutputDevice();
2851 *outNumSamples = mWorld->mBufLength;
2852 if (mPreferredSampleRate)
2853 *outSampleRate = mPreferredSampleRate;
2854 else
2855 *outSampleRate = 44100.;
2858 if (mDeviceInOut[0]!=paNoDevice && mDeviceInOut[1]!=paNoDevice) {
2860 if (mPreferredHardwareBufferFrameSize)
2861 // controls the suggested latency by hardwareBufferSize switch -Z
2862 suggestedLatencyIn = suggestedLatencyOut = mPreferredHardwareBufferFrameSize / (*outSampleRate);
2863 else {
2864 suggestedLatencyIn = Pa_GetDeviceInfo( mDeviceInOut[0] )->defaultLowInputLatency;
2865 suggestedLatencyOut = Pa_GetDeviceInfo( mDeviceInOut[1] )->defaultLowOutputLatency;
2868 PaSampleFormat fmt = paFloat32 | paNonInterleaved;
2869 mInputChannelCount = Pa_GetDeviceInfo( mDeviceInOut[0] )->maxInputChannels;
2870 mOutputChannelCount = Pa_GetDeviceInfo( mDeviceInOut[1] )->maxOutputChannels;
2871 fprintf(stdout, "\nBooting with:\n In: %s : %s \n",
2872 Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[0] )->hostApi)->name,
2873 Pa_GetDeviceInfo( mDeviceInOut[0] )->name);
2874 fprintf(stdout, " Out: %s : %s \n",
2875 Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[1] )->hostApi)->name,
2876 Pa_GetDeviceInfo( mDeviceInOut[1] )->name);
2878 PaStreamParameters inStreamParams;
2879 inStreamParams.device = mDeviceInOut[0];
2880 inStreamParams.channelCount = mInputChannelCount;
2881 inStreamParams.sampleFormat = fmt;
2882 inStreamParams.suggestedLatency = suggestedLatencyIn;
2883 inStreamParams.hostApiSpecificStreamInfo = NULL;
2885 PaStreamParameters outStreamParams;
2886 outStreamParams.device = mDeviceInOut[1];
2887 outStreamParams.channelCount = mOutputChannelCount;
2888 outStreamParams.sampleFormat = fmt;
2889 outStreamParams.suggestedLatency = suggestedLatencyOut;
2890 outStreamParams.hostApiSpecificStreamInfo = NULL;
2892 paerror = Pa_OpenStream(&mStream, &inStreamParams, &outStreamParams, *outSampleRate, *outNumSamples, paNoFlag, SC_PortAudioStreamCallback, this );
2893 if( paerror != paNoError )
2894 PRINT_PORTAUDIO_ERROR( Pa_OpenStream, paerror );
2895 else {
2896 psi = Pa_GetStreamInfo(mStream);
2897 if (!psi)
2898 fprintf(stdout," Could not obtain further info from portaudio stream\n");
2899 else {
2900 fprintf(stdout," Sample rate: %.3f\n", psi->sampleRate);
2901 fprintf(stdout," Latency (in/out): %.3f / %.3f sec\n", psi->inputLatency, psi->outputLatency);
2904 return paerror == paNoError;
2907 // should not be necessary, but a last try with OpenDefaultStream...
2908 paerror = Pa_OpenDefaultStream( &mStream, 2, 2,
2909 paFloat32 | paNonInterleaved, *outSampleRate, *outNumSamples, SC_PortAudioStreamCallback, this );
2910 if( paerror != paNoError )
2911 PRINT_PORTAUDIO_ERROR( Pa_OpenDefaultStream, paerror );
2912 return paerror == paNoError;
2915 bool SC_PortAudioDriver::DriverStart()
2917 if (!mStream)
2918 return false;
2920 PaError paerror = Pa_StartStream( mStream );
2921 if( paerror != paNoError )
2922 PRINT_PORTAUDIO_ERROR( Pa_StartStream, paerror );
2924 // sync times
2925 mPaStreamStartupTimeOSC = 0;
2926 mPaStreamStartupTime = 0;
2927 // it would be better to do the sync here, but the timeInfo in the callback is incomplete
2928 //mPaStreamStartupTimeOSC = GetCurrentOSCTime();
2929 //mPaStreamStartupTime = Pa_GetStreamTime(mStream);
2931 return paerror == paNoError;
2934 bool SC_PortAudioDriver::DriverStop()
2936 if (!mStream)
2937 return false;
2939 PaError paerror = Pa_StopStream(mStream);
2940 if( paerror != paNoError )
2941 PRINT_PORTAUDIO_ERROR( Pa_StopStream, paerror );
2943 return paerror == paNoError;
2946 #endif // SC_AUDIO_API_PORTAUDIO