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
22 #ifndef _SC_CoreAudio_
23 #define _SC_CoreAudio_
26 #include "SC_FifoMsg.h"
27 #include "OSC_Packet.h"
28 #include "SC_SyncCondition.h"
29 #include "PriorityQueue.h"
32 #define SC_AUDIO_API_COREAUDIO 1
33 #define SC_AUDIO_API_JACK 2
34 #define SC_AUDIO_API_PORTAUDIO 3
35 #define SC_AUDIO_API_AUDIOUNITS 4
36 #define SC_AUDIO_API_COREAUDIOIPHONE 5
37 #define SC_AUDIO_API_ANDROIDJNI 6
40 #define SC_AUDIO_API SC_AUDIO_API_ANDROIDJNI
44 #define SC_AUDIO_API SC_AUDIO_API_COREAUDIOIPHONE
49 # define SC_AUDIO_API SC_AUDIO_API_PORTAUDIO
50 # elif defined(__APPLE__)
51 # define SC_AUDIO_API SC_AUDIO_API_COREAUDIO
53 # error SC_AUDIO_API undefined, cannot determine audio backend
55 #endif // SC_AUDIO_API
57 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
58 # include <CoreAudio/AudioHardware.h>
59 # include <CoreAudio/HostTime.h>
62 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
63 #include <AudioUnit/AudioUnit.h>
64 #include <AudioToolbox/AudioToolbox.h>
65 #include <AudioToolbox/AudioConverter.h>
66 #include <AudioToolbox/AUGraph.h>
70 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
71 #include "portaudio.h"
74 const double kSecondsToOSCunits
= 4294967296.; // pow(2,32)
75 const double kMicrosToOSCunits
= 4294.967296; // pow(2,32)/1e6
76 const double kNanosToOSCunits
= 4.294967296; // pow(2,32)/1e9
78 const int32 kSECONDS_FROM_1900_to_1970
= (int32
)2208988800UL; /* 17 leap years */
79 const double kOSCtoSecs
= 2.328306436538696e-10;
81 struct SC_ScheduledEvent
83 /// Callback function responsible for freeing the OSC packet in the correct thread.
84 typedef void (*PacketFreeFunc
)(struct World
* world
, OSC_Packet
* packet
);
86 /// Frees an OSC packet in the realtime thread (to be used as a PacketFreeFunc).
87 static void FreeInRT(struct World
* world
, OSC_Packet
* packet
);
88 /// Frees an OSC packet in the non-realtime thread (to be used as a PacketFreeFunc).
89 static void FreeInNRT(struct World
* world
, OSC_Packet
* packet
);
91 SC_ScheduledEvent() : mTime(0), mPacket(0) {}
92 SC_ScheduledEvent(struct World
*inWorld
, int64 inTime
, OSC_Packet
*inPacket
, PacketFreeFunc freeFunc
)
93 : mTime(inTime
), mPacket(inPacket
), mPacketFreeFunc(freeFunc
), mWorld(inWorld
) {}
95 int64
Time() { return mTime
; }
100 PacketFreeFunc mPacketFreeFunc
;
101 struct World
*mWorld
;
104 typedef MsgFifo
<FifoMsg
, 1024> EngineFifo
;
106 // Functions to be implemented by the driver backend
108 int32
server_timeseed();
112 void initializeScheduler();
114 /** Denotes whether an OSC packet has been performed immediately or has been scheduled for later execution.
116 If the package has been scheduled, memory ownership is transferred from the caller to the scheduler.
124 /** Perform a completion message in the realtime thread.
126 The return value denotes whether ownership is transferred to the scheduler or not.
128 PacketStatus
PerformCompletionMsg(World
*world
, const OSC_Packet
& packet
);
134 struct World
*mWorld
;
135 double mOSCtoSamples
;
139 uint32 mHardwareBufferSize
; // bufferSize returned by kAudioDevicePropertyBufferSize
140 EngineFifo mFromEngine
, mToEngine
;
141 EngineFifo mOscPacketsToEngine
;
142 SC_SyncCondition mAudioSync
;
145 uint32 mSafetyOffset
;
146 PriorityQueueT
<SC_ScheduledEvent
, 2048> mScheduler
;
147 int mNumSamplesPerCallback
;
148 uint32 mPreferredHardwareBufferFrameSize
;
149 uint32 mPreferredSampleRate
;
150 double mBuffersPerSecond
;
151 double mAvgCPU
, mPeakCPU
;
152 int mPeakCounter
, mMaxPeakCounter
;
153 double mOSCincrementNumerator
;
155 double mStartHostSecs
;
156 double mPrevHostSecs
;
157 double mStartSampleTime
;
158 double mPrevSampleTime
;
159 double mSmoothSampleRate
;
162 // Driver interface methods, implemented by subclasses
164 * DriverSetup() should init the driver and write the num of samples per callback
165 * and the sample rate into the two addresses supplied as arguments.
166 * The driver will have access to the "preferred" values of these two args
167 * (mPreferredHardwareBufferFrameSize, mPreferredSampleRate) and ideally should follow them.
168 * This method should open the resources (and return true if successful), but shouldn't
169 * really start the streaming (this is the responsibility of DriverStart()).
171 virtual bool DriverSetup(int* outNumSamplesPerCallback
, double* outSampleRate
) = 0;
173 * Start the audio streaming. Return true iff successful.
175 virtual bool DriverStart() = 0;
177 * Stop the audio streaming. Return true iff successful.
179 virtual bool DriverStop() = 0;
183 SC_AudioDriver(struct World
*inWorld
);
184 virtual ~SC_AudioDriver();
192 void ClearSched() { mScheduler
.Empty(); }
194 void RunNonRealTime(float *in
, float *out
, int numSamples
, int64 oscTime
);
197 int SafetyOffset() const { return mSafetyOffset
; }
198 int NumSamplesPerCallback() const { return mNumSamplesPerCallback
; }
199 void SetPreferredHardwareBufferFrameSize(int inSize
)
201 mPreferredHardwareBufferFrameSize
= inSize
;
203 void SetPreferredSampleRate(int inRate
)
205 mPreferredSampleRate
= inRate
;
208 bool SendMsgToEngine(FifoMsg
& inMsg
); // called by NRT thread
209 bool SendMsgFromEngine(FifoMsg
& inMsg
);
210 bool SendOscPacketMsgToEngine(FifoMsg
& inMsg
); // called by OSC socket listener threads, protected by mWorld->mDriverLock
212 void AddEvent(SC_ScheduledEvent
& event
) { mScheduler
.Add(event
); }
214 double GetAvgCPU() const { return mAvgCPU
; }
215 double GetPeakCPU() const { return mPeakCPU
; }
216 double GetSampleRate() const { return mSampleRate
; }
217 double GetActualSampleRate() const { return mSmoothSampleRate
; }
220 extern SC_AudioDriver
* SC_NewAudioDriver(struct World
* inWorld
);
223 // the following classes should be split out into separate source files.
224 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
225 class SC_CoreAudioDriver
: public SC_AudioDriver
228 AudioBufferList
* mInputBufList
;
229 AudioDeviceID mInputDevice
;
230 AudioDeviceID mOutputDevice
;
232 AudioStreamBasicDescription inputStreamDesc
; // info about the default device
233 AudioStreamBasicDescription outputStreamDesc
; // info about the default device
235 friend OSStatus
appIOProc ( AudioDeviceID inDevice
,
236 const AudioTimeStamp
* inNow
,
237 const AudioBufferList
* inInputData
,
238 const AudioTimeStamp
* inInputTime
,
239 AudioBufferList
* outOutputData
,
240 const AudioTimeStamp
* inOutputTime
,
243 friend OSStatus
appIOProcSeparateIn (AudioDeviceID device
, const AudioTimeStamp
* inNow
,
244 const AudioBufferList
* inInputData
,
245 const AudioTimeStamp
* inInputTime
,
246 AudioBufferList
* outOutputData
,
247 const AudioTimeStamp
* inOutputTime
,
251 // Driver interface methods
252 virtual bool DriverSetup(int* outNumSamplesPerCallback
, double* outSampleRate
);
253 virtual bool DriverStart();
254 virtual bool DriverStop();
256 AudioDeviceIOProcID mOutputID
;
257 AudioDeviceIOProcID mInputID
;
260 int builtinoutputflag_
;
262 SC_CoreAudioDriver(struct World
*inWorld
);
263 virtual ~SC_CoreAudioDriver();
267 void Run(const AudioBufferList
* inInputData
, AudioBufferList
* outOutputData
, int64 oscTime
);
269 bool UseInput() { return mInputDevice
!= kAudioDeviceUnknown
; }
270 bool UseSeparateIO() { return UseInput() && mInputDevice
!= mOutputDevice
; }
271 AudioDeviceID
InputDevice() { return mInputDevice
; }
272 AudioDeviceID
OutputDevice() { return mOutputDevice
; }
274 void SetInputBufferList(AudioBufferList
* inBufList
) { mInputBufList
= inBufList
; }
275 AudioBufferList
* GetInputBufferList() const { return mInputBufList
; }
280 #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE
281 class SC_iCoreAudioDriver
: public SC_AudioDriver
285 AudioStreamBasicDescription inputStreamDesc
; // info about the default device
286 AudioStreamBasicDescription outputStreamDesc
; // info about the default device
289 // Driver interface methods
290 virtual bool DriverSetup(int* outNumSamplesPerCallback
, double* outSampleRate
);
291 virtual bool DriverStart();
292 virtual bool DriverStop();
295 SC_iCoreAudioDriver(struct World
*inWorld
);
296 virtual ~SC_iCoreAudioDriver();
298 void Run(const AudioBufferList
* inInputData
, AudioBufferList
* outOutputData
, int64 oscTime
);
300 AudioBufferList
* buflist
;
301 AudioBufferList
* floatInputList
;
302 AudioBufferList
* floatOutputList
;
303 AudioConverterRef converter_in_to_F32
;
304 AudioConverterRef converter_F32_to_out
;
305 AudioConverterRef converter_in_to_out
;
306 int *converter_buffer
;
314 inline SC_AudioDriver
* SC_NewAudioDriver(struct World
*inWorld
)
316 return new SC_iCoreAudioDriver(inWorld
);
318 #endif // SC_AUDIO_API_COREAUDIOIPHONE
321 #if SC_AUDIO_API == SC_AUDIO_API_PORTAUDIO
322 class SC_PortAudioDriver
: public SC_AudioDriver
325 int mInputChannelCount
, mOutputChannelCount
;
327 PaTime mPaStreamStartupTime
;
328 int64 mPaStreamStartupTimeOSC
;
331 // Driver interface methods
332 virtual bool DriverSetup(int* outNumSamplesPerCallback
, double* outSampleRate
);
333 virtual bool DriverStart();
334 virtual bool DriverStop();
337 SC_PortAudioDriver(struct World
*inWorld
);
338 virtual ~SC_PortAudioDriver();
340 int PortAudioCallback( const void *input
, void *output
,
341 unsigned long frameCount
, const PaStreamCallbackTimeInfo
* timeInfo
,
342 PaStreamCallbackFlags statusFlags
);
344 void GetPaDeviceFromName(const char* device
, int* mInOut
);
347 inline SC_AudioDriver
* SC_NewAudioDriver(struct World
*inWorld
)
349 return new SC_PortAudioDriver(inWorld
);
351 #endif // SC_AUDIO_API_PORTAUDIO
353 #if SC_AUDIO_API == SC_AUDIO_API_ANDROIDJNI
355 class SC_AndroidJNIAudioDriver
: public SC_AudioDriver
360 // Driver interface methods
361 virtual bool DriverSetup(int* outNumSamplesPerCallback
, double* outSampleRate
);
362 virtual bool DriverStart();
363 virtual bool DriverStop();
366 SC_AndroidJNIAudioDriver(struct World
*inWorld
);
367 virtual ~SC_AndroidJNIAudioDriver();
369 void genaudio(short* arri
, int numSamples
);
373 inline SC_AudioDriver
* SC_NewAudioDriver(struct World
*inWorld
)
375 return new SC_AndroidJNIAudioDriver(inWorld
);
378 #endif // SC_AUDIO_API == SC_AUDIO_API_ANDROIDJNI