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