bumping version to 3.5-rc1
[supercollider.git] / server / scsynth / SC_CoreAudio.cpp
blob383a94a1088e6b8d504c0a4a7c7dd38942e30d22
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 #ifndef SC_INNERSC
50 int64 gStartupOSCTime = -1;
51 #endif //ifndef SC_INNERSC
53 void sc_SetDenormalFlags();
55 void set_real_time_priority(pthread_t thread);
57 double gSampleRate, gSampleDur;
59 // =====================================================================
60 // Timing (CoreAudio)
62 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
64 int64 gOSCoffset = 0;
66 int32 server_timeseed()
68 static int32 count = 0;
69 int64 time = AudioGetCurrentHostTime();
70 return (int32)(time >> 32) ^ (int32)time ^ count--;
73 inline int64 CoreAudioHostTimeToOSC(int64 hostTime)
75 return (int64)((double)AudioConvertHostTimeToNanos(hostTime) * kNanosToOSCunits) + gOSCoffset;
78 int64 oscTimeNow()
80 return CoreAudioHostTimeToOSC(AudioGetCurrentHostTime());
83 void syncOSCOffsetWithTimeOfDay();
84 void syncOSCOffsetWithTimeOfDay()
86 // generate a value gOSCoffset such that
87 // (gOSCOffset + systemTimeInOSCunits)
88 // is equal to gettimeofday time in OSCunits.
89 // Then if this machine is synced via NTP, we are synced with the world.
90 // more accurate way to do this??
92 struct timeval tv;
94 int64 systemTimeBefore, systemTimeAfter, diff;
95 int64 minDiff = 0x7fffFFFFffffFFFFLL;
97 // take best of several tries
98 const int numberOfTries = 5;
99 int64 newOffset = gOSCoffset;
100 for (int i=0; i<numberOfTries; ++i) {
101 systemTimeBefore = AudioGetCurrentHostTime();
102 gettimeofday(&tv, 0);
103 systemTimeAfter = AudioGetCurrentHostTime();
105 diff = systemTimeAfter - systemTimeBefore;
106 if (diff < minDiff) {
107 minDiff = diff;
108 // assume that gettimeofday happens halfway between AudioGetCurrentHostTime calls
109 int64 systemTimeBetween = systemTimeBefore + diff/2;
110 int64 systemTimeInOSCunits = (int64)((double)AudioConvertHostTimeToNanos(systemTimeBetween) * kNanosToOSCunits);
111 int64 timeOfDayInOSCunits = ((int64)(tv.tv_sec + kSECONDS_FROM_1900_to_1970) << 32)
112 + (int64)(tv.tv_usec * kMicrosToOSCunits);
113 newOffset = timeOfDayInOSCunits - systemTimeInOSCunits;
117 gOSCoffset = newOffset;
118 //scprintf("gOSCoffset %016llX\n", gOSCoffset);
121 void* resyncThreadFunc(void* arg);
122 void* resyncThreadFunc(void* /*arg*/)
124 while (true) {
125 sleep(20);
126 syncOSCOffsetWithTimeOfDay();
128 return 0;
131 void initializeScheduler()
133 syncOSCOffsetWithTimeOfDay();
135 pthread_t resyncThread;
136 pthread_create (&resyncThread, NULL, resyncThreadFunc, (void*)0);
137 set_real_time_priority(resyncThread);
139 #endif // SC_AUDIO_API_COREAUDIO
142 // =====================================================================
143 // Timing (CoreAudioIPHONE)
145 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
147 int64 gOSCoffset = 0;
149 static inline int64 GetMicroseconds()
151 struct timeval tv;
152 gettimeofday(&tv, 0);
153 return (int64) tv.tv_sec * 1000000 + tv.tv_usec;
156 static inline int64 GetCurrentOSCTime()
158 struct timeval tv;
159 uint64 s, f;
160 gettimeofday(&tv, 0);
161 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
162 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
164 return (s << 32) + f;
167 int32 server_timeseed()
169 int64 time = GetCurrentOSCTime();
170 return Hash((int32)(time >> 32) + Hash((int32)time));
173 int64 oscTimeNow()
175 return GetCurrentOSCTime();
178 void initializeScheduler()
180 gOSCoffset = GetCurrentOSCTime();
182 #endif // SC_AUDIO_API_COREAUDIO
187 // =====================================================================
188 // Timing (PortAudio)
190 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
192 int64 gOSCoffset = 0;
194 static inline int64 GetCurrentOSCTime()
196 struct timeval tv;
197 uint64 s, f;
198 gettimeofday(&tv, 0);
199 s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970;
200 f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits);
202 return (s << 32) + f;
205 int32 server_timeseed()
207 int64 time = GetCurrentOSCTime();
208 return Hash((int32)(time >> 32) + Hash((int32)time));
211 int64 oscTimeNow()
213 return GetCurrentOSCTime();
216 int64 PaStreamTimeToOSC(PaTime pa_time) {
217 uint64 s, f;
218 s = (uint64)pa_time;
219 f = (uint64)((pa_time - s) * 1000000 * kMicrosToOSCunits);
221 return (s << 32) + f;
224 void initializeScheduler()
226 gOSCoffset = GetCurrentOSCTime();
228 #endif // SC_AUDIO_API_PORTAUDIO
231 // =====================================================================
232 // Packets (Common)
234 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket);
235 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket);
236 int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply);
237 PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc);
239 void Perform_ToEngine_Msg(FifoMsg *inMsg);
240 void FreeOSCPacket(FifoMsg *inMsg);
242 struct IsBundle
244 IsBundle() { str4cpy(s, "#bundle"); }
245 bool checkIsBundle(int32 *in) { return in[0] == s[0] && in[1] == s[1]; }
246 int32 s[2];
248 IsBundle gIsBundle;
250 bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket)
252 //scprintf("ProcessOSCPacket %d, '%s'\n", inPacket->mSize, inPacket->mData);
253 if (!inPacket) return false;
254 bool result;
255 inWorld->mDriverLock->Lock();
256 SC_AudioDriver *driver = AudioDriver(inWorld);
257 if (!driver) {
258 inWorld->mDriverLock->Unlock();
259 return false;
261 inPacket->mIsBundle = gIsBundle.checkIsBundle((int32*)inPacket->mData);
262 FifoMsg fifoMsg;
263 fifoMsg.Set(inWorld, Perform_ToEngine_Msg, FreeOSCPacket, (void*)inPacket);
264 result = driver->SendOscPacketMsgToEngine(fifoMsg);
265 inWorld->mDriverLock->Unlock();
266 return result;
269 int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply)
271 // scprintf("->PerformOSCMessage %d\n", inData[0]);
272 SC_LibCmd *cmdObj;
273 int cmdNameLen;
274 if (inData[0] == 0) {
275 cmdNameLen = 4;
276 uint32 index = inData[3];
277 if (index >= NUMBER_OF_COMMANDS) cmdObj = 0;
278 else cmdObj = gCmdArray[index];
279 } else {
280 cmdNameLen = OSCstrlen(inData);
281 cmdObj = gCmdLib->Get((int32*)inData);
283 if (!cmdObj) {
284 CallSendFailureCommand(inWorld, inData, "Command not found", inReply);
285 scprintf("FAILURE %s Command not found\n", inData);
286 return kSCErr_NoSuchCommand;
289 int err = cmdObj->Perform(inWorld, inSize - cmdNameLen, inData + cmdNameLen, inReply);
290 //scprintf("<-PerformOSCMessage %d\n", inData[0]);
291 return err;
294 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket)
296 //scprintf("->PerformOSCBundle %d\n", inPacket->mSize);
297 char *data = inPacket->mData + 16;
298 char* dataEnd = inPacket->mData + inPacket->mSize;
300 while (data < dataEnd) {
301 int32 msgSize = ntohl(*(int32*)data);
302 data += sizeof(int32);
303 //scprintf("msgSize %d\n", msgSize);
304 PerformOSCMessage(inWorld, msgSize, data, &inPacket->mReplyAddr);
305 data += msgSize;
308 // reset so next command uses permanent error notification status
309 inWorld->mLocalErrorNotification = 0;
311 // // 0 is a temporary change, so reset the local error flag
312 // if(!inWorld->mLocalErrorNotification) {
313 // inWorld->mLocalErrorNotification = inWorld->mErrorNotification;
314 // };
316 //scprintf("<-PerformOSCBundle %d\n", inPacket->mSize);
319 PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc freeFunc)
321 SC_AudioDriver *driver = world->hw->mAudioDriver;
323 if (!packet->mIsBundle) {
324 PerformOSCMessage(world, packet->mSize, packet->mData, &packet->mReplyAddr);
325 world->mLocalErrorNotification = 0;
326 // if(!world->mLocalErrorNotification) {
327 // world->mLocalErrorNotification = world->mErrorNotification;
328 // };
329 return PacketPerformed;
330 } else {
331 // in real time engine, schedule the packet
332 int64 time = OSCtime(packet->mData + 8);
333 if (time == 0 || time == 1) {
334 PerformOSCBundle(world, packet);
335 return PacketPerformed;
336 } else {
337 if ((time < driver->mOSCbuftime) && (world->mVerbosity >= 0)) {
338 double seconds = (driver->mOSCbuftime - time)*kOSCtoSecs;
339 scprintf("late %.9f\n", seconds);
340 //FifoMsg outMsg;
342 //ReportLateness(packet->mReply, seconds)
344 // DEBUG
345 // else
346 //scprintf("scheduled in %.6f at time %.6f\n",
347 // (time-driver->mOSCbuftime)*kOSCtoSecs,
348 // (time-gStartupOSCTime)*kOSCtoSecs);
350 SC_ScheduledEvent event(world, time, packet, freeFunc);
351 driver->AddEvent(event);
352 return PacketScheduled;
357 ////////////////////////////////////////////////////////////////////////////
359 void Perform_ToEngine_Msg(FifoMsg *inMsg)
361 World *world = inMsg->mWorld;
362 OSC_Packet *packet = (OSC_Packet*)inMsg->mData;
363 if (!packet) return;
365 PacketStatus status = PerformOSCPacket(world, packet, SC_ScheduledEvent::FreeInNRT);
366 if (status == PacketScheduled) {
367 // Transfer ownership
368 inMsg->mData = 0;
369 inMsg->mFreeFunc = 0;
373 PacketStatus PerformCompletionMsg(World *inWorld, const OSC_Packet& inPacket)
375 OSC_Packet* packet = (OSC_Packet*)World_Alloc(inWorld, sizeof(OSC_Packet));
376 *packet = inPacket;
377 packet->mIsBundle = gIsBundle.checkIsBundle((int32*)packet->mData);
378 PacketStatus status = PerformOSCPacket(inWorld, packet, SC_ScheduledEvent::FreeInRT);
379 if (status == PacketPerformed) {
380 World_Free(inWorld, packet);
382 return status;
385 void FreeOSCPacket(FifoMsg *inMsg)
387 OSC_Packet *packet = (OSC_Packet*)inMsg->mData;
388 if (packet) {
389 inMsg->mData = 0;
390 #ifdef _WIN32
391 #pragma message("$$$todo fixme hack for the 'uninitialized packet->mData ptr when using MSVC 7.1 debug")
392 if (packet->mData != reinterpret_cast<char*>(0xcdcdcdcd))
393 free(packet->mData);
394 #else //#ifdef _WIN32
395 free(packet->mData);
396 #endif //#ifdef _WIN32
397 free(packet);
401 void Free_FromEngine_Msg(FifoMsg *inMsg);
402 void Free_FromEngine_Msg(FifoMsg *inMsg)
404 World_Free(inMsg->mWorld, inMsg->mData);
407 // =====================================================================
408 // Audio driver (Common)
410 SC_AudioDriver::SC_AudioDriver(struct World *inWorld)
411 : mWorld(inWorld)
412 , mSampleTime(0)
413 , mNumSamplesPerCallback(0)
418 SC_AudioDriver::~SC_AudioDriver()
420 mRunThreadFlag = false;
421 mAudioSync.Signal();
422 pthread_join(mThread, 0);
425 void* audio_driver_thread_func(void* arg);
426 void* audio_driver_thread_func(void* arg)
428 SC_AudioDriver *ca = (SC_AudioDriver*)arg;
429 void* result = ca->RunThread();
430 return result;
433 void* SC_AudioDriver::RunThread()
435 TriggersFifo *trigfifo = &mWorld->hw->mTriggers;
436 NodeReplyFifo *nodereplyfifo = &mWorld->hw->mNodeMsgs;
437 NodeEndsFifo *nodeendfifo = &mWorld->hw->mNodeEnds;
438 DeleteGraphDefsFifo *deletegraphfifo = &mWorld->hw->mDeleteGraphDefs;
440 while (mRunThreadFlag) {
441 // wait for sync
442 mAudioSync.WaitNext();
444 mWorld->mNRTLock->Lock();
446 // send /tr messages
447 trigfifo->Perform();
449 // send node reply messages
450 nodereplyfifo->Perform();
452 // send node status messages
453 nodeendfifo->Perform();
455 // free GraphDefs
456 deletegraphfifo->Perform();
458 // perform messages
459 mFromEngine.Perform();
461 mWorld->mNRTLock->Unlock();
463 return 0;
466 bool SC_AudioDriver::SendMsgFromEngine(FifoMsg& inMsg)
468 return mFromEngine.Write(inMsg);
472 bool SC_AudioDriver::SendMsgToEngine(FifoMsg& inMsg)
474 mToEngine.Free();
475 return mToEngine.Write(inMsg);
478 bool SC_AudioDriver::SendOscPacketMsgToEngine(FifoMsg& inMsg)
480 mOscPacketsToEngine.Free();
481 return mOscPacketsToEngine.Write(inMsg);
484 void SC_ScheduledEvent::FreeInRT(struct World* world, OSC_Packet* packet)
486 World_Free(world, packet->mData);
487 World_Free(world, packet);
490 void SC_ScheduledEvent::FreeInNRT(struct World* world, OSC_Packet* packet)
492 FifoMsg msg;
493 msg.Set(world, FreeOSCPacket, 0, (void*)packet);
494 world->hw->mAudioDriver->SendMsgFromEngine(msg);
497 void SC_ScheduledEvent::Perform()
499 PerformOSCBundle(mWorld, mPacket);
500 (*mPacketFreeFunc)(mWorld, mPacket);
503 bool SC_AudioDriver::Setup()
505 mRunThreadFlag = true;
506 pthread_create (&mThread, NULL, audio_driver_thread_func, (void*)this);
507 set_real_time_priority(mThread);
509 int numSamples;
510 double sampleRate;
512 if (!DriverSetup(&numSamples, &sampleRate)) return false;
514 mNumSamplesPerCallback = numSamples;
515 //scprintf("mNumSamplesPerCallback %d\n", mNumSamplesPerCallback);
516 //scprintf("mHardwareBufferSize %lu\n", mHardwareBufferSize);
518 // compute a per sample increment to the OpenSoundControl Time
519 mOSCincrementNumerator = (double)mWorld->mBufLength * pow(2.,32.);
520 mOSCincrement = (int64)(mOSCincrementNumerator / sampleRate);
521 mOSCtoSamples = sampleRate / pow(2.,32.);
523 World_SetSampleRate(mWorld, sampleRate);
524 mSampleRate = mSmoothSampleRate = sampleRate;
525 mBuffersPerSecond = sampleRate / mNumSamplesPerCallback;
526 mMaxPeakCounter = (int)mBuffersPerSecond;
528 if(mWorld->mVerbosity >= 0){
529 scprintf("SC_AudioDriver: sample rate = %f, driver's block size = %d\n", sampleRate, mNumSamplesPerCallback);
532 return true;
535 bool SC_AudioDriver::Start()
537 mAvgCPU = 0.;
538 mPeakCPU = 0.;
539 mPeakCounter = 0;
541 mStartHostSecs = 0.;
542 mPrevHostSecs = 0.;
543 mStartSampleTime = 0.;
544 mPrevSampleTime = 0.;
546 World_Start(mWorld);
547 #ifndef SC_INNERSC
548 gStartupOSCTime = oscTimeNow();
549 #endif //SC_INNERSC
551 return DriverStart();
554 bool SC_AudioDriver::Stop()
556 if (!DriverStop()) return false;
557 return true;
561 // =====================================================================
562 // Audio driver (CoreAudio)
563 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO
565 SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld)
567 return new SC_CoreAudioDriver(inWorld);
570 #endif
572 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
574 SC_CoreAudioDriver::SC_CoreAudioDriver(struct World *inWorld)
575 : SC_AudioDriver(inWorld)
576 , mInputBufList(0)
580 SC_CoreAudioDriver::~SC_CoreAudioDriver()
582 if (mInputBufList)
584 int i;
585 for (i=0; i<mInputBufList->mNumberBuffers; i++)
587 free(mInputBufList->mBuffers[i].mData);
589 free(mInputBufList);
593 bool SC_CoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
595 OSStatus err = kAudioHardwareNoError;
596 UInt32 count;
597 mOutputDevice = kAudioDeviceUnknown;
598 mInputDevice = kAudioDeviceUnknown;
600 //scprintf("SC_CoreAudioDriver::Setup world %p\n", mWorld);
602 ////////////////////////////////////////////////////////////////////////////////////////////////
604 do {
605 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0);
607 AudioDeviceID *devices = (AudioDeviceID*)malloc(count);
608 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
609 if (err != kAudioHardwareNoError) {
610 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
611 free(devices);
612 break;
615 int numdevices = count / sizeof(AudioDeviceID);
616 if(mWorld->mVerbosity >= 0){
617 scprintf("Number of Devices: %d\n", numdevices);
619 for (int i = 0; i < numdevices; ++i) {
620 err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
621 if (err != kAudioHardwareNoError) {
622 scprintf("info kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]);
623 break;
626 char *name = (char*)malloc(count);
627 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
628 if (err != kAudioHardwareNoError) {
629 scprintf("get kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]);
630 free(name);
631 break;
633 if(mWorld->mVerbosity >= 0){
634 scprintf(" %d : \"%s\"\n", i, name);
636 free(name);
638 free(devices);
639 if(mWorld->mVerbosity >= 0){
640 scprintf("\n");
642 } while (false);
644 if (mWorld->hw->mInDeviceName || mWorld->hw->mOutDeviceName) {
645 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0);
646 if (err != kAudioHardwareNoError) {
647 scprintf("info kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
648 return false;
651 AudioDeviceID *devices = (AudioDeviceID*)malloc(count);
652 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices);
653 if (err != kAudioHardwareNoError) {
654 scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err);
655 return false;
658 int numdevices = count / sizeof(AudioDeviceID);
659 for (int i = 0; i < numdevices; ++i) {
660 err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0);
661 if (err != kAudioHardwareNoError) {
662 scprintf("info kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]);
663 break;
666 char *name = (char*)malloc(count);
667 err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name);
668 if (err != kAudioHardwareNoError) {
669 scprintf("get kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]);
670 return false;
672 if (strcmp(name, mWorld->hw->mInDeviceName) == 0) {
673 mInputDevice = devices[i];
675 if (strcmp(name, mWorld->hw->mOutDeviceName) == 0) {
676 mOutputDevice = devices[i];
678 free(name);
679 if (mInputDevice!=kAudioDeviceUnknown && mOutputDevice!=kAudioDeviceUnknown) break;
681 free(devices);
682 if (mOutputDevice==kAudioDeviceUnknown || mInputDevice==kAudioDeviceUnknown) goto getDefault;
683 } else {
684 getDefault:
686 // get the default output device for the HAL
687 if (mOutputDevice==kAudioDeviceUnknown)
689 count = sizeof(mOutputDevice);
690 //get the output device:
691 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) & mOutputDevice);
692 if (err != kAudioHardwareNoError) {
693 scprintf("get kAudioHardwarePropertyDefaultOutputDevice error %4.4s\n", (char*)&err);
694 return false;
698 //get the input device
699 if (mInputDevice==kAudioDeviceUnknown)
701 count = sizeof(mInputDevice);
702 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &count, (void *) & mInputDevice);
703 //get the input device:
704 if (err != kAudioHardwareNoError) {
705 scprintf("get kAudioHardwarePropertyDefaultInputDevice error %4.4s\n", (char*)&err);
706 return false;
711 ////////////////////////////////////////////////////////////////////////////////////////////////
713 AudioTimeStamp now;
714 now.mFlags = kAudioTimeStampHostTimeValid;
715 now.mHostTime = AudioGetCurrentHostTime();
717 if (mPreferredHardwareBufferFrameSize)
720 count = sizeof(UInt32);
721 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize);
722 if (err != kAudioHardwareNoError) {
723 scprintf("set kAudioDevicePropertyBufferFrameSize error %4.4s\n", (char*)&err);
724 //return false;
726 if (UseSeparateIO())
728 count = sizeof(UInt32);
729 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize);
730 if (err != kAudioHardwareNoError) {
731 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
732 //return false;
737 if (mPreferredSampleRate)
739 Float64 sampleRate = mPreferredSampleRate;
740 count = sizeof(Float64);
741 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
742 if (err != kAudioHardwareNoError) {
743 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
744 //return false;
746 if (UseSeparateIO())
748 count = sizeof(Float64);
749 err = AudioDeviceSetProperty(mInputDevice, &now, 0, false, kAudioDevicePropertyNominalSampleRate, count, &sampleRate);
750 if (err != kAudioHardwareNoError) {
751 scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err);
752 //return false;
757 // get the buffersize for the out device
758 count = sizeof(mHardwareBufferSize);
759 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyBufferSize, &count, &mHardwareBufferSize);
760 if (err != kAudioHardwareNoError) {
761 scprintf("get kAudioDevicePropertyBufferSize error %4.4s\n", (char*)&err);
762 return false;
764 //scprintf("mHardwareBufferSize = %ld\n", mHardwareBufferSize);
766 // get a description of the data format used by the output device
767 count = sizeof(AudioStreamBasicDescription);
768 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDesc);
769 if (err != kAudioHardwareNoError) {
770 scprintf("get kAudioDevicePropertyStreamFormat error %4.4s\n", (char*)&err);
771 return false;
774 if (mInputDevice != kAudioDeviceUnknown) {
775 // get a description of the data format used by the input device
776 count = sizeof(AudioStreamBasicDescription);
777 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamFormat, &count, &inputStreamDesc);
778 if (err != kAudioHardwareNoError) {
779 scprintf("get kAudioDevicePropertyStreamFormat error %4.4s\n", (char*)&err);
780 return false;
783 if (inputStreamDesc.mSampleRate != outputStreamDesc.mSampleRate) {
784 scprintf("input and output sample rates do not match. %g != %g\n", inputStreamDesc.mSampleRate, outputStreamDesc.mSampleRate);
785 return false;
789 ////////////////////////////////////////////////////////////////////////////////////////////////
791 do {
792 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
793 if (err != kAudioHardwareNoError) {
794 scprintf("info kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice);
795 break;
798 char *name = (char*)malloc(count);
799 err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name);
800 if (err != kAudioHardwareNoError) {
801 scprintf("get kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice);
802 free(name);
803 break;
806 if(mWorld->mVerbosity >= 0){
807 scprintf("\"%s\" Input Device\n", name);
809 free(name);
811 Boolean writeable;
812 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration,
813 &count, &writeable);
814 if (err != kAudioHardwareNoError) {
815 scprintf("info kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
816 break;
819 AudioBufferList *bufList = (AudioBufferList*)malloc(count);
820 err = AudioDeviceGetProperty(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration,
821 &count, bufList);
822 if (err != kAudioHardwareNoError) {
823 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
824 free(bufList);
825 break;
828 if(mWorld->mVerbosity >= 0){
829 scprintf(" Streams: %d\n", bufList->mNumberBuffers);
830 for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) {
831 scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels);
835 free(bufList);
836 } while (false);
837 if(mWorld->mVerbosity >= 0){
838 scprintf("\n");
841 ////////////////////////////////////////////////////////////////////////////////////////////////
843 do {
844 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
846 char *name = (char*)malloc(count);
847 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name);
848 if (err != kAudioHardwareNoError) {
849 scprintf("get kAudioDevicePropertyDeviceName error %4.4s\n", (char*)&err);
850 free(name);
851 break;
854 if(mWorld->mVerbosity >= 0){
855 scprintf("\"%s\" Output Device\n", name);
857 free(name);
859 Boolean writeable;
860 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration,
861 &count, &writeable);
862 if (err != kAudioHardwareNoError) {
863 scprintf("info kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
864 break;
867 AudioBufferList *bufList = (AudioBufferList*)malloc(count);
868 err = AudioDeviceGetProperty(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration,
869 &count, bufList);
870 if (err != kAudioHardwareNoError) {
871 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
872 free(bufList);
873 break;
876 if(mWorld->mVerbosity >= 0){
877 scprintf(" Streams: %d\n", bufList->mNumberBuffers);
878 for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) {
879 scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels);
882 free(bufList);
883 } while (false);
884 if(mWorld->mVerbosity >= 0){
885 scprintf("\n");
888 ////////////////////////////////////////////////////////////////////////////////////////////////
891 if (UseSeparateIO()) {
892 count = sizeof(UInt32);
893 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertySafetyOffset, &count, &mSafetyOffset);
894 if (err != kAudioHardwareNoError) {
895 scprintf("get kAudioDevicePropertySafetyOffset error %4.4s\n", (char*)&err);
896 return false;
898 if(mWorld->mVerbosity >= 1){
899 scprintf("mSafetyOffset %lu\n", mSafetyOffset);
902 Boolean writeable;
903 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, &writeable);
904 mInputBufList = (AudioBufferList*)malloc(count);
905 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, mInputBufList);
906 if (err != kAudioHardwareNoError) {
907 scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err);
908 return false;
911 if(mWorld->mVerbosity >= 1){
912 scprintf("mNumberBuffers %lu\n", mInputBufList->mNumberBuffers);
914 for (uint32 i=0; i<mInputBufList->mNumberBuffers; ++i) {
915 if(mWorld->mVerbosity >= 1){
916 scprintf(" mDataByteSize %d %lu\n", i, mInputBufList->mBuffers[i].mDataByteSize);
918 mInputBufList->mBuffers[i].mData = zalloc(1, mInputBufList->mBuffers[i].mDataByteSize);
922 AudioTimeStamp now;
923 now.mFlags = kAudioTimeStampHostTimeValid;
924 now.mHostTime = AudioGetCurrentHostTime();
927 err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyRegisterBufferList, count, mInputBufList);
928 if (err != kAudioHardwareNoError) {
929 scprintf("get kAudioDevicePropertyRegisterBufferList error %4.4s\n", (char*)&err);
930 return false;
935 *outNumSamplesPerCallback = mHardwareBufferSize / outputStreamDesc.mBytesPerFrame;
936 *outSampleRate = outputStreamDesc.mSampleRate;
938 if(mWorld->mVerbosity >= 1){
939 scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld);
944 //check if using built-in output, and thus whether there could be headphone plug/un-plug issues
945 //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
947 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0);
948 if (err != kAudioHardwareNoError) {
949 scprintf("info kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice);
950 return false;
953 char *outputname = (char*)malloc(count);
954 const char *testname = "Built-in Output";
955 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, outputname);
956 if (err != kAudioHardwareNoError) {
957 scprintf("get kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice);
958 return false;
960 builtinoutputflag_ = 0;
962 if (strcmp(testname, outputname) == 0) {
963 builtinoutputflag_ = 1;
965 // else {
967 // //check for an Aggregate Devices with a subdevice which is Built-in Output
968 // //http://lists.apple.com/archives/coreaudio-api/2009/Oct/msg00182.html
971 // }
973 free(outputname);
976 return true;
980 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
981 const AudioBufferList* inInputData,
982 const AudioTimeStamp* inInputTime,
983 AudioBufferList* outOutputData,
984 const AudioTimeStamp* inOutputTime,
985 void* defptr);
986 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
987 const AudioBufferList* inInputData,
988 const AudioTimeStamp* inInputTime,
989 AudioBufferList* outOutputData,
990 const AudioTimeStamp* inOutputTime,
991 void* defptr)
993 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
995 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
997 AudioTimeStamp readTime;
998 readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback();
999 readTime.mFlags = kAudioTimeStampSampleTimeValid;
1001 AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList());
1003 def->Run(def->GetInputBufferList(), outOutputData, oscTime);
1005 return kAudioHardwareNoError;
1010 OSStatus appIOProcSeparateIn (AudioDeviceID device, const AudioTimeStamp* inNow,
1011 const AudioBufferList* inInputData,
1012 const AudioTimeStamp* inInputTime,
1013 AudioBufferList* outOutputData,
1014 const AudioTimeStamp* inOutputTime,
1015 void* defptr)
1017 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1019 // copy input data to driver's private buffer list
1020 int i;
1021 for (i=0; i<inInputData->mNumberBuffers; i++)
1023 memcpy(def->mInputBufList->mBuffers[i].mData, inInputData->mBuffers[i].mData, inInputData->mBuffers[i].mDataByteSize);
1026 return kAudioHardwareNoError;
1029 OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow,
1030 const AudioBufferList* inInputData,
1031 const AudioTimeStamp* inInputTime,
1032 AudioBufferList* outOutputData,
1033 const AudioTimeStamp* inOutputTime,
1034 void* defptr)
1036 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1037 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
1039 double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9;
1040 double sampleTime = inOutputTime->mSampleTime;
1041 if (def->mStartHostSecs == 0) {
1042 def->mStartHostSecs = hostSecs;
1043 def->mStartSampleTime = sampleTime;
1044 } else {
1045 double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs);
1046 double smoothSampleRate = def->mSmoothSampleRate;
1047 smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
1048 def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate);
1049 def->mSmoothSampleRate = smoothSampleRate;
1051 #if 0
1052 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs);
1053 double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime);
1054 double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs);
1055 //if (fabs(jitter) > 0.01) {
1056 scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n",
1057 avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement);
1059 #endif
1061 def->mPrevHostSecs = hostSecs;
1062 def->mPrevSampleTime = sampleTime;
1064 if (!def->UseSeparateIO())
1066 def->Run(inInputData, outOutputData, oscTime);
1067 return kAudioHardwareNoError;
1071 def->Run(def->mInputBufList, outOutputData, oscTime);
1072 return kAudioHardwareNoError;
1075 void SC_CoreAudioDriver::Run(const AudioBufferList* inInputData,
1076 AudioBufferList* outOutputData, int64 oscTime)
1078 int64 systemTimeBefore = AudioGetCurrentHostTime();
1079 World *world = mWorld;
1081 try {
1082 int numSamplesPerCallback = NumSamplesPerCallback();
1083 mOSCbuftime = oscTime;
1085 #ifdef __APPLE__
1086 sc_SetDenormalFlags();
1087 #endif
1089 mFromEngine.Free();
1090 /*if (mToEngine.HasData()) {
1091 scprintf("oscTime %.9f %.9f\n", oscTime*kOSCtoSecs, CoreAudioHostTimeToOSC(AudioGetCurrentHostTime())*kOSCtoSecs);
1093 mToEngine.Perform();
1094 mOscPacketsToEngine.Perform();
1096 int bufFrames = world->mBufLength;
1097 int numBufs = numSamplesPerCallback / bufFrames;
1099 int numInputBuses = world->mNumInputs;
1100 int numOutputBuses = world->mNumOutputs;
1101 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
1102 float* outputBuses = world->mAudioBus;
1103 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
1104 int32* outputTouched = world->mAudioBusTouched;
1105 int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0;
1106 int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0;
1108 //static int go = 0;
1110 int64 oscInc = mOSCincrement;
1111 double oscToSamples = mOSCtoSamples;
1113 int bufFramePos = 0;
1115 for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) {
1116 int32 bufCounter = world->mBufCounter;
1118 // de-interleave input
1119 if (inInputData) {
1120 const AudioBuffer* inInputDataBuffers = inInputData->mBuffers;
1121 for (int s = 0, b = 0; b<numInputBuses && s < numInputStreams; s++) {
1122 const AudioBuffer* buf = inInputDataBuffers + s;
1123 int nchan = buf->mNumberChannels;
1124 if (buf->mData) {
1125 float *busdata = inputBuses + b * bufFrames;
1126 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1127 if (nchan == 1) {
1128 for (int k=0; k<bufFrames; ++k) {
1129 busdata[k] = bufdata[k];
1131 inputTouched[b] = bufCounter;
1132 } else {
1133 int minchan = sc_min(nchan, numInputBuses - b);
1134 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1135 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1136 busdata[k] = bufdata[m];
1138 inputTouched[b+j] = bufCounter;
1141 b += nchan;
1145 //count++;
1147 int64 schedTime;
1148 int64 nextTime = oscTime + oscInc;
1150 /*if (mScheduler.Ready(nextTime)) {
1151 double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs;
1152 scprintf("rdy %.9f %.9f %.9f\n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff);
1155 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
1156 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
1157 float diffTimeFloor = floor(diffTime);
1158 world->mSampleOffset = (int)diffTimeFloor;
1159 world->mSubsampleOffset = diffTime - diffTimeFloor;
1161 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
1162 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
1164 SC_ScheduledEvent event = mScheduler.Remove();
1165 event.Perform();
1167 world->mSampleOffset = 0;
1168 world->mSubsampleOffset = 0.f;
1170 World_Run(world);
1172 // interleave output
1173 AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers;
1174 for (int s = 0, b = 0; b<numOutputBuses && s < numOutputStreams; s++) {
1175 AudioBuffer* buf = outOutputDataBuffers + s;
1176 int nchan = buf->mNumberChannels;
1177 if (buf->mData) {
1178 float *busdata = outputBuses + b * bufFrames;
1179 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1180 if (nchan == 1) {
1181 if (outputTouched[b] == bufCounter) {
1182 for (int k=0; k<bufFrames; ++k) {
1183 bufdata[k] = busdata[k];
1186 } else {
1187 int minchan = sc_min(nchan, numOutputBuses - b);
1188 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1189 if (outputTouched[b+j] == bufCounter) {
1190 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1191 bufdata[m] = busdata[k];
1196 b += nchan;
1199 oscTime = mOSCbuftime = nextTime;
1201 } catch (std::exception& exc) {
1202 scprintf("exception in real time: %s\n", exc.what());
1203 } catch (...) {
1204 scprintf("unknown exception in real time\n");
1206 int64 systemTimeAfter = AudioGetCurrentHostTime();
1207 double calcTime = (double)AudioConvertHostTimeToNanos(systemTimeAfter - systemTimeBefore) * 1e-9;
1208 double cpuUsage = calcTime * mBuffersPerSecond * 100.;
1209 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
1210 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
1212 mPeakCPU = cpuUsage;
1213 mPeakCounter = mMaxPeakCounter;
1216 mAudioSync.Signal();
1222 //////////////////////////////////////////////////////////////////////////////////////////
1223 //////////////////////////////////////////////////////////////////////////////////////////
1224 //////////////////////////////////////////////////////////////////////////////////////////
1225 // These are not linked in yet, but we'll need to listen for the properties and stop/restart synthesis
1226 // if sample-rate, format, or device change.
1228 OSStatus hardwareListenerProc ( AudioHardwarePropertyID inPropertyID,
1229 void* inClientData)
1231 OSStatus err = noErr;
1232 char cStr[255];
1233 UInt32 outSize;
1234 Boolean outWritable;
1235 AudioDeviceID deviceID;
1237 switch(inPropertyID)
1239 case kAudioHardwarePropertyDefaultOutputDevice:
1240 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultOutputDevice\r");
1241 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &outWritable);
1242 if (err) break;
1243 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &deviceID);
1244 if (err) break;
1245 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1246 if (err) break;
1247 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1248 if (err) break;
1250 // do something
1252 break;
1254 case kAudioHardwarePropertyDefaultInputDevice:
1255 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultInputDevice\r");
1256 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultInputDevice, &outSize, &outWritable);
1257 if (err) break;
1258 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &outSize, &deviceID);
1259 if (err) break;
1260 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1261 if (err) break;
1262 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1263 if (err) break;
1265 // do something
1267 break;
1269 case kAudioHardwarePropertyDefaultSystemOutputDevice:
1270 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultSystemOutputDevice\r");
1271 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &outWritable);
1272 if (err) break;
1273 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &deviceID);
1274 if (err) break;
1275 err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
1276 if (err) break;
1277 err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr);
1278 if (err) break;
1280 // do something
1282 break;
1284 case kAudioHardwarePropertyDevices:
1286 scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDevices\r");
1288 break;
1289 default:
1290 scprintf("%s\n", "***** HARDWARE NOTIFICATION - %4.4s\r", &inPropertyID);
1293 fflush(stdout);
1294 return (noErr);
1300 OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData);
1302 OSStatus AddHardwareListeners(void* inClientData);
1303 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1304 OSStatus AddHardwareListeners(void* inClientData)
1306 OSStatus err = noErr;
1308 //non deprecated but requires AudiObject, bleargh
1309 //err= AudioObjectAddPropertyListener(AudioObject, kAudioHardwarePropertyDefaultOutputDevice, hardwareListenerProc, inClientData);
1311 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultOutputDevice, hardwareListenerProc, inClientData);
1312 if (err) return err;
1314 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultInputDevice, hardwareListenerProc, inClientData);
1315 if (err) return err;
1317 //doesn't matter? Only default looked at by SC?
1318 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultSystemOutputDevice, hardwareListenerProc, inClientData);
1319 if (err) return err;
1321 err = AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, hardwareListenerProc, inClientData);
1322 if (err) return err;
1324 return (err);
1327 bool SC_CoreAudioDriver::DriverStart()
1329 if(mWorld->mVerbosity >= 1){
1330 scprintf("->SC_CoreAudioDriver::DriverStart\n");
1332 OSStatus err = kAudioHardwareNoError;
1333 AudioTimeStamp now;
1334 UInt32 propertySize;
1335 Boolean writable;
1337 if(mWorld->mVerbosity >= 1){
1338 scprintf("start UseSeparateIO?: %d\n", UseSeparateIO());
1341 try {
1342 if (UseSeparateIO()) {
1343 err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup Out device with an IO proc
1344 if (err != kAudioHardwareNoError) {
1345 scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err);
1346 return false;
1349 err = AudioDeviceAddIOProc(mInputDevice, appIOProcSeparateIn, (void *) this); // setup In device with an IO proc
1350 if (err != kAudioHardwareNoError) {
1351 scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err);
1352 return false;
1356 if (mWorld->hw->mInputStreamsEnabled) {
1357 err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1358 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1359 su->mIOProc = (void*)appIOProcSeparateIn;
1360 err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1361 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled));
1362 for (int i=0; i<len; ++i) {
1363 su->mStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1';
1365 err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1368 if (mWorld->hw->mOutputStreamsEnabled) {
1369 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1370 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1371 su->mIOProc = (void*)appIOProc;
1372 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1373 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled));
1374 for (int i=0; i<len; ++i) {
1375 su->mStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1';
1377 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1380 err = AudioDeviceStart(mInputDevice, appIOProcSeparateIn); // start playing sound through the device
1381 if (err != kAudioHardwareNoError) {
1382 scprintf("AudioDeviceStart failed %d\n", (int)err);
1383 return false;
1386 err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device
1387 if (err != kAudioHardwareNoError) {
1388 scprintf("AudioDeviceStart failed %d\n", (int)err);
1389 err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn); // stop playing sound through the device
1390 return false;
1392 } else {
1393 err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup our device with an IO proc
1394 if (err != kAudioHardwareNoError) {
1395 scprintf("AudioDeviceAddIOProc failed %d\n", (int)err);
1396 return false;
1399 if (mWorld->hw->mInputStreamsEnabled) {
1400 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1401 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1402 su->mIOProc = (void*)appIOProc;
1403 err = AudioDeviceGetProperty(mOutputDevice, 0, true, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1404 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled));
1405 for (int i=0; i<len; ++i) {
1406 su->mStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1';
1408 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1411 if (mWorld->hw->mOutputStreamsEnabled) {
1412 err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, &writable);
1413 AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize);
1414 su->mIOProc = (void*)appIOProc;
1415 err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyIOProcStreamUsage, &propertySize, su);
1416 int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled));
1417 for (int i=0; i<len; ++i) {
1418 su->mStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1';
1420 err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyIOProcStreamUsage, propertySize, su);
1423 err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device
1424 if (err != kAudioHardwareNoError) {
1425 scprintf("AudioDeviceStart failed %d\n", (int)err);
1426 return false;
1429 } catch (...) {
1430 scprintf("exception in SC_CoreAudioDriver::DriverStart\n");
1432 if(mWorld->mVerbosity >= 1){
1433 scprintf("<-SC_CoreAudioDriver::DriverStart\n");
1437 //http://lists.apple.com/archives/coreaudio-api/2010/Aug/msg00114.html
1438 CFRunLoopRef theRunLoop = NULL;
1439 AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1440 AudioObjectSetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
1442 //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
1443 //by switching to system default?
1444 //AddHardwareListeners(NULL);
1445 //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
1446 AddDeviceListeners(mOutputDevice, this);
1448 return true;
1452 bool SC_CoreAudioDriver::StopStart() {
1454 bool test = DriverStop();
1456 bool test2 = DriverStart();
1457 return test && test2;
1461 bool SC_CoreAudioDriver::DriverStop()
1463 if(mWorld->mVerbosity >= 1){
1464 scprintf("->SC_CoreAudioDriver::DriverStop\n");
1466 OSStatus err = kAudioHardwareNoError;
1468 if (UseSeparateIO()) {
1469 err = AudioDeviceStop(mOutputDevice, appIOProc);
1470 if (err != kAudioHardwareNoError) {
1471 scprintf("AudioDeviceStop A failed %p\n", err);
1472 return false;
1474 err = AudioDeviceRemoveIOProc(mOutputDevice, appIOProc);
1475 if (err != kAudioHardwareNoError) {
1476 scprintf("AudioDeviceRemoveIOProc A failed %p\n", err);
1477 return false;
1480 err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn);
1481 if (err != kAudioHardwareNoError) {
1482 scprintf("AudioDeviceStop A failed %p\n", err);
1483 return false;
1486 err = AudioDeviceRemoveIOProc(mInputDevice, appIOProcSeparateIn);
1487 if (err != kAudioHardwareNoError) {
1488 scprintf("AudioDeviceRemoveIOProc A failed %p\n", err);
1489 return false;
1491 } else {
1492 err = AudioDeviceStop(mOutputDevice, appIOProc);
1493 if (err != kAudioHardwareNoError) {
1494 scprintf("AudioDeviceStop B failed %p\n", err);
1495 return false;
1498 err = AudioDeviceRemoveIOProc(mOutputDevice, appIOProc);
1499 if (err != kAudioHardwareNoError) {
1500 scprintf("AudioDeviceRemoveIOProc B failed %p\n", err);
1501 return false;
1504 if(mWorld->mVerbosity >= 1){
1505 scprintf("<-SC_CoreAudioDriver::DriverStop\n");
1507 return true;
1511 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1512 // Listen for Device Properties and update interface and globals
1513 OSStatus deviceListenerProc ( AudioDeviceID inDevice,
1514 UInt32 inLine,
1515 Boolean isInput,
1516 AudioDevicePropertyID inPropertyID,
1517 void* inClientData)
1519 OSStatus err = noErr;
1520 UInt32 outSize,
1521 theUIntData,
1522 mute,
1523 playThru;
1524 UInt32 tLong;
1525 Float32 vol;
1528 SC_CoreAudioDriver* coredriver = (SC_CoreAudioDriver*) inClientData;
1530 switch(inPropertyID)
1532 // case kAudioDevicePropertyBufferSize:
1533 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferSize\r");
1534 // outSize = sizeof(UInt32);
1535 // err = AudioDeviceGetProperty(inDevice, 0, 0, kAudioDevicePropertyBufferSize, &outSize, &theUIntData);
1537 // break;
1539 // case kAudioDevicePropertyBufferFrameSize:
1540 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferFrameSize\r");
1541 // outSize = sizeof(UInt32);
1542 // err = AudioDeviceGetProperty(inDevice, 0, 0, kAudioDevicePropertyBufferFrameSize, &outSize, &theUIntData);
1544 // break;
1546 // case kAudioDevicePropertyBufferSizeRange:
1547 // {
1548 // AudioValueRange range;
1550 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyBufferSizeRange\r");
1551 // outSize = sizeof(AudioValueRange);
1552 // err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyBufferSizeRange, &outSize, &range);
1553 // }
1554 // break;
1556 // case kAudioDevicePropertyStreamFormat:
1557 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyStreamFormat\r");
1558 // break;
1560 // case kAudioDevicePropertyDeviceIsRunning:
1561 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDeviceIsRunning\r");
1562 // outSize = sizeof(UInt32);
1563 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyDeviceIsRunning, &outSize, &theUIntData);
1565 // //when change device get up to four messages:
1566 // //isInput ==NO or YES theUIntData= 0 or 1 from old and possibly new device (ieheadphone swap)
1570 // break;
1572 // case kAudioDevicePropertyVolumeScalar:
1573 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyVolumeScalar\r");
1574 // outSize = sizeof(Float32);
1575 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyVolumeScalar, &outSize, &vol);
1576 // break;
1578 // case kAudioDevicePropertyMute:
1579 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyMute\r");
1580 // outSize = sizeof(UInt32);
1581 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyMute, &outSize, &mute);
1582 // break;
1584 // case kAudioDevicePropertyPlayThru:
1585 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyPlayThru\r");
1586 // outSize = sizeof(UInt32);
1587 // err = AudioDeviceGetProperty(inDevice, inLine, isInput, kAudioDevicePropertyPlayThru, &outSize, &playThru);
1589 // break;
1591 // case kAudioDevicePropertyDeviceIsAlive:
1592 // scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDeviceIsAlive\r");
1593 // outSize = sizeof(UInt32);
1594 // err = AudioDeviceGetProperty(inDevice, 0, false, kAudioDevicePropertyDeviceIsAlive, &outSize, &tLong);
1596 // break;
1598 case kAudioDevicePropertyDataSource:
1599 //Don't print anything
1600 //scprintf("%s\n", "***** DEVICE NOTIFICATION - kAudioDevicePropertyDataSource\r");
1601 // get the source
1602 // match the source to one of the available sources and return the index of that source
1603 //SetControlValue(control, (chan->vol) * 100);
1605 //will get this message anyway even if don't have built-in output seleected.
1606 //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
1607 //swapping to new driver
1608 if (coredriver->builtinoutputflag_==1)
1609 coredriver->StopStart();
1612 break;
1614 //default:
1615 // scprintf("%s\n", "***** DEVICE NOTIFICATION - %4.4s\r", &inPropertyID);
1618 //fflush(stdout);
1619 return (err);
1622 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1623 OSStatus streamListenerProc ( AudioStreamID inStream,
1624 UInt32 inChannel,
1625 AudioDevicePropertyID inPropertyID,
1626 void* inClientData)
1628 OSStatus err = noErr;
1630 switch(inPropertyID)
1632 case kAudioStreamPropertyPhysicalFormat:
1633 scprintf("%s\n", "***** STREAM NOTIFICATION - kAudioStreamPropertyPhysicalFormat\r");
1634 break;
1636 case kAudioDevicePropertyStreamFormat:
1637 scprintf("%s\n", "***** STREAM NOTIFICATION - kAudioDevicePropertyStreamFormat\r");
1638 break;
1640 default:
1641 break;
1644 fflush(stdout);
1646 return (err);
1649 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1650 OSStatus AddStreamListeners (AudioDeviceID inDevice, AudioDevicePropertyID inPropertyID, Boolean isInput, void *inClientData);
1652 OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData)
1654 OSStatus err = noErr;
1656 //ONLY REACTING TO HEADPHONE SWAPS FOR NOW
1660 // // kAudioDevicePropertyBufferSize
1661 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferSize, deviceListenerProc, inClientData);
1662 // if (err) return err;
1664 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferSize, deviceListenerProc, inClientData);
1665 // if (err) return err;
1668 // // kAudioDevicePropertyBufferFrameSize
1669 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferFrameSize, deviceListenerProc, inClientData);
1670 // if (err) return err;
1672 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferFrameSize, deviceListenerProc, inClientData);
1673 // if (err) return err;
1675 // // kAudioDevicePropertyDeviceIsRunning
1676 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDeviceIsRunning, deviceListenerProc, inClientData);
1677 // if (err) return err;
1679 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDeviceIsRunning, deviceListenerProc, inClientData);
1680 // if (err) return err;
1682 ///*
1683 // for (i = 0; i <= deviceInfo->totalOutputChannels; i++)
1684 // {
1685 // // kAudioDevicePropertyVolumeScalar output
1686 // err = AudioDeviceAddPropertyListener(inDevice, i, false, kAudioDevicePropertyVolumeScalar, deviceListenerProc, inClientData);
1687 // if (err) return err;
1689 // // kAudioDevicePropertyVolumeMute output
1690 // err = AudioDeviceAddPropertyListener(inDevice, i, false, kAudioDevicePropertyMute, deviceListenerProc, inClientData);
1691 // if (err) return err;
1692 // }
1694 // for (i = 0; i <= deviceInfo->totalInputChannels; i++)
1695 // {
1696 // // kAudioDevicePropertyVolumeScalar input
1697 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyVolumeScalar, deviceListenerProc, inClientData);
1698 // if (err) return err;
1700 // // kAudioDevicePropertyVolumeMute input
1701 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyMute, deviceListenerProc, inClientData);
1702 // if (err) return err;
1704 // // kAudioDevicePropertyPlayThru input
1705 // err = AudioDeviceAddPropertyListener(inDevice, i, true, kAudioDevicePropertyPlayThru, deviceListenerProc, inClientData);
1706 // if (err) return err;
1707 // }
1708 //*/
1710 // // kAudioDevicePropertyDeviceIsAlive
1711 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDeviceIsAlive, deviceListenerProc, inClientData);
1712 // if (err) return err;
1714 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDeviceIsAlive, deviceListenerProc, inClientData);
1715 // if (err) return err;
1718 // // kAudioDevicePropertyStreamFormat
1719 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyStreamFormat, deviceListenerProc, inClientData);
1720 // if (err) return err;
1722 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyStreamFormat, deviceListenerProc, inClientData);
1723 // if (err) return err;
1725 // // kAudioDevicePropertyBufferSizeRange
1726 // err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyBufferSizeRange, deviceListenerProc, inClientData);
1727 // if (err) return err;
1729 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyBufferSizeRange, deviceListenerProc, inClientData);
1730 // if (err) return err;
1732 //kAudioDevicePropertyDataSource
1733 err = AudioDeviceAddPropertyListener(inDevice, 0, false, kAudioDevicePropertyDataSource, deviceListenerProc, inClientData);
1734 if (err) return err;
1736 // err = AudioDeviceAddPropertyListener(inDevice, 0, true, kAudioDevicePropertyDataSource, deviceListenerProc, inClientData);
1737 // if (err) return err;
1740 //AddStreamListeners (inDevice, kAudioStreamPropertyPhysicalFormat, false, inClientData);
1742 //AddStreamListeners (inDevice, kAudioStreamPropertyPhysicalFormat, true, inClientData);
1744 return (err);
1749 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1750 OSStatus AddStreamListeners (AudioDeviceID inDevice, AudioDevicePropertyID inPropertyID, Boolean isInput, void *inClientData)
1752 OSStatus err = noErr;
1753 UInt32 count;
1754 UInt32 outSize;
1755 Boolean outWritable;
1756 AudioStreamID *streamList = nil;
1758 err = AudioDeviceGetPropertyInfo(inDevice, 0, isInput, kAudioDevicePropertyStreams, &outSize, &outWritable);
1759 if (err == noErr)
1761 streamList = (AudioStreamID*)malloc(outSize);
1762 err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyStreams, &outSize, streamList);
1763 if (err == noErr)
1765 for (count = 0; count < (outSize / sizeof(AudioStreamID)); count++)
1767 err = AudioStreamAddPropertyListener(streamList[count], 0, inPropertyID, streamListenerProc, inClientData);
1768 if (err) return err;
1771 if (streamList != nil)
1773 free(streamList);
1774 streamList = nil;
1779 return (noErr);
1781 #endif // SC_AUDIO_API_COREAUDIO
1786 // =====================================================================
1787 // Audio driver (CoreAudioIPHONE)
1789 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
1790 SC_iCoreAudioDriver::SC_iCoreAudioDriver(struct World *inWorld)
1791 : SC_AudioDriver(inWorld)
1793 receivedIn = 0;
1796 SC_iCoreAudioDriver::~SC_iCoreAudioDriver()
1801 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
1802 const AudioBufferList* inInputData,
1803 const AudioTimeStamp* inInputTime,
1804 AudioBufferList* outOutputData,
1805 const AudioTimeStamp* inOutputTime,
1806 void* defptr);
1807 OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
1808 const AudioBufferList* inInputData,
1809 const AudioTimeStamp* inInputTime,
1810 AudioBufferList* outOutputData,
1811 const AudioTimeStamp* inOutputTime,
1812 void* defptr)
1814 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
1816 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
1818 AudioTimeStamp readTime;
1819 readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback();
1820 readTime.mFlags = kAudioTimeStampSampleTimeValid;
1822 AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList());
1824 def->Run(def->GetInputBufferList(), outOutputData, oscTime);
1826 return kAudioHardwareNoError;
1831 OSStatus InputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
1833 SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon;
1835 if (driver->receivedIn)
1837 //printf("exit input with no data \n");
1838 return noErr;
1841 OSStatus ret = AudioUnitRender(driver->inputUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, driver->buflist);
1842 if (ret)
1844 //printf("no input !\n");
1845 return noErr;
1847 driver->receivedIn = 1;
1849 return noErr;
1852 OSStatus RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
1854 SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon;
1856 #ifndef SC_IPHONE
1857 if (!driver->receivedIn)
1859 //printf("exit output with no data \n");
1860 return noErr;
1862 #endif
1864 //float *fbuffer = (float *) driver->converter_buffer;
1866 int i;
1867 for (i=0; i<inNumberFrames; i++)
1869 signed short s = ((signed short *)driver->buflist->mBuffers[0].mData)[i];
1870 int k = s + 0x43c00000;
1871 float f = *((float *) &k);
1872 ((float *)driver->floatInputList->mBuffers[0].mData)[i] = f - 384.0f;
1875 int64 oscTime = GetCurrentOSCTime();
1876 //driver->Run(driver->floatInputList, driver->floatOutputList, oscTime);
1877 driver->Run(driver->floatInputList, ioData, oscTime);
1879 for (i=0; i<inNumberFrames; i++)
1881 float f1 = ((float *)ioData->mBuffers[0].mData)[i];
1882 float f2 = ((float *)ioData->mBuffers[1].mData)[i];
1883 ((int *) ioData->mBuffers[0].mData)[i] = (int) (f1*16777216);
1884 ((int *) ioData->mBuffers[1].mData)[i] = (int) (f2*16777216);
1889 unsigned long size = 2*1024*sizeof(unsigned long);
1890 OSStatus ret = AudioConverterConvertBuffer(driver->converter_in_to_F32, driver->buflist->mBuffers[0].mDataByteSize, driver->buflist->mBuffers[0].mData, &size, driver->converter_buffer);
1891 if (ret)
1893 printf("couldn't convert !\n");
1894 return noErr;
1897 int i;
1898 for (i=0; i<inNumberFrames; i++)
1900 ((int *)ioData->mBuffers[0].mData)[i] = ((int *)ioData->mBuffers[1].mData)[i] = driver->converter_buffer[2*i];
1903 driver->receivedIn = 0;
1904 return noErr;
1909 void SC_iCoreAudioDriver::Run(const AudioBufferList* inInputData,
1910 AudioBufferList* outOutputData, int64 oscTime)
1912 int64 systemTimeBefore = GetMicroseconds();
1914 World *world = mWorld;
1916 try {
1917 int numSamplesPerCallback = NumSamplesPerCallback();
1918 mOSCbuftime = oscTime;
1920 #ifdef __APPLE__
1921 sc_SetDenormalFlags();
1922 #endif
1924 mFromEngine.Free();
1926 mToEngine.Perform();
1927 mOscPacketsToEngine.Perform();
1928 //printf("mOscPacketsToEngine : %d micros\n", (int) (GetMicroseconds()-systemTimeBefore));
1930 int bufFrames = world->mBufLength;
1931 int numBufs = numSamplesPerCallback / bufFrames;
1933 int numInputBuses = world->mNumInputs;
1934 int numOutputBuses = world->mNumOutputs;
1935 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
1936 float* outputBuses = world->mAudioBus;
1937 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
1938 int32* outputTouched = world->mAudioBusTouched;
1939 int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0;
1940 int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0;
1942 //static int go = 0;
1944 int64 oscInc = mOSCincrement;
1945 double oscToSamples = mOSCtoSamples;
1947 int bufFramePos = 0;
1949 for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) {
1950 int32 bufCounter = world->mBufCounter;
1952 // de-interleave input
1953 if (inInputData) {
1954 const AudioBuffer* inInputDataBuffers = inInputData->mBuffers;
1955 for (int s = 0, b = 0; b<numInputBuses && s < numInputStreams; s++) {
1956 const AudioBuffer* buf = inInputDataBuffers + s;
1957 int nchan = buf->mNumberChannels;
1958 if (buf->mData) {
1959 float *busdata = inputBuses + b * bufFrames;
1960 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
1961 if (nchan == 1)
1963 #ifdef IPHONE_VEC
1964 vcopy(busdata, bufdata, bufFrames);
1965 #else
1966 for (int k=0; k<bufFrames; ++k)
1968 busdata[k] = bufdata[k];
1970 #endif
1971 inputTouched[b] = bufCounter;
1972 } else {
1973 int minchan = sc_min(nchan, numInputBuses - b);
1974 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
1975 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
1976 busdata[k] = bufdata[m];
1978 inputTouched[b+j] = bufCounter;
1981 b += nchan;
1985 //count++;
1987 int64 schedTime;
1988 int64 nextTime = oscTime + oscInc;
1990 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
1991 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
1992 float diffTimeFloor = floor(diffTime);
1993 world->mSampleOffset = (int)diffTimeFloor;
1994 world->mSubsampleOffset = diffTime - diffTimeFloor;
1996 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
1997 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
1999 SC_ScheduledEvent event = mScheduler.Remove();
2000 event.Perform();
2002 world->mSampleOffset = 0;
2003 world->mSubsampleOffset = 0.f;
2005 //int64 now = GetMicroseconds();
2007 World_Run(world);
2009 //printf("world run : %fms\n", (float) (GetMicroseconds()-now)/1000);
2012 // interleave output
2013 AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers;
2014 for (int s = 0, b = 0; b<numOutputBuses && s < numOutputStreams; s++) {
2015 AudioBuffer* buf = outOutputDataBuffers + s;
2016 int nchan = buf->mNumberChannels;
2017 if (buf->mData) {
2018 float *busdata = outputBuses + b * bufFrames;
2019 float *bufdata = (float*)buf->mData + bufFramePos * nchan;
2020 if (nchan == 1)
2022 if (outputTouched[b] == bufCounter)
2024 #ifdef IPHONE_VEC
2025 vcopy(bufdata, busdata, bufFrames);
2026 #else
2027 for (int k=0; k<bufFrames; ++k)
2029 bufdata[k] = busdata[k];
2031 #endif
2033 } else {
2034 int minchan = sc_min(nchan, numOutputBuses - b);
2035 for (int j=0; j<minchan; ++j, busdata += bufFrames) {
2036 if (outputTouched[b+j] == bufCounter) {
2037 for (int k=0, m=j; k<bufFrames; ++k, m += nchan) {
2038 bufdata[m] = busdata[k];
2043 b += nchan;
2046 oscTime = mOSCbuftime = nextTime;
2048 } catch (std::exception& exc) {
2049 scprintf("exception in real time: %s\n", exc.what());
2050 } catch (...) {
2051 scprintf("unknown exception in real time\n");
2054 int64 systemTimeAfter = GetMicroseconds();
2055 double calcTime = (double)(systemTimeAfter - systemTimeBefore) * 1e-6;
2056 double cpuUsage = calcTime * mBuffersPerSecond * 100.;
2057 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2058 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2060 mPeakCPU = cpuUsage;
2061 mPeakCounter = mMaxPeakCounter;
2064 mAudioSync.Signal();
2071 OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow,
2072 const AudioBufferList* inInputData,
2073 const AudioTimeStamp* inInputTime,
2074 AudioBufferList* outOutputData,
2075 const AudioTimeStamp* inOutputTime,
2076 void* defptr)
2078 SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr;
2079 int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime);
2081 double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9;
2082 double sampleTime = inOutputTime->mSampleTime;
2083 if (def->mStartHostSecs == 0) {
2084 def->mStartHostSecs = hostSecs;
2085 def->mStartSampleTime = sampleTime;
2086 } else {
2087 double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs);
2088 double smoothSampleRate = def->mSmoothSampleRate;
2089 smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
2090 def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate);
2091 def->mSmoothSampleRate = smoothSampleRate;
2093 #if 0
2094 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs);
2095 double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime);
2096 double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs);
2097 //if (fabs(jitter) > 0.01) {
2098 scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n",
2099 avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement);
2101 #endif
2103 def->mPrevHostSecs = hostSecs;
2104 def->mPrevSampleTime = sampleTime;
2106 if (!def->UseSeparateIO())
2108 def->Run(inInputData, outOutputData, oscTime);
2109 return kAudioHardwareNoError;
2113 def->Run(lastInputData, outOutputData, oscTime);
2114 lastInputData = 0;
2116 return kAudioHardwareNoError;
2121 void AudioSessionInterruptionCbk(void *inClientData, UInt32 inInterruptionState)
2126 bool SC_iCoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate)
2128 AudioSessionInitialize(0, 0, AudioSessionInterruptionCbk, 0);
2129 unsigned long category = kAudioSessionCategory_PlayAndRecord;
2130 #ifdef SC_IPHONE
2131 UInt32 micInput, micInputSize = sizeof(&micInput);
2132 AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &micInputSize, &micInput);
2133 if(!micInput) {
2134 category = kAudioSessionCategory_MediaPlayback;
2135 scprintf("SC_IPHONE: WARNING - no audio input available\n");
2137 #endif
2138 AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
2140 if (mPreferredHardwareBufferFrameSize)
2142 Float32 preferredBufferSize = (float) mPreferredHardwareBufferFrameSize/44100.f;
2143 AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
2146 AudioSessionSetActive(true);
2148 float actualBufferDuration;
2149 UInt32 size = sizeof(actualBufferDuration);
2150 AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &actualBufferDuration);
2152 *outNumSamplesPerCallback = (int) (actualBufferDuration*44100.f+0.5f);
2153 *outSampleRate = 44100;
2155 AudioComponentDescription desc;
2156 desc.componentType = kAudioUnitType_Output;
2157 desc.componentSubType = kAudioUnitSubType_RemoteIO;
2158 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
2160 NewAUGraph(&graph);
2161 AUNode node;
2162 AudioUnit unit;
2163 OSStatus ret = AUGraphAddNode(graph, &desc, &node);
2164 //printf("node : %d\n", node);
2165 AUGraphOpen(graph);
2167 ret = AUGraphNodeInfo(graph, node, &desc, &unit);
2168 //printf("%d\n", unit);
2172 AudioComponent remoteIOComp = AudioComponentFindNext(0, &desc);
2173 if (AudioComponentInstanceNew(remoteIOComp, &inputUnit)!=noErr)
2175 //printf("error instantiating RemoteIO\n");
2176 return false;
2178 //printf("instantiated : %d\n", inputUnit);
2180 int enableIO = 1;
2181 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
2182 if (ret!=noErr)
2184 //printf("can't set input : %d\n", ret);
2185 return false;
2187 enableIO = 0;
2188 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
2189 if (ret!=noErr)
2191 //printf("can't set output : %d\n", ret);
2192 return false;
2195 AudioUnitInitialize(inputUnit);
2197 unsigned long bufferSizeBytes = 1024 * sizeof(unsigned long);
2198 buflist = (AudioBufferList *) malloc(sizeof(AudioBufferList));
2199 buflist->mNumberBuffers = 1;
2200 buflist->mBuffers[0].mDataByteSize = bufferSizeBytes;
2201 buflist->mBuffers[0].mData = malloc(bufferSizeBytes);
2202 buflist->mBuffers[0].mNumberChannels = 1;
2204 floatInputList = (AudioBufferList *) malloc(sizeof(AudioBufferList));
2205 floatInputList->mNumberBuffers = 1;
2206 floatInputList->mBuffers[0].mDataByteSize = bufferSizeBytes;
2207 floatInputList->mBuffers[0].mData = malloc(bufferSizeBytes);
2208 floatInputList->mBuffers[0].mNumberChannels = 1;
2211 floatOutputList = (AudioBufferList *) malloc(sizeof(AudioBufferList)+sizeof(AudioBuffer));
2212 floatOutputList->mNumberBuffers = 2;
2213 floatOutputList->mBuffers[0].mDataByteSize = bufferSizeBytes;
2214 floatOutputList->mBuffers[0].mData = malloc(bufferSizeBytes);
2215 floatOutputList->mBuffers[0].mNumberChannels = 1;
2216 floatOutputList->mBuffers[1].mDataByteSize = bufferSizeBytes;
2217 floatOutputList->mBuffers[1].mData = malloc(bufferSizeBytes);
2218 floatOutputList->mBuffers[1].mNumberChannels = 1;
2221 AURenderCallbackStruct inputStruct;
2222 inputStruct.inputProc = InputCallback;
2223 inputStruct.inputProcRefCon = this;
2224 ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &inputStruct, sizeof(inputStruct));
2226 AURenderCallbackStruct renderStruct;
2227 renderStruct.inputProc = RenderCallback;
2228 renderStruct.inputProcRefCon = this;
2229 ret = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderStruct, sizeof(renderStruct));
2231 AudioStreamBasicDescription streamFormat;
2232 streamFormat.mFormatID = kAudioFormatLinearPCM;
2233 streamFormat.mFormatFlags =
2234 kAudioFormatFlagIsSignedInteger
2235 | kAudioFormatFlagsNativeEndian
2236 | kLinearPCMFormatFlagIsNonInterleaved
2237 | (24 << kLinearPCMFormatFlagsSampleFractionShift);
2238 streamFormat.mSampleRate = 44100;
2239 streamFormat.mBitsPerChannel = 32;
2240 streamFormat.mChannelsPerFrame = 2;
2241 streamFormat.mFramesPerPacket = 1;
2242 streamFormat.mBytesPerFrame = ( streamFormat.mBitsPerChannel / 8 );
2243 streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame *
2244 streamFormat.mFramesPerPacket;
2246 ret = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(streamFormat));
2249 AudioStreamBasicDescription audioFormat;
2250 audioFormat.mSampleRate = 44100.00;
2251 audioFormat.mFormatID = kAudioFormatLinearPCM;
2252 audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
2253 audioFormat.mFramesPerPacket = 1;
2254 audioFormat.mChannelsPerFrame = 1;
2255 audioFormat.mBitsPerChannel = 16;
2256 audioFormat.mBytesPerPacket = 2;
2257 audioFormat.mBytesPerFrame = 2;
2258 ret = AudioUnitSetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &audioFormat, sizeof(audioFormat));
2262 AudioStreamBasicDescription d;
2263 size = sizeof(d);
2264 ret = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &d, &size);
2266 AudioStreamBasicDescription inputFormat;
2267 AudioStreamBasicDescription outputFormat;
2268 AudioStreamBasicDescription f32Format;
2270 size = sizeof(AudioStreamBasicDescription);
2271 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &inputFormat, &size);
2272 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &inputFormat, &size);
2273 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outputFormat, &size);
2274 ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outputFormat, &size);
2276 outputFormat.mChannelsPerFrame = 1;
2278 f32Format.mSampleRate = inputFormat.mSampleRate;
2279 f32Format.mFormatID = inputFormat.mFormatID;
2280 f32Format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
2281 f32Format.mBytesPerPacket = 4;
2282 f32Format.mFramesPerPacket = 1;
2283 f32Format.mBytesPerFrame = 4;
2284 f32Format.mChannelsPerFrame = 1;
2285 f32Format.mBitsPerChannel = 32;
2286 f32Format.mReserved = 0;
2288 ret = AudioConverterNew(&inputFormat, &f32Format, &converter_in_to_F32);
2289 ret = AudioConverterNew(&f32Format, &outputFormat, &converter_F32_to_out);
2290 ret = AudioConverterNew(&inputFormat, &outputFormat, &converter_in_to_out);
2292 AUGraphInitialize(graph);
2294 if(mWorld->mVerbosity >= 0){
2295 scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld);
2297 return true;
2300 bool SC_iCoreAudioDriver::DriverStart()
2302 if(mWorld->mVerbosity >= 0){
2303 scprintf("->SC_CoreAudioDriver::DriverStart\n");
2308 OSStatus ret = AUGraphStart(graph);
2309 AudioOutputUnitStart(inputUnit);
2310 } catch (...) {
2311 scprintf("exception in SC_CoreAudioDriver::DriverStart\n");
2313 if(mWorld->mVerbosity >= 0){
2314 scprintf("<-SC_CoreAudioDriver::DriverStart\n");
2316 return true;
2319 bool SC_iCoreAudioDriver::DriverStop()
2321 if(mWorld->mVerbosity >= 0){
2322 scprintf("->SC_CoreAudioDriver::DriverStop\n");
2325 AUGraphStop(graph);
2326 AudioOutputUnitStop(inputUnit);
2328 if(mWorld->mVerbosity >= 0){
2329 scprintf("<-SC_CoreAudioDriver::DriverStop\n");
2331 return true;
2334 #endif // SC_AUDIO_API_COREAUDIOIPHONE
2339 // =====================================================================
2340 // Audio driver (PortAudio)
2342 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
2344 // =====================================================================
2345 // SC_PortAudioDriver (PortAudio)
2347 #define PRINT_PORTAUDIO_ERROR( function, errorcode )\
2348 scprintf( "SC_PortAudioDriver: PortAudio failed at %s with error: '%s'\n",\
2349 #function, Pa_GetErrorText( errorcode ) )
2351 SC_PortAudioDriver::SC_PortAudioDriver(struct World *inWorld)
2352 : SC_AudioDriver(inWorld)
2353 , mStream(0)
2355 PaError paerror = Pa_Initialize();
2356 if( paerror != paNoError )
2357 PRINT_PORTAUDIO_ERROR( Pa_Initialize, paerror );
2360 SC_PortAudioDriver::~SC_PortAudioDriver()
2362 if( mStream ){
2363 PaError paerror = Pa_CloseStream( mStream );
2364 if( paerror != paNoError )
2365 PRINT_PORTAUDIO_ERROR( Pa_CloseStream, paerror );
2367 Pa_Terminate();
2370 static int SC_PortAudioStreamCallback( const void *input, void *output,
2371 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
2372 PaStreamCallbackFlags statusFlags, void *userData )
2374 SC_PortAudioDriver *driver = (SC_PortAudioDriver*)userData;
2376 return driver->PortAudioCallback( input, output, frameCount, timeInfo, statusFlags );
2379 int SC_PortAudioDriver::PortAudioCallback( const void *input, void *output,
2380 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
2381 PaStreamCallbackFlags statusFlags )
2383 World *world = mWorld;
2384 (void) frameCount, timeInfo, statusFlags; // suppress unused parameter warnings
2386 try {
2387 // synchronise against the output buffer - timeInfo->currentTime is 0.0 bug in PA?
2388 if (mPaStreamStartupTime==0 && mPaStreamStartupTimeOSC==0) {
2389 mPaStreamStartupTimeOSC = GetCurrentOSCTime();
2390 mPaStreamStartupTime = timeInfo->outputBufferDacTime;
2392 mOSCbuftime = PaStreamTimeToOSC(timeInfo->outputBufferDacTime - mPaStreamStartupTime) + mPaStreamStartupTimeOSC;
2394 mFromEngine.Free();
2395 mToEngine.Perform();
2396 mOscPacketsToEngine.Perform();
2398 int numInputs = mInputChannelCount;
2399 int numOutputs = mOutputChannelCount;
2400 const float **inBuffers = (const float**)input;
2401 float **outBuffers = (float**)output;
2403 int numSamples = NumSamplesPerCallback();
2404 int bufFrames = mWorld->mBufLength;
2405 int numBufs = numSamples / bufFrames;
2407 float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
2408 float *outBuses = mWorld->mAudioBus;
2409 int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
2410 int32 *outTouched = mWorld->mAudioBusTouched;
2412 int minInputs = std::min<size_t>(numInputs, mWorld->mNumInputs);
2413 int minOutputs = std::min<size_t>(numOutputs, mWorld->mNumOutputs);
2415 int bufFramePos = 0;
2417 int64 oscTime = mOSCbuftime;
2418 int64 oscInc = mOSCincrement;
2419 double oscToSamples = mOSCtoSamples;
2421 // main loop
2422 for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames)
2424 int32 bufCounter = mWorld->mBufCounter;
2425 int32 *tch;
2427 // copy+touch inputs
2428 tch = inTouched;
2429 for (int k = 0; k < minInputs; ++k)
2431 const float *src = inBuffers[k] + bufFramePos;
2432 float *dst = inBuses + k * bufFrames;
2433 for (int n = 0; n < bufFrames; ++n) *dst++ = *src++;
2434 *tch++ = bufCounter;
2437 // run engine
2438 int64 schedTime;
2439 int64 nextTime = oscTime + oscInc;
2440 // DEBUG
2442 if (mScheduler.Ready(nextTime)) {
2443 double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs;
2444 scprintf("rdy %.6f %.6f %.6f %.6f \n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff, (nextTime-gStartupOSCTime)*kOSCtoSecs);
2447 while ((schedTime = mScheduler.NextTime()) <= nextTime) {
2448 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
2449 float diffTimeFloor = floor(diffTime);
2450 world->mSampleOffset = (int)diffTimeFloor;
2451 world->mSubsampleOffset = diffTime - diffTimeFloor;
2453 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
2454 else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;
2456 SC_ScheduledEvent event = mScheduler.Remove();
2457 event.Perform();
2459 world->mSampleOffset = 0;
2460 world->mSubsampleOffset = 0.f;
2462 World_Run(world);
2464 // copy touched outputs
2465 tch = outTouched;
2466 for (int k = 0; k < minOutputs; ++k) {
2467 float *dst = outBuffers[k] + bufFramePos;
2468 if (*tch++ == bufCounter) {
2469 float *src = outBuses + k * bufFrames;
2470 for (int n = 0; n < bufFrames; ++n) *dst++ = *src++;
2471 } else {
2472 for (int n = 0; n < bufFrames; ++n) *dst++ = 0.0f;
2476 // update buffer time
2477 oscTime = mOSCbuftime = nextTime;
2479 } catch (std::exception& exc) {
2480 scprintf("SC_PortAudioDriver: exception in real time: %s\n", exc.what());
2481 } catch (...) {
2482 scprintf("SC_PortAudioDriver: unknown exception in real time\n");
2485 double cpuUsage = (double)Pa_GetStreamCpuLoad(mStream);
2486 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2487 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2489 mPeakCPU = cpuUsage;
2490 mPeakCounter = mMaxPeakCounter;
2493 mAudioSync.Signal();
2495 return paContinue;
2498 void SC_PortAudioDriver::GetPaDeviceFromName(const char* device, int* mInOut) {
2500 const PaDeviceInfo *pdi;
2501 const PaHostApiInfo *apiInfo;
2502 char devString[256];
2503 PaDeviceIndex numDevices = Pa_GetDeviceCount();
2504 mInOut[0] = paNoDevice;
2505 mInOut[1] = paNoDevice;
2507 // This tries to find one or two devices that match the given name (substring)
2508 // might cause problems for some names...
2509 for( int i=0; i<numDevices; i++ ) {
2510 pdi = Pa_GetDeviceInfo( i );
2511 apiInfo = Pa_GetHostApiInfo(pdi->hostApi);
2512 strcpy(devString, apiInfo->name);
2513 strcat(devString, " : ");
2514 strcat(devString, pdi->name);
2515 if (strstr(devString, device)) {
2516 if (pdi->maxInputChannels > 0) mInOut[0] = i;
2517 if (pdi->maxOutputChannels > 0) mInOut[1] = i;
2522 // ====================================================================
2525 bool SC_PortAudioDriver::DriverSetup(int* outNumSamples, double* outSampleRate)
2527 int mDeviceInOut[2];
2528 PaError paerror;
2529 const PaDeviceInfo *pdi;
2530 const PaHostApiInfo *apiInfo;
2531 const PaStreamInfo *psi;
2532 PaTime suggestedLatencyIn, suggestedLatencyOut;
2533 PaDeviceIndex numDevices = Pa_GetDeviceCount();
2535 // print out all options:
2536 fprintf(stdout, "\nDevice options:\n");
2537 for( int i=0; i<numDevices; i++ ) {
2538 pdi = Pa_GetDeviceInfo( i );
2539 apiInfo = Pa_GetHostApiInfo(pdi->hostApi);
2540 fprintf(stdout, " - %s : %s (device #%d with %d ins %d outs)\n",apiInfo->name,pdi->name, i, pdi->maxInputChannels, pdi->maxOutputChannels);
2543 mDeviceInOut[0] = paNoDevice;
2544 mDeviceInOut[1] = paNoDevice;
2545 if (mWorld->hw->mInDeviceName)
2546 GetPaDeviceFromName(mWorld->hw->mInDeviceName, mDeviceInOut);
2547 if (mDeviceInOut[0] == paNoDevice) mDeviceInOut[0] = Pa_GetDefaultInputDevice();
2548 if (mDeviceInOut[1] == paNoDevice) mDeviceInOut[1] = Pa_GetDefaultOutputDevice();
2550 *outNumSamples = mWorld->mBufLength;
2551 if (mPreferredSampleRate)
2552 *outSampleRate = mPreferredSampleRate;
2553 else
2554 *outSampleRate = 44100.;
2557 if (mDeviceInOut[0]!=paNoDevice && mDeviceInOut[1]!=paNoDevice) {
2559 if (mPreferredHardwareBufferFrameSize)
2560 // controls the suggested latency by hardwareBufferSize switch -Z
2561 suggestedLatencyIn = suggestedLatencyOut = mPreferredHardwareBufferFrameSize / (*outSampleRate);
2562 else {
2563 suggestedLatencyIn = Pa_GetDeviceInfo( mDeviceInOut[0] )->defaultLowInputLatency;
2564 suggestedLatencyOut = Pa_GetDeviceInfo( mDeviceInOut[1] )->defaultLowOutputLatency;
2567 PaSampleFormat fmt = paFloat32 | paNonInterleaved;
2568 mInputChannelCount = Pa_GetDeviceInfo( mDeviceInOut[0] )->maxInputChannels;
2569 mOutputChannelCount = Pa_GetDeviceInfo( mDeviceInOut[1] )->maxOutputChannels;
2570 fprintf(stdout, "\nBooting with:\n In: %s : %s \n",
2571 Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[0] )->hostApi)->name,
2572 Pa_GetDeviceInfo( mDeviceInOut[0] )->name);
2573 fprintf(stdout, " Out: %s : %s \n",
2574 Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[1] )->hostApi)->name,
2575 Pa_GetDeviceInfo( mDeviceInOut[1] )->name);
2577 PaStreamParameters inStreamParams;
2578 inStreamParams.device = mDeviceInOut[0];
2579 inStreamParams.channelCount = mInputChannelCount;
2580 inStreamParams.sampleFormat = fmt;
2581 inStreamParams.suggestedLatency = suggestedLatencyIn;
2582 inStreamParams.hostApiSpecificStreamInfo = NULL;
2584 PaStreamParameters outStreamParams;
2585 outStreamParams.device = mDeviceInOut[1];
2586 outStreamParams.channelCount = mOutputChannelCount;
2587 outStreamParams.sampleFormat = fmt;
2588 outStreamParams.suggestedLatency = suggestedLatencyOut;
2589 outStreamParams.hostApiSpecificStreamInfo = NULL;
2591 paerror = Pa_OpenStream(&mStream, &inStreamParams, &outStreamParams, *outSampleRate, *outNumSamples, paNoFlag, SC_PortAudioStreamCallback, this );
2592 if( paerror != paNoError )
2593 PRINT_PORTAUDIO_ERROR( Pa_OpenStream, paerror );
2594 else {
2595 psi = Pa_GetStreamInfo(mStream);
2596 if (!psi)
2597 fprintf(stdout," Could not obtain further info from portaudio stream\n");
2598 else {
2599 fprintf(stdout," Sample rate: %.3f\n", psi->sampleRate);
2600 fprintf(stdout," Latency (in/out): %.3f / %.3f sec\n", psi->inputLatency, psi->outputLatency);
2603 return paerror == paNoError;
2606 // should not be necessary, but a last try with OpenDefaultStream...
2607 paerror = Pa_OpenDefaultStream( &mStream, 2, 2,
2608 paFloat32 | paNonInterleaved, *outSampleRate, *outNumSamples, SC_PortAudioStreamCallback, this );
2609 if( paerror != paNoError )
2610 PRINT_PORTAUDIO_ERROR( Pa_OpenDefaultStream, paerror );
2611 return paerror == paNoError;
2614 bool SC_PortAudioDriver::DriverStart()
2616 if (!mStream)
2617 return false;
2619 PaError paerror = Pa_StartStream( mStream );
2620 if( paerror != paNoError )
2621 PRINT_PORTAUDIO_ERROR( Pa_StartStream, paerror );
2623 // sync times
2624 mPaStreamStartupTimeOSC = 0;
2625 mPaStreamStartupTime = 0;
2626 // it would be better to do the sync here, but the timeInfo in the callback is incomplete
2627 //mPaStreamStartupTimeOSC = GetCurrentOSCTime();
2628 //mPaStreamStartupTime = Pa_GetStreamTime(mStream);
2630 return paerror == paNoError;
2633 bool SC_PortAudioDriver::DriverStop()
2635 if (!mStream)
2636 return false;
2638 PaError paerror = Pa_StopStream(mStream);
2639 if( paerror != paNoError )
2640 PRINT_PORTAUDIO_ERROR( Pa_StopStream, paerror );
2642 return paerror == paNoError;
2645 #endif // SC_AUDIO_API_PORTAUDIO
2648 #if SC_AUDIO_API == SC_AUDIO_API_INNERSC_VST
2650 // =====================================================================
2651 // SC_VSTAudioDriver (VST)
2654 SC_VSTAudioDriver::SC_VSTAudioDriver(struct World *inWorld)
2655 : SC_AudioDriver(inWorld)
2657 mIsStreaming = false;
2658 // init big rsrc
2661 SC_VSTAudioDriver::~SC_VSTAudioDriver()
2663 // close small rsrc (stream)
2664 // close big rsrc
2667 void SC_VSTAudioDriver::Callback( const void *input, void *output,
2668 unsigned long frameCount, const VstTimeInfo* timeInfo )
2670 World *world = mWorld;
2672 // (void) frameCount, timeInfo, statusFlags; // suppress unused parameter warnings
2674 try {
2675 int64 oscTime = 0; // $$$todo FIXME -> PortAudioTimeToHostTime( mStream, timeInfo.outputBufferDacTime );
2676 mOSCbuftime = oscTime;
2678 mFromEngine.Free();
2679 mToEngine.Perform();
2680 mOscPacketsToEngine.Perform();
2682 int numInputs = mInputChannelCount;
2683 int numOutputs = mOutputChannelCount;
2684 const float **inBuffers = (const float**)input;
2685 float **outBuffers = (float**)output;
2687 int numSamples = NumSamplesPerCallback();
2688 int bufFrames = mWorld->mBufLength;
2689 int numBufs = numSamples / bufFrames;
2691 float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
2692 float *outBuses = mWorld->mAudioBus;
2693 int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
2694 int32 *outTouched = mWorld->mAudioBusTouched;
2696 int minInputs = std::min<size_t>(numInputs, mWorld->mNumInputs);
2697 int minOutputs = std::min<size_t>(numOutputs, mWorld->mNumOutputs);
2699 int bufFramePos = 0;
2701 int64 oscInc = mOSCincrement;
2702 double oscToSamples = mOSCtoSamples;
2704 // main loop
2705 for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames) {
2706 int32 bufCounter = mWorld->mBufCounter;
2707 int32 *tch;
2708 // copy+touch inputs
2709 tch = inTouched;
2710 for (int k = 0; k < minInputs; ++k) {
2711 const float *src = inBuffers[k] + bufFramePos;
2712 float *dst = inBuses + k * bufFrames;
2713 for (int n = 0; n < bufFrames; ++n)
2714 *dst++ = *src++;
2715 *tch++ = bufCounter;
2717 // run engine
2718 //int64 schedTime;
2719 //int64 nextTime = oscTime + oscInc;
2720 //while ((schedTime = mScheduler.NextTime()) <= nextTime) {
2721 // world->mSampleOffset = (int)((double)(schedTime - oscTime) * oscToSamples);
2722 // SC_ScheduledEvent event = mScheduler.Remove();
2723 // event.Perform();
2724 // world->mSampleOffset = 0;
2726 // hack for now, schedule events as soon as they arrive
2728 int64 schedTime;
2729 int64 nextTime = oscTime + oscInc;
2730 while ((schedTime = mScheduler.NextTime()) != kMaxInt64) {
2731 world->mSampleOffset = 0;
2732 SC_ScheduledEvent event = mScheduler.Remove();
2733 event.Perform();
2734 world->mSampleOffset = 0;
2736 World_Run(world);
2737 // copy touched outputs
2738 tch = outTouched;
2739 for (int k = 0; k < minOutputs; ++k) {
2740 float *dst = outBuffers[k] + bufFramePos;
2741 if (*tch++ == bufCounter) {
2742 float *src = outBuses + k * bufFrames;
2743 for (int n = 0; n < bufFrames; ++n)
2744 *dst++ = *src++;
2746 else {
2747 for (int n = 0; n < bufFrames; ++n)
2748 *dst++ = 0.0f;
2751 // update buffer time
2752 mOSCbuftime = nextTime;
2754 } catch (std::exception& exc) {
2755 scprintf("SC_PortAudioDriver: exception in real time: %s\n", exc.what());
2756 } catch (...) {
2757 scprintf("SC_PortAudioDriver: unknown exception in real time\n");
2760 //double cpuUsage = (double)Pa_GetStreamCpuLoad(mStream);
2761 double cpuUsage = 0.0; // $$$todo fix fix. user will check load in host
2762 mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
2763 if (cpuUsage > mPeakCPU || --mPeakCounter <= 0)
2765 mPeakCPU = cpuUsage;
2766 mPeakCounter = mMaxPeakCounter;
2768 mAudioSync.Signal();
2769 //return paContinue;
2773 // ====================================================================
2774 // NOTE: for now, in lieu of a mechanism that passes generic options to
2775 // the platform driver, we rely on the PortAudio default device environment variables
2776 bool SC_VSTAudioDriver::DriverSetup(int* outNumSamples, double* outSampleRate)
2778 // should init the driver and write the num of samples per callback
2779 // and the sample rate in the supplied addresses
2781 // this should open the resources (and return true if successful), but not
2782 // really start the streaming... (this is the resp of DriverStart())
2783 return true;
2786 bool SC_VSTAudioDriver::DriverStart()
2788 return true;
2791 bool SC_VSTAudioDriver::DriverStop()
2793 mIsStreaming = false;
2794 return true;
2797 int32 server_timeseed()
2799 static int32 count = 0;
2800 struct timeval tv;
2801 double us = timeGetTime( )*1000;
2802 int sec = us/1000000;
2803 int usec = us-sec*1000000;
2804 return (int32)sec ^ (int32)usec ^ count--;
2807 static inline int64 GetCurrentOSCTime()
2809 #pragma message("check where GetCurrentOSCTime( ) is called and try to defer that somewhere where VstTimeInfo is available")
2810 //$$$todo fixme
2811 return 0;
2815 int64 oscTimeNow()
2817 return GetCurrentOSCTime();
2820 void initializeScheduler()
2824 #endif // SC_AUDIO_API_INNERSC_VST