common: win32utils - compile fix
[supercollider.git] / server / scsynth / SC_CoreAudio.cpp
blob75e90ae65c71dcae02950e8f7dd494032dfeb715
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 "SC_ComPort.h"
24 #include <stdarg.h>
25 #include "SC_SequencedCommand.h"
26 #include "SC_Prototypes.h"
27 #include "SC_HiddenWorld.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 void syncOSCOffsetWithTimeOfDay();
82 void syncOSCOffsetWithTimeOfDay()
84 // generate a value gOSCoffset such that
85 // (gOSCOffset + systemTimeInOSCunits)
86 // is equal to gettimeofday time in OSCunits.
87 // Then if this machine is synced via NTP, we are synced with the world.
88 // more accurate way to do this??
90 struct timeval tv;
92 int64 systemTimeBefore, systemTimeAfter, diff;
93 int64 minDiff = 0x7fffFFFFffffFFFFLL;
95 // take best of several tries
96 const int numberOfTries = 5;
97 int64 newOffset = gOSCoffset;
98 for (int i=0; i<numberOfTries; ++i) {
99 systemTimeBefore = AudioGetCurrentHostTime();
100 gettimeofday(&tv, 0);
101 systemTimeAfter = AudioGetCurrentHostTime();
103 diff = systemTimeAfter - systemTimeBefore;
104 if (diff < minDiff) {
105 minDiff = diff;
106 // assume that gettimeofday happens halfway between AudioGetCurrentHostTime calls
107 int64 systemTimeBetween = systemTimeBefore + diff/2;
108 int64 systemTimeInOSCunits = (int64)((double)AudioConvertHostTimeToNanos(systemTimeBetween) * kNanosToOSCunits);
109 int64 timeOfDayInOSCunits = ((int64)(tv.tv_sec + kSECONDS_FROM_1900_to_1970) << 32)
110 + (int64)(tv.tv_usec * kMicrosToOSCunits);
111 newOffset = timeOfDayInOSCunits - systemTimeInOSCunits;
115 gOSCoffset = newOffset;
116 //scprintf("gOSCoffset %016llX\n", gOSCoffset);
119 void* resyncThreadFunc(void* arg);
120 void* resyncThreadFunc(void* /*arg*/)
122 while (true) {
123 sleep(20);
124 syncOSCOffsetWithTimeOfDay();
126 return 0;
129 void initializeScheduler()
131 syncOSCOffsetWithTimeOfDay();
133 pthread_t resyncThread;
134 pthread_create (&resyncThread, NULL, resyncThreadFunc, (void*)0);
135 set_real_time_priority(resyncThread);
137 #endif // SC_AUDIO_API_COREAUDIO
140 // =====================================================================
141 // Timing (CoreAudioIPHONE)
143 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
145 int64 gOSCoffset = 0;
147 static inline int64 GetMicroseconds()
149 struct timeval tv;
150 gettimeofday(&tv, 0);
151 return (int64) tv.tv_sec * 1000000 + tv.tv_usec;
154 static inline int64 GetCurrentOSCTime()
156 struct timeval tv;
157 uint64 s, f;
158 gettimeofday(&tv, 0);
159 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
160 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
162 return (s << 32) + f;
165 int32 server_timeseed()
167 int64 time = GetCurrentOSCTime();
168 return Hash((int32)(time >> 32) + Hash((int32)time));
171 int64 oscTimeNow()
173 return GetCurrentOSCTime();
176 void initializeScheduler()
178 gOSCoffset = GetCurrentOSCTime();
180 #endif // SC_AUDIO_API_COREAUDIO
185 // =====================================================================
186 // Timing (PortAudio)
188 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
190 int64 gOSCoffset = 0;
192 static inline int64 GetCurrentOSCTime()
194 struct timeval tv;
195 uint64 s, f;
196 gettimeofday(&tv, 0);
197 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
198 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
200 return (s << 32) + f;
203 int32 server_timeseed()
205 int64 time = GetCurrentOSCTime();
206 return Hash((int32)(time >> 32) + Hash((int32)time));
209 int64 oscTimeNow()
211 return GetCurrentOSCTime();
214 int64 PaStreamTimeToOSC(PaTime pa_time) {
215 uint64 s, f;
216 s = (uint64)pa_time;
217 f = (uint64)((pa_time - s) * 1000000 * kMicrosToOSCunits);
219 return (s << 32) + f;
222 void initializeScheduler()
224 gOSCoffset = GetCurrentOSCTime();
226 #endif // SC_AUDIO_API_PORTAUDIO
229 // =====================================================================
230 // Packets (Common)
232 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket);
233 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket);
234 int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply);
235 PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc);
237 void Perform_ToEngine_Msg(FifoMsg *inMsg);
238 void FreeOSCPacket(FifoMsg *inMsg);
240 struct IsBundle
242 IsBundle() { str4cpy(s, "#bundle"); }
243 bool checkIsBundle(int32 *in) { return in[0] == s[0] && in[1] == s[1]; }
244 int32 s[2];
246 IsBundle gIsBundle;
248 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket)
250 //scprintf("ProcessOSCPacket %d, '%s'\n", inPacket->mSize, inPacket->mData);
251 if (!inPacket) return false;
252 bool result;
253 inWorld->mDriverLock->Lock();
254 SC_AudioDriver *driver = AudioDriver(inWorld);
255 if (!driver) {
256 inWorld->mDriverLock->Unlock();
257 return false;
259 inPacket->mIsBundle = gIsBundle.checkIsBundle((int32*)inPacket->mData);
260 FifoMsg fifoMsg;
261 fifoMsg.Set(inWorld, Perform_ToEngine_Msg, FreeOSCPacket, (void*)inPacket);
262 result = driver->SendOscPacketMsgToEngine(fifoMsg);
263 inWorld->mDriverLock->Unlock();
264 return result;
267 int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply)
269 // scprintf("->PerformOSCMessage %d\n", inData[0]);
270 SC_LibCmd *cmdObj;
271 int cmdNameLen;
272 if (inData[0] == 0) {
273 cmdNameLen = 4;
274 uint32 index = inData[3];
275 if (index >= NUMBER_OF_COMMANDS) cmdObj = 0;
276 else cmdObj = gCmdArray[index];
277 } else {
278 cmdNameLen = OSCstrlen(inData);
279 cmdObj = gCmdLib->Get((int32*)inData);
281 if (!cmdObj) {
282 CallSendFailureCommand(inWorld, inData, "Command not found", inReply);
283 scprintf("FAILURE %s Command not found\n", inData);
284 return kSCErr_NoSuchCommand;
287 int err = cmdObj->Perform(inWorld, inSize - cmdNameLen, inData + cmdNameLen, inReply);
288 //scprintf("<-PerformOSCMessage %d\n", inData[0]);
289 return err;
292 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket)
294 //scprintf("->PerformOSCBundle %d\n", inPacket->mSize);
295 char *data = inPacket->mData + 16;
296 char* dataEnd = inPacket->mData + inPacket->mSize;
298 while (data < dataEnd) {
299 int32 msgSize = ntohl(*(int32*)data);
300 data += sizeof(int32);
301 //scprintf("msgSize %d\n", msgSize);
302 PerformOSCMessage(inWorld, msgSize, data, &inPacket->mReplyAddr);
303 data += msgSize;
306 // reset so next command uses permanent error notification status
307 inWorld->mLocalErrorNotification = 0;
309 // // 0 is a temporary change, so reset the local error flag
310 // if(!inWorld->mLocalErrorNotification) {
311 // inWorld->mLocalErrorNotification = inWorld->mErrorNotification;
312 // };
314 //scprintf("<-PerformOSCBundle %d\n", inPacket->mSize);
317 PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc freeFunc)
319 SC_AudioDriver *driver = world->hw->mAudioDriver;
321 if (!packet->mIsBundle) {
322 PerformOSCMessage(world, packet->mSize, packet->mData, &packet->mReplyAddr);
323 world->mLocalErrorNotification = 0;
324 // if(!world->mLocalErrorNotification) {
325 // world->mLocalErrorNotification = world->mErrorNotification;
326 // };
327 return PacketPerformed;
328 } else {
329 // in real time engine, schedule the packet
330 int64 time = OSCtime(packet->mData + 8);
331 if (time == 0 || time == 1) {
332 PerformOSCBundle(world, packet);
333 return PacketPerformed;
334 } else {
335 if ((time < driver->mOSCbuftime) && (world->mVerbosity >= 0)) {
336 double seconds = (driver->mOSCbuftime - time)*kOSCtoSecs;
337 scprintf("late %.9f\n", seconds);
338 //FifoMsg outMsg;
340 //ReportLateness(packet->mReply, seconds)
342 // DEBUG
343 // else
344 //scprintf("scheduled in %.6f at time %.6f\n",
345 // (time-driver->mOSCbuftime)*kOSCtoSecs,
346 // (time-gStartupOSCTime)*kOSCtoSecs);
348 SC_ScheduledEvent event(world, time, packet, freeFunc);
349 driver->AddEvent(event);
350 return PacketScheduled;
355 ////////////////////////////////////////////////////////////////////////////
357 void Perform_ToEngine_Msg(FifoMsg *inMsg)
359 World *world = inMsg->mWorld;
360 OSC_Packet *packet = (OSC_Packet*)inMsg->mData;
361 if (!packet) return;
363 PacketStatus status = PerformOSCPacket(world, packet, SC_ScheduledEvent::FreeInNRT);
364 if (status == PacketScheduled) {
365 // Transfer ownership
366 inMsg->mData = 0;
367 inMsg->mFreeFunc = 0;
371 PacketStatus PerformCompletionMsg(World *inWorld, const OSC_Packet& inPacket)
373 OSC_Packet* packet = (OSC_Packet*)World_Alloc(inWorld, sizeof(OSC_Packet));
374 *packet = inPacket;
375 packet->mIsBundle = gIsBundle.checkIsBundle((int32*)packet->mData);
376 PacketStatus status = PerformOSCPacket(inWorld, packet, SC_ScheduledEvent::FreeInRT);
377 if (status == PacketPerformed) {
378 World_Free(inWorld, packet);
380 return status;
383 void FreeOSCPacket(FifoMsg *inMsg)
385 OSC_Packet *packet = (OSC_Packet*)inMsg->mData;
386 if (packet) {
387 inMsg->mData = 0;
388 #ifdef _WIN32
389 #pragma message("$$$todo fixme hack for the 'uninitialized packet->mData ptr when using MSVC 7.1 debug")
390 if (packet->mData != reinterpret_cast<char*>(0xcdcdcdcd))
391 free(packet->mData);
392 #else //#ifdef _WIN32
393 free(packet->mData);
394 #endif //#ifdef _WIN32
395 free(packet);
399 void Free_FromEngine_Msg(FifoMsg *inMsg);
400 void Free_FromEngine_Msg(FifoMsg *inMsg)
402 World_Free(inMsg->mWorld, inMsg->mData);
405 // =====================================================================
406 // Audio driver (Common)
408 SC_AudioDriver::SC_AudioDriver(struct World *inWorld)
409 : mWorld(inWorld)
410 , mSampleTime(0)
411 , mNumSamplesPerCallback(0)
416 SC_AudioDriver::~SC_AudioDriver()
418 mRunThreadFlag = false;
419 mAudioSync.Signal();
420 pthread_join(mThread, 0);
423 void* audio_driver_thread_func(void* arg);
424 void* audio_driver_thread_func(void* arg)
426 SC_AudioDriver *ca = (SC_AudioDriver*)arg;
427 void* result = ca->RunThread();
428 return result;
431 void* SC_AudioDriver::RunThread()
433 TriggersFifo *trigfifo = &mWorld->hw->mTriggers;
434 NodeReplyFifo *nodereplyfifo = &mWorld->hw->mNodeMsgs;
435 NodeEndsFifo *nodeendfifo = &mWorld->hw->mNodeEnds;
436 DeleteGraphDefsFifo *deletegraphfifo = &mWorld->hw->mDeleteGraphDefs;
438 while (mRunThreadFlag) {
439 // wait for sync
440 mAudioSync.WaitNext();
442 mWorld->mNRTLock->Lock();
444 // send /tr messages
445 trigfifo->Perform();
447 // send node reply messages
448 nodereplyfifo->Perform();
450 // send node status messages
451 nodeendfifo->Perform();
453 // free GraphDefs
454 deletegraphfifo->Perform();
456 // perform messages
457 mFromEngine.Perform();
459 mWorld->mNRTLock->Unlock();
461 return 0;
464 bool SC_AudioDriver::SendMsgFromEngine(FifoMsg& inMsg)
466 return mFromEngine.Write(inMsg);
470 bool SC_AudioDriver::SendMsgToEngine(FifoMsg& inMsg)
472 mToEngine.Free();
473 return mToEngine.Write(inMsg);
476 bool SC_AudioDriver::SendOscPacketMsgToEngine(FifoMsg& inMsg)
478 mOscPacketsToEngine.Free();
479 return mOscPacketsToEngine.Write(inMsg);
482 void SC_ScheduledEvent::FreeInRT(struct World* world, OSC_Packet* packet)
484 World_Free(world, packet->mData);
485 World_Free(world, packet);
488 void SC_ScheduledEvent::FreeInNRT(struct World* world, OSC_Packet* packet)
490 FifoMsg msg;
491 msg.Set(world, FreeOSCPacket, 0, (void*)packet);
492 world->hw->mAudioDriver->SendMsgFromEngine(msg);
495 void SC_ScheduledEvent::Perform()
497 PerformOSCBundle(mWorld, mPacket);
498 (*mPacketFreeFunc)(mWorld, mPacket);
501 bool SC_AudioDriver::Setup()
503 mRunThreadFlag = true;
504 pthread_create (&mThread, NULL, audio_driver_thread_func, (void*)this);
505 set_real_time_priority(mThread);
507 int numSamples;
508 double sampleRate;
510 if (!DriverSetup(&numSamples, &sampleRate)) return false;
512 mNumSamplesPerCallback = numSamples;
513 //scprintf("mNumSamplesPerCallback %d\n", mNumSamplesPerCallback);
514 //scprintf("mHardwareBufferSize %lu\n", mHardwareBufferSize);
516 // compute a per sample increment to the OpenSoundControl Time
517 mOSCincrementNumerator = (double)mWorld->mBufLength * pow(2.,32.);
518 mOSCincrement = (int64)(mOSCincrementNumerator / sampleRate);
519 mOSCtoSamples = sampleRate / pow(2.,32.);
521 World_SetSampleRate(mWorld, sampleRate);
522 mSampleRate = mSmoothSampleRate = sampleRate;
523 mBuffersPerSecond = sampleRate / mNumSamplesPerCallback;
524 mMaxPeakCounter = (int)mBuffersPerSecond;
526 if(mWorld->mVerbosity >= 0){
527 scprintf("SC_AudioDriver: sample rate = %f, driver's block size = %d\n", sampleRate, mNumSamplesPerCallback);
530 return true;
533 bool SC_AudioDriver::Start()
535 mAvgCPU = 0.;
536 mPeakCPU = 0.;
537 mPeakCounter = 0;
539 mStartHostSecs = 0.;
540 mPrevHostSecs = 0.;
541 mStartSampleTime = 0.;
542 mPrevSampleTime = 0.;
544 World_Start(mWorld);
546 gStartupOSCTime = oscTimeNow();
548 return DriverStart();
551 bool SC_AudioDriver::Stop()
553 if (!DriverStop()) return false;
554 return true;
558 // =====================================================================
559 // Audio driver (CoreAudio)
560 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO
562 SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld)
564 return new SC_CoreAudioDriver(inWorld);
567 #endif
569 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
571 SC_CoreAudioDriver::SC_CoreAudioDriver(struct World *inWorld)
572 : SC_AudioDriver(inWorld)
573 , mInputBufList(0)
577 SC_CoreAudioDriver::~SC_CoreAudioDriver()
579 if (mInputBufList)
581 int i;
582 for (i=0; i<mInputBufList->mNumberBuffers; i++)
584 free(mInputBufList->mBuffers[i].mData);
586 free(mInputBufList);
590 bool SC_CoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
592 OSStatus err = kAudioHardwareNoError;
593 UInt32 count;
594 mOutputDevice = kAudioDeviceUnknown;
595 mInputDevice = kAudioDeviceUnknown;
597 //scprintf("SC_CoreAudioDriver::Setup world %p\n", mWorld);
599 ////////////////////////////////////////////////////////////////////////////////////////////////
601 do {
602 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0);
604 AudioDeviceID *devices = (AudioDeviceID*)malloc(count);
605 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
606 if (err != kAudioHardwareNoError) {
607 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
608 free(devices);
609 break;
612 int numdevices = count / sizeof(AudioDeviceID);
613 if(mWorld->mVerbosity >= 0){
614 scprintf("Number of Devices: %d\n", numdevices);
616 for (int i = 0; i < numdevices; ++i) {
617 err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
618 if (err != kAudioHardwareNoError) {
619 scprintf("info kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]);
620 break;
623 char *name = (char*)malloc(count);
624 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
625 if (err != kAudioHardwareNoError) {
626 scprintf("get kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]);
627 free(name);
628 break;
630 if(mWorld->mVerbosity >= 0){
631 scprintf(" %d : \"%s\"\n", i, name);
633 free(name);
635 free(devices);
636 if(mWorld->mVerbosity >= 0){
637 scprintf("\n");
639 } while (false);
641 if (mWorld->hw->mInDeviceName || mWorld->hw->mOutDeviceName) {
642 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0);
643 if (err != kAudioHardwareNoError) {
644 scprintf("info kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
645 return false;
648 AudioDeviceID *devices = (AudioDeviceID*)malloc(count);
649 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
650 if (err != kAudioHardwareNoError) {
651 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
652 return false;
655 int numdevices = count / sizeof(AudioDeviceID);
656 for (int i = 0; i < numdevices; ++i) {
657 err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
658 if (err != kAudioHardwareNoError) {
659 scprintf("info kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]);
660 break;
663 char *name = (char*)malloc(count);
664 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
665 if (err != kAudioHardwareNoError) {
666 scprintf("get kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]);
667 return false;
669 if (strcmp(name, mWorld->hw->mInDeviceName) == 0) {
670 mInputDevice = devices[i];
672 if (strcmp(name, mWorld->hw->mOutDeviceName) == 0) {
673 mOutputDevice = devices[i];
675 free(name);
676 if (mInputDevice!=kAudioDeviceUnknown && mOutputDevice!=kAudioDeviceUnknown) break;
678 free(devices);
679 if (mOutputDevice==kAudioDeviceUnknown || mInputDevice==kAudioDeviceUnknown) goto getDefault;
680 } else {
681 getDefault:
683 // get the default output device for the HAL
684 if (mOutputDevice==kAudioDeviceUnknown)
686 count = sizeof(mOutputDevice);
687 //get the output device:
688 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) & mOutputDevice);
689 if (err != kAudioHardwareNoError) {
690 scprintf("get kAudioHardwarePropertyDefaultOutputDevice error %4.4s\n", (char*)&err);
691 return false;
695 //get the input device
696 if (mInputDevice==kAudioDeviceUnknown)
698 count = sizeof(mInputDevice);
699 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &count, (void *) & mInputDevice);
700 //get the input device:
701 if (err != kAudioHardwareNoError) {
702 scprintf("get kAudioHardwarePropertyDefaultInputDevice error %4.4s\n", (char*)&err);
703 return false;
708 ////////////////////////////////////////////////////////////////////////////////////////////////
710 AudioTimeStamp now;
711 now.mFlags = kAudioTimeStampHostTimeValid;
712 now.mHostTime = AudioGetCurrentHostTime();
714 if (mPreferredHardwareBufferFrameSize)
717 count = sizeof(UInt32);
718 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize);
719 if (err != kAudioHardwareNoError) {
720 scprintf("set kAudioDevicePropertyBufferFrameSize error %4.4s\n", (char*)&err);
721 //return false;
723 if (UseSeparateIO())
725 count = sizeof(UInt32);
726 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize);
727 if (err != kAudioHardwareNoError) {
728 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
729 //return false;
734 if (mPreferredSampleRate)
736 Float64 sampleRate = mPreferredSampleRate;
737 count = sizeof(Float64);
738 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
739 if (err != kAudioHardwareNoError) {
740 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
741 //return false;
743 if (UseSeparateIO())
745 count = sizeof(Float64);
746 err = AudioDeviceSetProperty(mInputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
747 if (err != kAudioHardwareNoError) {
748 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
749 //return false;
754 // get the buffersize for the out device
755 count = sizeof(mHardwareBufferSize);
756 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyBufferSize, &count, &mHardwareBufferSize);
757 if (err != kAudioHardwareNoError) {
758 scprintf("get kAudioDevicePropertyBufferSize error %4.4s\n", (char*)&err);
759 return false;
761 //scprintf("mHardwareBufferSize = %ld\n", mHardwareBufferSize);
763 // get a description of the data format used by the output device
764 count = sizeof(AudioStreamBasicDescription);
765 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDesc);
766 if (err != kAudioHardwareNoError) {
767 scprintf("get kAudioDevicePropertyStreamFormat error %4.4s\n", (char*)&err);
768 return false;
771 if (mInputDevice != kAudioDeviceUnknown) {
772 // get a description of the data format used by the input device
773 count = sizeof(AudioStreamBasicDescription);
774 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamFormat, &count, &inputStreamDesc);
775 if (err != kAudioHardwareNoError) {
776 scprintf("get kAudioDevicePropertyStreamFormat error %4.4s\n", (char*)&err);
777 return false;
780 if (inputStreamDesc.mSampleRate != outputStreamDesc.mSampleRate) {
781 scprintf("input and output sample rates do not match. %g != %g\n", inputStreamDesc.mSampleRate, outputStreamDesc.mSampleRate);
782 return false;
786 ////////////////////////////////////////////////////////////////////////////////////////////////
788 do {
789 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
790 if (err != kAudioHardwareNoError) {
791 scprintf("info kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice);
792 break;
795 char *name = (char*)malloc(count);
796 err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name);
797 if (err != kAudioHardwareNoError) {
798 scprintf("get kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice);
799 free(name);
800 break;
803 if(mWorld->mVerbosity >= 0){
804 scprintf("\"%s\" Input Device\n", name);
806 free(name);
808 Boolean writeable;
809 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration,
810 &count, &writeable);
811 if (err != kAudioHardwareNoError) {
812 scprintf("info kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
813 break;
816 AudioBufferList *bufList = (AudioBufferList*)malloc(count);
817 err = AudioDeviceGetProperty(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration,
818 &count, bufList);
819 if (err != kAudioHardwareNoError) {
820 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
821 free(bufList);
822 break;
825 if(mWorld->mVerbosity >= 0){
826 scprintf(" Streams: %d\n", bufList->mNumberBuffers);
827 for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) {
828 scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels);
832 free(bufList);
833 } while (false);
834 if(mWorld->mVerbosity >= 0){
835 scprintf("\n");
838 ////////////////////////////////////////////////////////////////////////////////////////////////
840 do {
841 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
843 char *name = (char*)malloc(count);
844 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name);
845 if (err != kAudioHardwareNoError) {
846 scprintf("get kAudioDevicePropertyDeviceName error %4.4s\n", (char*)&err);
847 free(name);
848 break;
851 if(mWorld->mVerbosity >= 0){
852 scprintf("\"%s\" Output Device\n", name);
854 free(name);
856 Boolean writeable;
857 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration,
858 &count, &writeable);
859 if (err != kAudioHardwareNoError) {
860 scprintf("info kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
861 break;
864 AudioBufferList *bufList = (AudioBufferList*)malloc(count);
865 err = AudioDeviceGetProperty(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration,
866 &count, bufList);
867 if (err != kAudioHardwareNoError) {
868 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
869 free(bufList);
870 break;
873 if(mWorld->mVerbosity >= 0){
874 scprintf(" Streams: %d\n", bufList->mNumberBuffers);
875 for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) {
876 scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels);
879 free(bufList);
880 } while (false);
881 if(mWorld->mVerbosity >= 0){
882 scprintf("\n");
885 ////////////////////////////////////////////////////////////////////////////////////////////////
888 if (UseSeparateIO()) {
889 count = sizeof(UInt32);
890 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertySafetyOffset, &count, &mSafetyOffset);
891 if (err != kAudioHardwareNoError) {
892 scprintf("get kAudioDevicePropertySafetyOffset error %4.4s\n", (char*)&err);
893 return false;
895 if(mWorld->mVerbosity >= 1){
896 scprintf("mSafetyOffset %lu\n", mSafetyOffset);
899 Boolean writeable;
900 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, &writeable);
901 mInputBufList = (AudioBufferList*)malloc(count);
902 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, mInputBufList);
903 if (err != kAudioHardwareNoError) {
904 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
905 return false;
908 if(mWorld->mVerbosity >= 1){
909 scprintf("mNumberBuffers %lu\n", mInputBufList->mNumberBuffers);
911 for (uint32 i=0; i<mInputBufList->mNumberBuffers; ++i) {
912 if(mWorld->mVerbosity >= 1){
913 scprintf(" mDataByteSize %d %lu\n", i, mInputBufList->mBuffers[i].mDataByteSize);
915 mInputBufList->mBuffers[i].mData = zalloc(1, mInputBufList->mBuffers[i].mDataByteSize);
919 AudioTimeStamp now;
920 now.mFlags = kAudioTimeStampHostTimeValid;
921 now.mHostTime = AudioGetCurrentHostTime();
924 err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyRegisterBufferList, count, mInputBufList);
925 if (err != kAudioHardwareNoError) {
926 scprintf("get kAudioDevicePropertyRegisterBufferList error %4.4s\n", (char*)&err);
927 return false;
932 *outNumSamplesPerCallback = mHardwareBufferSize / outputStreamDesc.mBytesPerFrame;
933 *outSampleRate = outputStreamDesc.mSampleRate;
935 if(mWorld->mVerbosity >= 1){
936 scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld);
941 //check if using built-in output, and thus whether there could be headphone plug/un-plug issues
942 //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
944 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
945 if (err != kAudioHardwareNoError) {
946 scprintf("info kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice);
947 return false;
950 char *outputname = (char*)malloc(count);
951 const char *testname = "Built-in Output";
952 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, outputname);
953 if (err != kAudioHardwareNoError) {
954 scprintf("get kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice);
955 return false;
957 builtinoutputflag_ = 0;
959 if (strcmp(testname, outputname) == 0) {
960 builtinoutputflag_ = 1;
962 // else {
964 // //check for an Aggregate Devices with a subdevice which is Built-in Output
965 // //http://lists.apple.com/archives/coreaudio-api/2009/Oct/msg00182.html
968 // }
970 free(outputname);
973 return true;
977 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
978 const AudioBufferList* inInputData,
979 const AudioTimeStamp* inInputTime,
980 AudioBufferList* outOutputData,
981 const AudioTimeStamp* inOutputTime,
982 void* defptr);
983 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
984 const AudioBufferList* inInputData,
985 const AudioTimeStamp* inInputTime,
986 AudioBufferList* outOutputData,
987 const AudioTimeStamp* inOutputTime,
988 void* defptr)
990 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
992 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
994 AudioTimeStamp readTime;
995 readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback();
996 readTime.mFlags = kAudioTimeStampSampleTimeValid;
998 AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList());
1000 def->Run(def->GetInputBufferList(), outOutputData, oscTime);
1002 return kAudioHardwareNoError;
1007 OSStatus appIOProcSeparateIn (AudioDeviceID device, const AudioTimeStamp* inNow,
1008 const AudioBufferList* inInputData,
1009 const AudioTimeStamp* inInputTime,
1010 AudioBufferList* outOutputData,
1011 const AudioTimeStamp* inOutputTime,
1012 void* defptr)
1014 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1016 // copy input data to driver's private buffer list
1017 int i;
1018 for (i=0; i<inInputData->mNumberBuffers; i++)
1020 memcpy(def->mInputBufList->mBuffers[i].mData, inInputData->mBuffers[i].mData, inInputData->mBuffers[i].mDataByteSize);
1023 return kAudioHardwareNoError;
1026 OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow,
1027 const AudioBufferList* inInputData,
1028 const AudioTimeStamp* inInputTime,
1029 AudioBufferList* outOutputData,
1030 const AudioTimeStamp* inOutputTime,
1031 void* defptr)
1033 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1034 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
1036 double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9;
1037 double sampleTime = inOutputTime->mSampleTime;
1038 if (def->mStartHostSecs == 0) {
1039 def->mStartHostSecs = hostSecs;
1040 def->mStartSampleTime = sampleTime;
1041 } else {
1042 double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs);
1043 double smoothSampleRate = def->mSmoothSampleRate;
1044 smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
1045 def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate);
1046 def->mSmoothSampleRate = smoothSampleRate;
1048 #if 0
1049 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs);
1050 double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime);
1051 double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs);
1052 //if (fabs(jitter) > 0.01) {
1053 scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n",
1054 avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement);
1056 #endif
1058 def->mPrevHostSecs = hostSecs;
1059 def->mPrevSampleTime = sampleTime;
1061 if (!def->UseSeparateIO())
1063 def->Run(inInputData, outOutputData, oscTime);
1064 return kAudioHardwareNoError;
1068 def->Run(def->mInputBufList, outOutputData, oscTime);
1069 return kAudioHardwareNoError;
1072 void SC_CoreAudioDriver::Run(const AudioBufferList* inInputData,
1073 AudioBufferList* outOutputData, int64 oscTime)
1075 int64 systemTimeBefore = AudioGetCurrentHostTime();
1076 World *world = mWorld;
1078 try {
1079 int numSamplesPerCallback = NumSamplesPerCallback();
1080 mOSCbuftime = oscTime;
1082 #ifdef __APPLE__
1083 sc_SetDenormalFlags();
1084 #endif
1086 mFromEngine.Free();
1087 /*if (mToEngine.HasData()) {
1088 scprintf("oscTime %.9f %.9f\n", oscTime*kOSCtoSecs, CoreAudioHostTimeToOSC(AudioGetCurrentHostTime())*kOSCtoSecs);
1090 mToEngine.Perform();
1091 mOscPacketsToEngine.Perform();
1093 int bufFrames = world->mBufLength;
1094 int numBufs = numSamplesPerCallback / bufFrames;
1096 int numInputBuses = world->mNumInputs;
1097 int numOutputBuses = world->mNumOutputs;
1098 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
1099 float* outputBuses = world->mAudioBus;
1100 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
1101 int32* outputTouched = world->mAudioBusTouched;
1102 int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0;
1103 int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0;
1105 //static int go = 0;
1107 int64 oscInc = mOSCincrement;
1108 double oscToSamples = mOSCtoSamples;
1110 int bufFramePos = 0;
1112 for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) {
1113 int32 bufCounter = world->mBufCounter;
1115 // de-interleave input
1116 if (inInputData) {
1117 const AudioBuffer* inInputDataBuffers = inInputData->mBuffers;
1118 for (int s = 0, b = 0; b<numInputBuses && s < numInputStreams; s++) {
1119 const AudioBuffer* buf = inInputDataBuffers + s;
1120 int nchan = buf->mNumberChannels;
1121 if (buf->mData) {
1122 float *busdata = inputBuses + b * bufFrames;
1123 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1124 if (nchan == 1) {
1125 for (int k=0; k<bufFrames; ++k) {
1126 busdata[k] = bufdata[k];
1128 inputTouched[b] = bufCounter;
1129 } else {
1130 int minchan = sc_min(nchan, numInputBuses - b);
1131 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1132 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1133 busdata[k] = bufdata[m];
1135 inputTouched[b+j] = bufCounter;
1138 b += nchan;
1142 //count++;
1144 int64 schedTime;
1145 int64 nextTime = oscTime + oscInc;
1147 /*if (mScheduler.Ready(nextTime)) {
1148 double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs;
1149 scprintf("rdy %.9f %.9f %.9f\n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff);
1152 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
1153 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
1154 float diffTimeFloor = floor(diffTime);
1155 world->mSampleOffset = (int)diffTimeFloor;
1156 world->mSubsampleOffset = diffTime - diffTimeFloor;
1158 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
1159 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
1161 SC_ScheduledEvent event = mScheduler.Remove();
1162 event.Perform();
1164 world->mSampleOffset = 0;
1165 world->mSubsampleOffset = 0.f;
1167 World_Run(world);
1169 // interleave output
1170 AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers;
1171 for (int s = 0, b = 0; b<numOutputBuses && s < numOutputStreams; s++) {
1172 AudioBuffer* buf = outOutputDataBuffers + s;
1173 int nchan = buf->mNumberChannels;
1174 if (buf->mData) {
1175 float *busdata = outputBuses + b * bufFrames;
1176 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1177 if (nchan == 1) {
1178 if (outputTouched[b] == bufCounter) {
1179 for (int k=0; k<bufFrames; ++k) {
1180 bufdata[k] = busdata[k];
1183 } else {
1184 int minchan = sc_min(nchan, numOutputBuses - b);
1185 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1186 if (outputTouched[b+j] == bufCounter) {
1187 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1188 bufdata[m] = busdata[k];
1193 b += nchan;
1196 oscTime = mOSCbuftime = nextTime;
1198 } catch (std::exception& exc) {
1199 scprintf("exception in real time: %s\n", exc.what());
1200 } catch (...) {
1201 scprintf("unknown exception in real time\n");
1203 int64 systemTimeAfter = AudioGetCurrentHostTime();
1204 double calcTime = (double)AudioConvertHostTimeToNanos(systemTimeAfter - systemTimeBefore) * 1e-9;
1205 double cpuUsage = calcTime * mBuffersPerSecond * 100.;
1206 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
1207 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
1209 mPeakCPU = cpuUsage;
1210 mPeakCounter = mMaxPeakCounter;
1213 mAudioSync.Signal();
1219 //////////////////////////////////////////////////////////////////////////////////////////
1220 //////////////////////////////////////////////////////////////////////////////////////////
1221 //////////////////////////////////////////////////////////////////////////////////////////
1222 // These are not linked in yet, but we'll need to listen for the properties and stop/restart synthesis
1223 // if sample-rate, format, or device change.
1225 OSStatus hardwareListenerProc ( AudioHardwarePropertyID inPropertyID,
1226 void* inClientData)
1228 OSStatus err = noErr;
1229 char cStr[255];
1230 UInt32 outSize;
1231 Boolean outWritable;
1232 AudioDeviceID deviceID;
1234 switch(inPropertyID)
1236 case kAudioHardwarePropertyDefaultOutputDevice:
1237 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultOutputDevice\r");
1238 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &outWritable);
1239 if (err) break;
1240 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &deviceID);
1241 if (err) break;
1242 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1243 if (err) break;
1244 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1245 if (err) break;
1247 // do something
1249 break;
1251 case kAudioHardwarePropertyDefaultInputDevice:
1252 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultInputDevice\r");
1253 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultInputDevice, &outSize, &outWritable);
1254 if (err) break;
1255 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &outSize, &deviceID);
1256 if (err) break;
1257 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1258 if (err) break;
1259 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1260 if (err) break;
1262 // do something
1264 break;
1266 case kAudioHardwarePropertyDefaultSystemOutputDevice:
1267 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultSystemOutputDevice\r");
1268 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &outWritable);
1269 if (err) break;
1270 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &deviceID);
1271 if (err) break;
1272 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1273 if (err) break;
1274 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1275 if (err) break;
1277 // do something
1279 break;
1281 case kAudioHardwarePropertyDevices:
1283 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDevices\r");
1285 break;
1286 default:
1287 scprintf("%s\n", "***** HARDWARE NOTIFICATION - %4.4s\r", &inPropertyID);
1290 fflush(stdout);
1291 return (noErr);
1297 OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData);
1299 OSStatus AddHardwareListeners(void* inClientData);
1300 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1301 OSStatus AddHardwareListeners(void* inClientData)
1303 OSStatus err = noErr;
1305 //non deprecated but requires AudiObject, bleargh
1306 //err= AudioObjectAddPropertyListener(AudioObject, kAudioHardwarePropertyDefaultOutputDevice, hardwareListenerProc, inClientData);
1308 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultOutputDevice, hardwareListenerProc, inClientData);
1309 if (err) return err;
1311 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultInputDevice, hardwareListenerProc, inClientData);
1312 if (err) return err;
1314 //doesn't matter? Only default looked at by SC?
1315 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultSystemOutputDevice, hardwareListenerProc, inClientData);
1316 if (err) return err;
1318 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, hardwareListenerProc, inClientData);
1319 if (err) return err;
1321 return (err);
1324 bool SC_CoreAudioDriver::DriverStart()
1326 if(mWorld->mVerbosity >= 1){
1327 scprintf("->SC_CoreAudioDriver::DriverStart\n");
1329 OSStatus err = kAudioHardwareNoError;
1330 AudioTimeStamp now;
1331 UInt32 propertySize;
1332 Boolean writable;
1334 if(mWorld->mVerbosity >= 1){
1335 scprintf("start UseSeparateIO?: %d\n", UseSeparateIO());
1338 try {
1339 if (UseSeparateIO()) {
1340 err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup Out device with an IO proc
1341 if (err != kAudioHardwareNoError) {
1342 scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err);
1343 return false;
1346 err = AudioDeviceAddIOProc(mInputDevice, appIOProcSeparateIn, (void *) this); // setup In device with an IO proc
1347 if (err != kAudioHardwareNoError) {
1348 scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err);
1349 return false;
1353 if (mWorld->hw->mInputStreamsEnabled) {
1354 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1355 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1356 su->mIOProc = (void*)appIOProcSeparateIn;
1357 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1358 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled));
1359 for (int i=0; i<len; ++i) {
1360 su->mStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1';
1362 err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1365 if (mWorld->hw->mOutputStreamsEnabled) {
1366 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1367 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1368 su->mIOProc = (void*)appIOProc;
1369 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1370 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled));
1371 for (int i=0; i<len; ++i) {
1372 su->mStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1';
1374 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1377 err = AudioDeviceStart(mInputDevice, appIOProcSeparateIn); // start playing sound through the device
1378 if (err != kAudioHardwareNoError) {
1379 scprintf("AudioDeviceStart failed %d\n", (int)err);
1380 return false;
1383 err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device
1384 if (err != kAudioHardwareNoError) {
1385 scprintf("AudioDeviceStart failed %d\n", (int)err);
1386 err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn); // stop playing sound through the device
1387 return false;
1389 } else {
1390 err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup our device with an IO proc
1391 if (err != kAudioHardwareNoError) {
1392 scprintf("AudioDeviceAddIOProc failed %d\n", (int)err);
1393 return false;
1396 if (mWorld->hw->mInputStreamsEnabled) {
1397 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1398 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1399 su->mIOProc = (void*)appIOProc;
1400 err = AudioDeviceGetProperty(mOutputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1401 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled));
1402 for (int i=0; i<len; ++i) {
1403 su->mStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1';
1405 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1408 if (mWorld->hw->mOutputStreamsEnabled) {
1409 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1410 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1411 su->mIOProc = (void*)appIOProc;
1412 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1413 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled));
1414 for (int i=0; i<len; ++i) {
1415 su->mStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1';
1417 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1420 err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device
1421 if (err != kAudioHardwareNoError) {
1422 scprintf("AudioDeviceStart failed %d\n", (int)err);
1423 return false;
1426 } catch (...) {
1427 scprintf("exception in SC_CoreAudioDriver::DriverStart\n");
1429 if(mWorld->mVerbosity >= 1){
1430 scprintf("<-SC_CoreAudioDriver::DriverStart\n");
1434 //http://lists.apple.com/archives/coreaudio-api/2010/Aug/msg00114.html
1435 CFRunLoopRef theRunLoop = NULL;
1436 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1437 AudioObjectSetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
1439 //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
1440 //by switching to system default?
1441 //AddHardwareListeners(NULL);
1442 //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
1443 AddDeviceListeners(mOutputDevice, this);
1445 return true;
1449 bool SC_CoreAudioDriver::StopStart() {
1451 bool test = DriverStop();
1453 bool test2 = DriverStart();
1454 return test && test2;
1458 bool SC_CoreAudioDriver::DriverStop()
1460 if(mWorld->mVerbosity >= 1){
1461 scprintf("->SC_CoreAudioDriver::DriverStop\n");
1463 OSStatus err = kAudioHardwareNoError;
1465 if (UseSeparateIO()) {
1466 err = AudioDeviceStop(mOutputDevice, appIOProc);
1467 if (err != kAudioHardwareNoError) {
1468 scprintf("AudioDeviceStop A failed %p\n", err);
1469 return false;
1471 err = AudioDeviceRemoveIOProc(mOutputDevice, appIOProc);
1472 if (err != kAudioHardwareNoError) {
1473 scprintf("AudioDeviceRemoveIOProc A failed %p\n", err);
1474 return false;
1477 err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn);
1478 if (err != kAudioHardwareNoError) {
1479 scprintf("AudioDeviceStop A failed %p\n", err);
1480 return false;
1483 err = AudioDeviceRemoveIOProc(mInputDevice, appIOProcSeparateIn);
1484 if (err != kAudioHardwareNoError) {
1485 scprintf("AudioDeviceRemoveIOProc A failed %p\n", err);
1486 return false;
1488 } else {
1489 err = AudioDeviceStop(mOutputDevice, appIOProc);
1490 if (err != kAudioHardwareNoError) {
1491 scprintf("AudioDeviceStop B failed %p\n", err);
1492 return false;
1495 err = AudioDeviceRemoveIOProc(mOutputDevice, appIOProc);
1496 if (err != kAudioHardwareNoError) {
1497 scprintf("AudioDeviceRemoveIOProc B failed %p\n", err);
1498 return false;
1501 if(mWorld->mVerbosity >= 1){
1502 scprintf("<-SC_CoreAudioDriver::DriverStop\n");
1504 return true;
1508 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1509 // Listen for Device Properties and update interface and globals
1510 OSStatus deviceListenerProc ( AudioDeviceID inDevice,
1511 UInt32 inLine,
1512 Boolean isInput,
1513 AudioDevicePropertyID inPropertyID,
1514 void* inClientData)
1516 OSStatus err = noErr;
1517 UInt32 outSize,
1518 theUIntData,
1519 mute,
1520 playThru;
1521 UInt32 tLong;
1522 Float32 vol;
1525 SC_CoreAudioDriver* coredriver = (SC_CoreAudioDriver*) inClientData;
1527 switch(inPropertyID)
1529 // case kAudioDevicePropertyBufferSize:
1530 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferSize\r");
1531 // outSize = sizeof(UInt32);
1532 // err = AudioDeviceGetProperty(inDevice, 0, 0, kAudioDevicePropertyBufferSize, &outSize, &theUIntData);
1534 // break;
1536 // case kAudioDevicePropertyBufferFrameSize:
1537 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferFrameSize\r");
1538 // outSize = sizeof(UInt32);
1539 // err = AudioDeviceGetProperty(inDevice, 0, 0, kAudioDevicePropertyBufferFrameSize, &outSize, &theUIntData);
1541 // break;
1543 // case kAudioDevicePropertyBufferSizeRange:
1544 // {
1545 // AudioValueRange range;
1547 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferSizeRange\r");
1548 // outSize = sizeof(AudioValueRange);
1549 // err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyBufferSizeRange, &outSize, &range);
1550 // }
1551 // break;
1553 // case kAudioDevicePropertyStreamFormat:
1554 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyStreamFormat\r");
1555 // break;
1557 // case kAudioDevicePropertyDeviceIsRunning:
1558 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDeviceIsRunning\r");
1559 // outSize = sizeof(UInt32);
1560 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyDeviceIsRunning, &outSize, &theUIntData);
1562 // //when change device get up to four messages:
1563 // //isInput ==NO or YES theUIntData= 0 or 1 from old and possibly new device (ieheadphone swap)
1567 // break;
1569 // case kAudioDevicePropertyVolumeScalar:
1570 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyVolumeScalar\r");
1571 // outSize = sizeof(Float32);
1572 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyVolumeScalar, &outSize, &vol);
1573 // break;
1575 // case kAudioDevicePropertyMute:
1576 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyMute\r");
1577 // outSize = sizeof(UInt32);
1578 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyMute, &outSize, &mute);
1579 // break;
1581 // case kAudioDevicePropertyPlayThru:
1582 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyPlayThru\r");
1583 // outSize = sizeof(UInt32);
1584 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyPlayThru, &outSize, &playThru);
1586 // break;
1588 // case kAudioDevicePropertyDeviceIsAlive:
1589 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDeviceIsAlive\r");
1590 // outSize = sizeof(UInt32);
1591 // err = AudioDeviceGetProperty(inDevice, 0, false, kAudioDevicePropertyDeviceIsAlive, &outSize, &tLong);
1593 // break;
1595 case kAudioDevicePropertyDataSource:
1596 //Don't print anything
1597 //scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDataSource\r");
1598 // get the source
1599 // match the source to one of the available sources and return the index of that source
1600 //SetControlValue(control, (chan->vol) * 100);
1602 //will get this message anyway even if don't have built-in output seleected.
1603 //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
1604 //swapping to new driver
1605 if (coredriver->builtinoutputflag_==1)
1606 coredriver->StopStart();
1609 break;
1611 //default:
1612 // scprintf("%s\n", "***** DEVICE NOTIFICATION - %4.4s\r", &inPropertyID);
1615 //fflush(stdout);
1616 return (err);
1619 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1620 OSStatus streamListenerProc ( AudioStreamID inStream,
1621 UInt32 inChannel,
1622 AudioDevicePropertyID inPropertyID,
1623 void* inClientData)
1625 OSStatus err = noErr;
1627 switch(inPropertyID)
1629 case kAudioStreamPropertyPhysicalFormat:
1630 scprintf("%s\n", "***** STREAM NOTIFICATION - kAudioStreamPropertyPhysicalFormat\r");
1631 break;
1633 case kAudioDevicePropertyStreamFormat:
1634 scprintf("%s\n", "***** STREAM NOTIFICATION - kAudioDevicePropertyStreamFormat\r");
1635 break;
1637 default:
1638 break;
1641 fflush(stdout);
1643 return (err);
1646 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1647 OSStatus AddStreamListeners (AudioDeviceID inDevice, AudioDevicePropertyID inPropertyID, Boolean isInput, void *inClientData);
1649 OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData)
1651 OSStatus err = noErr;
1653 //ONLY REACTING TO HEADPHONE SWAPS FOR NOW
1657 // // kAudioDevicePropertyBufferSize
1658 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferSize, deviceListenerProc, inClientData);
1659 // if (err) return err;
1661 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferSize, deviceListenerProc, inClientData);
1662 // if (err) return err;
1665 // // kAudioDevicePropertyBufferFrameSize
1666 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferFrameSize, deviceListenerProc, inClientData);
1667 // if (err) return err;
1669 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferFrameSize, deviceListenerProc, inClientData);
1670 // if (err) return err;
1672 // // kAudioDevicePropertyDeviceIsRunning
1673 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDeviceIsRunning, deviceListenerProc, inClientData);
1674 // if (err) return err;
1676 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDeviceIsRunning, deviceListenerProc, inClientData);
1677 // if (err) return err;
1679 ///*
1680 // for (i = 0; i <= deviceInfo->totalOutputChannels; i++)
1681 // {
1682 // // kAudioDevicePropertyVolumeScalar output
1683 // err = AudioDeviceAddPropertyListener(inDevice, i, false, kAudioDevicePropertyVolumeScalar, deviceListenerProc, inClientData);
1684 // if (err) return err;
1686 // // kAudioDevicePropertyVolumeMute output
1687 // err = AudioDeviceAddPropertyListener(inDevice, i, false, kAudioDevicePropertyMute, deviceListenerProc, inClientData);
1688 // if (err) return err;
1689 // }
1691 // for (i = 0; i <= deviceInfo->totalInputChannels; i++)
1692 // {
1693 // // kAudioDevicePropertyVolumeScalar input
1694 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyVolumeScalar, deviceListenerProc, inClientData);
1695 // if (err) return err;
1697 // // kAudioDevicePropertyVolumeMute input
1698 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyMute, deviceListenerProc, inClientData);
1699 // if (err) return err;
1701 // // kAudioDevicePropertyPlayThru input
1702 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyPlayThru, deviceListenerProc, inClientData);
1703 // if (err) return err;
1704 // }
1705 //*/
1707 // // kAudioDevicePropertyDeviceIsAlive
1708 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDeviceIsAlive, deviceListenerProc, inClientData);
1709 // if (err) return err;
1711 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDeviceIsAlive, deviceListenerProc, inClientData);
1712 // if (err) return err;
1715 // // kAudioDevicePropertyStreamFormat
1716 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyStreamFormat, deviceListenerProc, inClientData);
1717 // if (err) return err;
1719 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyStreamFormat, deviceListenerProc, inClientData);
1720 // if (err) return err;
1722 // // kAudioDevicePropertyBufferSizeRange
1723 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferSizeRange, deviceListenerProc, inClientData);
1724 // if (err) return err;
1726 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferSizeRange, deviceListenerProc, inClientData);
1727 // if (err) return err;
1729 //kAudioDevicePropertyDataSource
1730 err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDataSource, deviceListenerProc, inClientData);
1731 if (err) return err;
1733 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDataSource, deviceListenerProc, inClientData);
1734 // if (err) return err;
1737 //AddStreamListeners (inDevice, kAudioStreamPropertyPhysicalFormat, false, inClientData);
1739 //AddStreamListeners (inDevice, kAudioStreamPropertyPhysicalFormat, true, inClientData);
1741 return (err);
1746 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1747 OSStatus AddStreamListeners (AudioDeviceID inDevice, AudioDevicePropertyID inPropertyID, Boolean isInput, void *inClientData)
1749 OSStatus err = noErr;
1750 UInt32 count;
1751 UInt32 outSize;
1752 Boolean outWritable;
1753 AudioStreamID *streamList = nil;
1755 err = AudioDeviceGetPropertyInfo(inDevice, 0, isInput, kAudioDevicePropertyStreams, &outSize, &outWritable);
1756 if (err == noErr)
1758 streamList = (AudioStreamID*)malloc(outSize);
1759 err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyStreams, &outSize, streamList);
1760 if (err == noErr)
1762 for (count = 0; count < (outSize / sizeof(AudioStreamID)); count++)
1764 err = AudioStreamAddPropertyListener(streamList[count], 0, inPropertyID, streamListenerProc, inClientData);
1765 if (err) return err;
1768 if (streamList != nil)
1770 free(streamList);
1771 streamList = nil;
1776 return (noErr);
1778 #endif // SC_AUDIO_API_COREAUDIO
1783 // =====================================================================
1784 // Audio driver (CoreAudioIPHONE)
1786 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
1787 SC_iCoreAudioDriver::SC_iCoreAudioDriver(struct World *inWorld)
1788 : SC_AudioDriver(inWorld)
1790 receivedIn = 0;
1793 SC_iCoreAudioDriver::~SC_iCoreAudioDriver()
1798 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
1799 const AudioBufferList* inInputData,
1800 const AudioTimeStamp* inInputTime,
1801 AudioBufferList* outOutputData,
1802 const AudioTimeStamp* inOutputTime,
1803 void* defptr);
1804 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
1805 const AudioBufferList* inInputData,
1806 const AudioTimeStamp* inInputTime,
1807 AudioBufferList* outOutputData,
1808 const AudioTimeStamp* inOutputTime,
1809 void* defptr)
1811 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1813 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
1815 AudioTimeStamp readTime;
1816 readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback();
1817 readTime.mFlags = kAudioTimeStampSampleTimeValid;
1819 AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList());
1821 def->Run(def->GetInputBufferList(), outOutputData, oscTime);
1823 return kAudioHardwareNoError;
1828 OSStatus InputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
1830 SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon;
1832 if (driver->receivedIn)
1834 //printf("exit input with no data \n");
1835 return noErr;
1838 OSStatus ret = AudioUnitRender(driver->inputUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, driver->buflist);
1839 if (ret)
1841 //printf("no input !\n");
1842 return noErr;
1844 driver->receivedIn = 1;
1846 return noErr;
1849 OSStatus RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
1851 SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon;
1853 #ifndef SC_IPHONE
1854 if (!driver->receivedIn)
1856 //printf("exit output with no data \n");
1857 return noErr;
1859 #endif
1861 //float *fbuffer = (float *) driver->converter_buffer;
1863 int i;
1864 for (i=0; i<inNumberFrames; i++)
1866 signed short s = ((signed short *)driver->buflist->mBuffers[0].mData)[i];
1867 int k = s + 0x43c00000;
1868 float f = *((float *) &k);
1869 ((float *)driver->floatInputList->mBuffers[0].mData)[i] = f - 384.0f;
1872 int64 oscTime = GetCurrentOSCTime();
1873 //driver->Run(driver->floatInputList, driver->floatOutputList, oscTime);
1874 driver->Run(driver->floatInputList, ioData, oscTime);
1876 for (i=0; i<inNumberFrames; i++)
1878 float f1 = ((float *)ioData->mBuffers[0].mData)[i];
1879 float f2 = ((float *)ioData->mBuffers[1].mData)[i];
1880 ((int *) ioData->mBuffers[0].mData)[i] = (int) (f1*16777216);
1881 ((int *) ioData->mBuffers[1].mData)[i] = (int) (f2*16777216);
1886 unsigned long size = 2*1024*sizeof(unsigned long);
1887 OSStatus ret = AudioConverterConvertBuffer(driver->converter_in_to_F32, driver->buflist->mBuffers[0].mDataByteSize, driver->buflist->mBuffers[0].mData, &size, driver->converter_buffer);
1888 if (ret)
1890 printf("couldn't convert !\n");
1891 return noErr;
1894 int i;
1895 for (i=0; i<inNumberFrames; i++)
1897 ((int *)ioData->mBuffers[0].mData)[i] = ((int *)ioData->mBuffers[1].mData)[i] = driver->converter_buffer[2*i];
1900 driver->receivedIn = 0;
1901 return noErr;
1906 void SC_iCoreAudioDriver::Run(const AudioBufferList* inInputData,
1907 AudioBufferList* outOutputData, int64 oscTime)
1909 int64 systemTimeBefore = GetMicroseconds();
1911 World *world = mWorld;
1913 try {
1914 int numSamplesPerCallback = NumSamplesPerCallback();
1915 mOSCbuftime = oscTime;
1917 #ifdef __APPLE__
1918 sc_SetDenormalFlags();
1919 #endif
1921 mFromEngine.Free();
1923 mToEngine.Perform();
1924 mOscPacketsToEngine.Perform();
1925 //printf("mOscPacketsToEngine : %d micros\n", (int) (GetMicroseconds()-systemTimeBefore));
1927 int bufFrames = world->mBufLength;
1928 int numBufs = numSamplesPerCallback / bufFrames;
1930 int numInputBuses = world->mNumInputs;
1931 int numOutputBuses = world->mNumOutputs;
1932 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
1933 float* outputBuses = world->mAudioBus;
1934 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
1935 int32* outputTouched = world->mAudioBusTouched;
1936 int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0;
1937 int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0;
1939 //static int go = 0;
1941 int64 oscInc = mOSCincrement;
1942 double oscToSamples = mOSCtoSamples;
1944 int bufFramePos = 0;
1946 for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) {
1947 int32 bufCounter = world->mBufCounter;
1949 // de-interleave input
1950 if (inInputData) {
1951 const AudioBuffer* inInputDataBuffers = inInputData->mBuffers;
1952 for (int s = 0, b = 0; b<numInputBuses && s < numInputStreams; s++) {
1953 const AudioBuffer* buf = inInputDataBuffers + s;
1954 int nchan = buf->mNumberChannels;
1955 if (buf->mData) {
1956 float *busdata = inputBuses + b * bufFrames;
1957 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1958 if (nchan == 1)
1960 #ifdef IPHONE_VEC
1961 vcopy(busdata, bufdata, bufFrames);
1962 #else
1963 for (int k=0; k<bufFrames; ++k)
1965 busdata[k] = bufdata[k];
1967 #endif
1968 inputTouched[b] = bufCounter;
1969 } else {
1970 int minchan = sc_min(nchan, numInputBuses - b);
1971 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1972 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1973 busdata[k] = bufdata[m];
1975 inputTouched[b+j] = bufCounter;
1978 b += nchan;
1982 //count++;
1984 int64 schedTime;
1985 int64 nextTime = oscTime + oscInc;
1987 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
1988 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
1989 float diffTimeFloor = floor(diffTime);
1990 world->mSampleOffset = (int)diffTimeFloor;
1991 world->mSubsampleOffset = diffTime - diffTimeFloor;
1993 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
1994 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
1996 SC_ScheduledEvent event = mScheduler.Remove();
1997 event.Perform();
1999 world->mSampleOffset = 0;
2000 world->mSubsampleOffset = 0.f;
2002 //int64 now = GetMicroseconds();
2004 World_Run(world);
2006 //printf("world run : %fms\n", (float) (GetMicroseconds()-now)/1000);
2009 // interleave output
2010 AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers;
2011 for (int s = 0, b = 0; b<numOutputBuses && s < numOutputStreams; s++) {
2012 AudioBuffer* buf = outOutputDataBuffers + s;
2013 int nchan = buf->mNumberChannels;
2014 if (buf->mData) {
2015 float *busdata = outputBuses + b * bufFrames;
2016 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
2017 if (nchan == 1)
2019 if (outputTouched[b] == bufCounter)
2021 #ifdef IPHONE_VEC
2022 vcopy(bufdata, busdata, bufFrames);
2023 #else
2024 for (int k=0; k<bufFrames; ++k)
2026 bufdata[k] = busdata[k];
2028 #endif
2030 } else {
2031 int minchan = sc_min(nchan, numOutputBuses - b);
2032 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
2033 if (outputTouched[b+j] == bufCounter) {
2034 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
2035 bufdata[m] = busdata[k];
2040 b += nchan;
2043 oscTime = mOSCbuftime = nextTime;
2045 } catch (std::exception& exc) {
2046 scprintf("exception in real time: %s\n", exc.what());
2047 } catch (...) {
2048 scprintf("unknown exception in real time\n");
2051 int64 systemTimeAfter = GetMicroseconds();
2052 double calcTime = (double)(systemTimeAfter - systemTimeBefore) * 1e-6;
2053 double cpuUsage = calcTime * mBuffersPerSecond * 100.;
2054 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2055 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2057 mPeakCPU = cpuUsage;
2058 mPeakCounter = mMaxPeakCounter;
2061 mAudioSync.Signal();
2068 OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow,
2069 const AudioBufferList* inInputData,
2070 const AudioTimeStamp* inInputTime,
2071 AudioBufferList* outOutputData,
2072 const AudioTimeStamp* inOutputTime,
2073 void* defptr)
2075 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
2076 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
2078 double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9;
2079 double sampleTime = inOutputTime->mSampleTime;
2080 if (def->mStartHostSecs == 0) {
2081 def->mStartHostSecs = hostSecs;
2082 def->mStartSampleTime = sampleTime;
2083 } else {
2084 double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs);
2085 double smoothSampleRate = def->mSmoothSampleRate;
2086 smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
2087 def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate);
2088 def->mSmoothSampleRate = smoothSampleRate;
2090 #if 0
2091 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs);
2092 double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime);
2093 double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs);
2094 //if (fabs(jitter) > 0.01) {
2095 scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n",
2096 avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement);
2098 #endif
2100 def->mPrevHostSecs = hostSecs;
2101 def->mPrevSampleTime = sampleTime;
2103 if (!def->UseSeparateIO())
2105 def->Run(inInputData, outOutputData, oscTime);
2106 return kAudioHardwareNoError;
2110 def->Run(lastInputData, outOutputData, oscTime);
2111 lastInputData = 0;
2113 return kAudioHardwareNoError;
2118 void AudioSessionInterruptionCbk(void *inClientData, UInt32 inInterruptionState)
2123 bool SC_iCoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
2125 AudioSessionInitialize(0, 0, AudioSessionInterruptionCbk, 0);
2126 unsigned long category = kAudioSessionCategory_PlayAndRecord;
2127 #ifdef SC_IPHONE
2128 UInt32 micInput, micInputSize = sizeof(&micInput);
2129 AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &micInputSize, &micInput);
2130 if(!micInput) {
2131 category = kAudioSessionCategory_MediaPlayback;
2132 scprintf("SC_IPHONE: WARNING - no audio input available\n");
2134 #endif
2135 AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
2137 if (mPreferredHardwareBufferFrameSize)
2139 Float32 preferredBufferSize = (float) mPreferredHardwareBufferFrameSize/44100.f;
2140 AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
2143 AudioSessionSetActive(true);
2145 float actualBufferDuration;
2146 UInt32 size = sizeof(actualBufferDuration);
2147 AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &actualBufferDuration);
2149 *outNumSamplesPerCallback = (int) (actualBufferDuration*44100.f+0.5f);
2150 *outSampleRate = 44100;
2152 AudioComponentDescription desc;
2153 desc.componentType = kAudioUnitType_Output;
2154 desc.componentSubType = kAudioUnitSubType_RemoteIO;
2155 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
2157 NewAUGraph(&graph);
2158 AUNode node;
2159 AudioUnit unit;
2160 OSStatus ret = AUGraphAddNode(graph, &desc, &node);
2161 //printf("node : %d\n", node);
2162 AUGraphOpen(graph);
2164 ret = AUGraphNodeInfo(graph, node, &desc, &unit);
2165 //printf("%d\n", unit);
2169 AudioComponent remoteIOComp = AudioComponentFindNext(0, &desc);
2170 if (AudioComponentInstanceNew(remoteIOComp, &inputUnit)!=noErr)
2172 //printf("error instantiating RemoteIO\n");
2173 return false;
2175 //printf("instantiated : %d\n", inputUnit);
2177 int enableIO = 1;
2178 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
2179 if (ret!=noErr)
2181 //printf("can't set input : %d\n", ret);
2182 return false;
2184 enableIO = 0;
2185 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
2186 if (ret!=noErr)
2188 //printf("can't set output : %d\n", ret);
2189 return false;
2192 AudioUnitInitialize(inputUnit);
2194 unsigned long bufferSizeBytes = 1024 * sizeof(unsigned long);
2195 buflist = (AudioBufferList *) malloc(sizeof(AudioBufferList));
2196 buflist->mNumberBuffers = 1;
2197 buflist->mBuffers[0].mDataByteSize = bufferSizeBytes;
2198 buflist->mBuffers[0].mData = malloc(bufferSizeBytes);
2199 buflist->mBuffers[0].mNumberChannels = 1;
2201 floatInputList = (AudioBufferList *) malloc(sizeof(AudioBufferList));
2202 floatInputList->mNumberBuffers = 1;
2203 floatInputList->mBuffers[0].mDataByteSize = bufferSizeBytes;
2204 floatInputList->mBuffers[0].mData = malloc(bufferSizeBytes);
2205 floatInputList->mBuffers[0].mNumberChannels = 1;
2208 floatOutputList = (AudioBufferList *) malloc(sizeof(AudioBufferList)+sizeof(AudioBuffer));
2209 floatOutputList->mNumberBuffers = 2;
2210 floatOutputList->mBuffers[0].mDataByteSize = bufferSizeBytes;
2211 floatOutputList->mBuffers[0].mData = malloc(bufferSizeBytes);
2212 floatOutputList->mBuffers[0].mNumberChannels = 1;
2213 floatOutputList->mBuffers[1].mDataByteSize = bufferSizeBytes;
2214 floatOutputList->mBuffers[1].mData = malloc(bufferSizeBytes);
2215 floatOutputList->mBuffers[1].mNumberChannels = 1;
2218 AURenderCallbackStruct inputStruct;
2219 inputStruct.inputProc = InputCallback;
2220 inputStruct.inputProcRefCon = this;
2221 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &inputStruct, sizeof(inputStruct));
2223 AURenderCallbackStruct renderStruct;
2224 renderStruct.inputProc = RenderCallback;
2225 renderStruct.inputProcRefCon = this;
2226 ret = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderStruct, sizeof(renderStruct));
2228 AudioStreamBasicDescription streamFormat;
2229 streamFormat.mFormatID = kAudioFormatLinearPCM;
2230 streamFormat.mFormatFlags =
2231 kAudioFormatFlagIsSignedInteger
2232 | kAudioFormatFlagsNativeEndian
2233 | kLinearPCMFormatFlagIsNonInterleaved
2234 | (24 << kLinearPCMFormatFlagsSampleFractionShift);
2235 streamFormat.mSampleRate = 44100;
2236 streamFormat.mBitsPerChannel = 32;
2237 streamFormat.mChannelsPerFrame = 2;
2238 streamFormat.mFramesPerPacket = 1;
2239 streamFormat.mBytesPerFrame = ( streamFormat.mBitsPerChannel / 8 );
2240 streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame *
2241 streamFormat.mFramesPerPacket;
2243 ret = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(streamFormat));
2246 AudioStreamBasicDescription audioFormat;
2247 audioFormat.mSampleRate = 44100.00;
2248 audioFormat.mFormatID = kAudioFormatLinearPCM;
2249 audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
2250 audioFormat.mFramesPerPacket = 1;
2251 audioFormat.mChannelsPerFrame = 1;
2252 audioFormat.mBitsPerChannel = 16;
2253 audioFormat.mBytesPerPacket = 2;
2254 audioFormat.mBytesPerFrame = 2;
2255 ret = AudioUnitSetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &audioFormat, sizeof(audioFormat));
2259 AudioStreamBasicDescription d;
2260 size = sizeof(d);
2261 ret = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &d, &size);
2263 AudioStreamBasicDescription inputFormat;
2264 AudioStreamBasicDescription outputFormat;
2265 AudioStreamBasicDescription f32Format;
2267 size = sizeof(AudioStreamBasicDescription);
2268 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &inputFormat, &size);
2269 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &inputFormat, &size);
2270 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outputFormat, &size);
2271 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outputFormat, &size);
2273 outputFormat.mChannelsPerFrame = 1;
2275 f32Format.mSampleRate = inputFormat.mSampleRate;
2276 f32Format.mFormatID = inputFormat.mFormatID;
2277 f32Format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
2278 f32Format.mBytesPerPacket = 4;
2279 f32Format.mFramesPerPacket = 1;
2280 f32Format.mBytesPerFrame = 4;
2281 f32Format.mChannelsPerFrame = 1;
2282 f32Format.mBitsPerChannel = 32;
2283 f32Format.mReserved = 0;
2285 ret = AudioConverterNew(&inputFormat, &f32Format, &converter_in_to_F32);
2286 ret = AudioConverterNew(&f32Format, &outputFormat, &converter_F32_to_out);
2287 ret = AudioConverterNew(&inputFormat, &outputFormat, &converter_in_to_out);
2289 AUGraphInitialize(graph);
2291 if(mWorld->mVerbosity >= 0){
2292 scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld);
2294 return true;
2297 bool SC_iCoreAudioDriver::DriverStart()
2299 if(mWorld->mVerbosity >= 0){
2300 scprintf("->SC_CoreAudioDriver::DriverStart\n");
2305 OSStatus ret = AUGraphStart(graph);
2306 AudioOutputUnitStart(inputUnit);
2307 } catch (...) {
2308 scprintf("exception in SC_CoreAudioDriver::DriverStart\n");
2310 if(mWorld->mVerbosity >= 0){
2311 scprintf("<-SC_CoreAudioDriver::DriverStart\n");
2313 return true;
2316 bool SC_iCoreAudioDriver::DriverStop()
2318 if(mWorld->mVerbosity >= 0){
2319 scprintf("->SC_CoreAudioDriver::DriverStop\n");
2322 AUGraphStop(graph);
2323 AudioOutputUnitStop(inputUnit);
2325 if(mWorld->mVerbosity >= 0){
2326 scprintf("<-SC_CoreAudioDriver::DriverStop\n");
2328 return true;
2331 #endif // SC_AUDIO_API_COREAUDIOIPHONE
2336 // =====================================================================
2337 // Audio driver (PortAudio)
2339 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
2341 // =====================================================================
2342 // SC_PortAudioDriver (PortAudio)
2344 #define PRINT_PORTAUDIO_ERROR( function, errorcode )\
2345 scprintf( "SC_PortAudioDriver: PortAudio failed at %s with error: '%s'\n",\
2346 #function, Pa_GetErrorText( errorcode ) )
2348 SC_PortAudioDriver::SC_PortAudioDriver(struct World *inWorld)
2349 : SC_AudioDriver(inWorld)
2350 , mStream(0)
2352 PaError paerror = Pa_Initialize();
2353 if( paerror != paNoError )
2354 PRINT_PORTAUDIO_ERROR( Pa_Initialize, paerror );
2357 SC_PortAudioDriver::~SC_PortAudioDriver()
2359 if( mStream ){
2360 PaError paerror = Pa_CloseStream( mStream );
2361 if( paerror != paNoError )
2362 PRINT_PORTAUDIO_ERROR( Pa_CloseStream, paerror );
2364 Pa_Terminate();
2367 static int SC_PortAudioStreamCallback( const void *input, void *output,
2368 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
2369 PaStreamCallbackFlags statusFlags, void *userData )
2371 SC_PortAudioDriver *driver = (SC_PortAudioDriver*)userData;
2373 return driver->PortAudioCallback( input, output, frameCount, timeInfo, statusFlags );
2376 int SC_PortAudioDriver::PortAudioCallback( const void *input, void *output,
2377 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
2378 PaStreamCallbackFlags statusFlags )
2380 World *world = mWorld;
2381 (void) frameCount, timeInfo, statusFlags; // suppress unused parameter warnings
2383 try {
2384 // synchronise against the output buffer - timeInfo->currentTime is 0.0 bug in PA?
2385 if (mPaStreamStartupTime==0 && mPaStreamStartupTimeOSC==0) {
2386 mPaStreamStartupTimeOSC = GetCurrentOSCTime();
2387 mPaStreamStartupTime = timeInfo->outputBufferDacTime;
2389 mOSCbuftime = PaStreamTimeToOSC(timeInfo->outputBufferDacTime - mPaStreamStartupTime) + mPaStreamStartupTimeOSC;
2391 mFromEngine.Free();
2392 mToEngine.Perform();
2393 mOscPacketsToEngine.Perform();
2395 int numInputs = mInputChannelCount;
2396 int numOutputs = mOutputChannelCount;
2397 const float **inBuffers = (const float**)input;
2398 float **outBuffers = (float**)output;
2400 int numSamples = NumSamplesPerCallback();
2401 int bufFrames = mWorld->mBufLength;
2402 int numBufs = numSamples / bufFrames;
2404 float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
2405 float *outBuses = mWorld->mAudioBus;
2406 int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
2407 int32 *outTouched = mWorld->mAudioBusTouched;
2409 int minInputs = std::min<size_t>(numInputs, mWorld->mNumInputs);
2410 int minOutputs = std::min<size_t>(numOutputs, mWorld->mNumOutputs);
2412 int bufFramePos = 0;
2414 int64 oscTime = mOSCbuftime;
2415 int64 oscInc = mOSCincrement;
2416 double oscToSamples = mOSCtoSamples;
2418 // main loop
2419 for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames)
2421 int32 bufCounter = mWorld->mBufCounter;
2422 int32 *tch;
2424 // copy+touch inputs
2425 tch = inTouched;
2426 for (int k = 0; k < minInputs; ++k)
2428 const float *src = inBuffers[k] + bufFramePos;
2429 float *dst = inBuses + k * bufFrames;
2430 for (int n = 0; n < bufFrames; ++n) *dst++ = *src++;
2431 *tch++ = bufCounter;
2434 // run engine
2435 int64 schedTime;
2436 int64 nextTime = oscTime + oscInc;
2437 // DEBUG
2439 if (mScheduler.Ready(nextTime)) {
2440 double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs;
2441 scprintf("rdy %.6f %.6f %.6f %.6f \n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff, (nextTime-gStartupOSCTime)*kOSCtoSecs);
2444 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
2445 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
2446 float diffTimeFloor = floor(diffTime);
2447 world->mSampleOffset = (int)diffTimeFloor;
2448 world->mSubsampleOffset = diffTime - diffTimeFloor;
2450 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
2451 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
2453 SC_ScheduledEvent event = mScheduler.Remove();
2454 event.Perform();
2456 world->mSampleOffset = 0;
2457 world->mSubsampleOffset = 0.f;
2459 World_Run(world);
2461 // copy touched outputs
2462 tch = outTouched;
2463 for (int k = 0; k < minOutputs; ++k) {
2464 float *dst = outBuffers[k] + bufFramePos;
2465 if (*tch++ == bufCounter) {
2466 float *src = outBuses + k * bufFrames;
2467 for (int n = 0; n < bufFrames; ++n) *dst++ = *src++;
2468 } else {
2469 for (int n = 0; n < bufFrames; ++n) *dst++ = 0.0f;
2473 // update buffer time
2474 oscTime = mOSCbuftime = nextTime;
2476 } catch (std::exception& exc) {
2477 scprintf("SC_PortAudioDriver: exception in real time: %s\n", exc.what());
2478 } catch (...) {
2479 scprintf("SC_PortAudioDriver: unknown exception in real time\n");
2482 double cpuUsage = (double)Pa_GetStreamCpuLoad(mStream);
2483 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2484 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2486 mPeakCPU = cpuUsage;
2487 mPeakCounter = mMaxPeakCounter;
2490 mAudioSync.Signal();
2492 return paContinue;
2495 void SC_PortAudioDriver::GetPaDeviceFromName(const char* device, int* mInOut) {
2497 const PaDeviceInfo *pdi;
2498 const PaHostApiInfo *apiInfo;
2499 char devString[256];
2500 PaDeviceIndex numDevices = Pa_GetDeviceCount();
2501 mInOut[0] = paNoDevice;
2502 mInOut[1] = paNoDevice;
2504 // This tries to find one or two devices that match the given name (substring)
2505 // might cause problems for some names...
2506 for( int i=0; i<numDevices; i++ ) {
2507 pdi = Pa_GetDeviceInfo( i );
2508 apiInfo = Pa_GetHostApiInfo(pdi->hostApi);
2509 strcpy(devString, apiInfo->name);
2510 strcat(devString, " : ");
2511 strcat(devString, pdi->name);
2512 if (strstr(devString, device)) {
2513 if (pdi->maxInputChannels > 0) mInOut[0] = i;
2514 if (pdi->maxOutputChannels > 0) mInOut[1] = i;
2519 // ====================================================================
2522 bool SC_PortAudioDriver::DriverSetup(int* outNumSamples, double* outSampleRate)
2524 int mDeviceInOut[2];
2525 PaError paerror;
2526 const PaDeviceInfo *pdi;
2527 const PaHostApiInfo *apiInfo;
2528 const PaStreamInfo *psi;
2529 PaTime suggestedLatencyIn, suggestedLatencyOut;
2530 PaDeviceIndex numDevices = Pa_GetDeviceCount();
2532 // print out all options:
2533 fprintf(stdout, "\nDevice options:\n");
2534 for( int i=0; i<numDevices; i++ ) {
2535 pdi = Pa_GetDeviceInfo( i );
2536 apiInfo = Pa_GetHostApiInfo(pdi->hostApi);
2537 fprintf(stdout, " - %s : %s (device #%d with %d ins %d outs)\n",apiInfo->name,pdi->name, i, pdi->maxInputChannels, pdi->maxOutputChannels);
2540 mDeviceInOut[0] = paNoDevice;
2541 mDeviceInOut[1] = paNoDevice;
2542 if (mWorld->hw->mInDeviceName)
2543 GetPaDeviceFromName(mWorld->hw->mInDeviceName, mDeviceInOut);
2544 if (mDeviceInOut[0] == paNoDevice) mDeviceInOut[0] = Pa_GetDefaultInputDevice();
2545 if (mDeviceInOut[1] == paNoDevice) mDeviceInOut[1] = Pa_GetDefaultOutputDevice();
2547 *outNumSamples = mWorld->mBufLength;
2548 if (mPreferredSampleRate)
2549 *outSampleRate = mPreferredSampleRate;
2550 else
2551 *outSampleRate = 44100.;
2554 if (mDeviceInOut[0]!=paNoDevice && mDeviceInOut[1]!=paNoDevice) {
2556 if (mPreferredHardwareBufferFrameSize)
2557 // controls the suggested latency by hardwareBufferSize switch -Z
2558 suggestedLatencyIn = suggestedLatencyOut = mPreferredHardwareBufferFrameSize / (*outSampleRate);
2559 else {
2560 suggestedLatencyIn = Pa_GetDeviceInfo( mDeviceInOut[0] )->defaultLowInputLatency;
2561 suggestedLatencyOut = Pa_GetDeviceInfo( mDeviceInOut[1] )->defaultLowOutputLatency;
2564 PaSampleFormat fmt = paFloat32 | paNonInterleaved;
2565 mInputChannelCount = Pa_GetDeviceInfo( mDeviceInOut[0] )->maxInputChannels;
2566 mOutputChannelCount = Pa_GetDeviceInfo( mDeviceInOut[1] )->maxOutputChannels;
2567 fprintf(stdout, "\nBooting with:\n In: %s : %s \n",
2568 Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[0] )->hostApi)->name,
2569 Pa_GetDeviceInfo( mDeviceInOut[0] )->name);
2570 fprintf(stdout, " Out: %s : %s \n",
2571 Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[1] )->hostApi)->name,
2572 Pa_GetDeviceInfo( mDeviceInOut[1] )->name);
2574 PaStreamParameters inStreamParams;
2575 inStreamParams.device = mDeviceInOut[0];
2576 inStreamParams.channelCount = mInputChannelCount;
2577 inStreamParams.sampleFormat = fmt;
2578 inStreamParams.suggestedLatency = suggestedLatencyIn;
2579 inStreamParams.hostApiSpecificStreamInfo = NULL;
2581 PaStreamParameters outStreamParams;
2582 outStreamParams.device = mDeviceInOut[1];
2583 outStreamParams.channelCount = mOutputChannelCount;
2584 outStreamParams.sampleFormat = fmt;
2585 outStreamParams.suggestedLatency = suggestedLatencyOut;
2586 outStreamParams.hostApiSpecificStreamInfo = NULL;
2588 paerror = Pa_OpenStream(&mStream, &inStreamParams, &outStreamParams, *outSampleRate, *outNumSamples, paNoFlag, SC_PortAudioStreamCallback, this );
2589 if( paerror != paNoError )
2590 PRINT_PORTAUDIO_ERROR( Pa_OpenStream, paerror );
2591 else {
2592 psi = Pa_GetStreamInfo(mStream);
2593 if (!psi)
2594 fprintf(stdout," Could not obtain further info from portaudio stream\n");
2595 else {
2596 fprintf(stdout," Sample rate: %.3f\n", psi->sampleRate);
2597 fprintf(stdout," Latency (in/out): %.3f / %.3f sec\n", psi->inputLatency, psi->outputLatency);
2600 return paerror == paNoError;
2603 // should not be necessary, but a last try with OpenDefaultStream...
2604 paerror = Pa_OpenDefaultStream( &mStream, 2, 2,
2605 paFloat32 | paNonInterleaved, *outSampleRate, *outNumSamples, SC_PortAudioStreamCallback, this );
2606 if( paerror != paNoError )
2607 PRINT_PORTAUDIO_ERROR( Pa_OpenDefaultStream, paerror );
2608 return paerror == paNoError;
2611 bool SC_PortAudioDriver::DriverStart()
2613 if (!mStream)
2614 return false;
2616 PaError paerror = Pa_StartStream( mStream );
2617 if( paerror != paNoError )
2618 PRINT_PORTAUDIO_ERROR( Pa_StartStream, paerror );
2620 // sync times
2621 mPaStreamStartupTimeOSC = 0;
2622 mPaStreamStartupTime = 0;
2623 // it would be better to do the sync here, but the timeInfo in the callback is incomplete
2624 //mPaStreamStartupTimeOSC = GetCurrentOSCTime();
2625 //mPaStreamStartupTime = Pa_GetStreamTime(mStream);
2627 return paerror == paNoError;
2630 bool SC_PortAudioDriver::DriverStop()
2632 if (!mStream)
2633 return false;
2635 PaError paerror = Pa_StopStream(mStream);
2636 if( paerror != paNoError )
2637 PRINT_PORTAUDIO_ERROR( Pa_StopStream, paerror );
2639 return paerror == paNoError;
2642 #endif // SC_AUDIO_API_PORTAUDIO