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