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