CSL  6.0
iphoneIO.cpp
Go to the documentation of this file.
1 //
2 // iphoneIO.cpp -- DAC IO using CoreAudio for the iphone
3 // Abstract AUIO class and concrete CAIO class
4 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
5 //
6 
7 #include "iphoneIO.h"
8 
9 using namespace csl;
10 
11 //float maxSampEver = 0.0f;
12 //extern float maxSampEver;
13 
14 #define CHECK_SAMP(sam) \
15  if (fabs(*sam) > maxSampEver) \
16  maxSampEver = fabs(*sam);
17 
18 // This callback routine will be called by CoreAudio/AudioUnits
19 
20 static OSStatus RenderCallback(void * userData, AudioUnitRenderActionFlags * ioActionFlags,
21  const AudioTimeStamp * inTimeStamp, UInt32 inOutputBusNumber,
22  UInt32 inNumberFrames, AudioBufferList * ioData) {
23  AUIO * auio = (AUIO *) userData; // cast uder data ptr
24  unsigned numChannels = ioData->buffer(0].mNumberChannels; // interleaved buffers
25  Buffer * auBuffer = &auio->mOutputBuffer; // temp buffer for passing ptrs to CSL
26 
27  if ( ! auio->mGraph) // if graph not set
28  return noErr;
29 
30  auBuffer->mNumChannels = numChannels; // set up buffer
31  auBuffer->mNumFrames = inNumberFrames;
32 
33  auio->pullInput(*auBuffer); ////// get data from the DSP graph //////
34 
35  auio->mNumFramesPlayed += inNumberFrames;
36 
37  sample * samp = auBuffer->buffer(0]; // src buffer ptr
38  SInt16 * outData = (SInt16 *) ioData->buffer(0].mData; // output ptr
39  SInt16 final;
40  if (numChannels == 1) { // mono case
41  for (unsigned i = 0; i < inNumberFrames; i++) { // output copy loop
42  final = (SInt16) (*samp++ * 32768.0f);
43  *outData++ = final;
44  }
45  } else { // stereo case; interleave samples
46  sample * samp2 = auBuffer->buffer(1]; // other channel
47  for (unsigned i = 0; i < inNumberFrames; i++) {
48 // CHECK_SAMP(samp)
49  final = (SInt16) (*samp++ * 32767.0f);
50  *outData++ = final;
51 // CHECK_SAMP(samp2)
52  final = (SInt16) (*samp2++ * 32767.0f);
53  *outData++ = final;
54  }
55  }
56  return noErr;
57 }
58 
59 // AUIO Constructors
60 
61 AUIO :: AUIO() : IO() {
62  mOutputBuffer.setSize(2, CGestalt::maxBufferFrames()); // allocate extra just for sure
63  mOutputBuffer.allocateBuffers();
64 }
65 
66 AUIO :: AUIO(unsigned s_rate, unsigned b_size, int in_device, int out_device,
67  unsigned in_chans, unsigned out_chans)
68 : IO(s_rate, b_size, in_device, out_device, in_chans, out_chans) {
69  mOutputBuffer.setSize(2, CGestalt::maxBufferFrames()); // allocate extra just for sure
70  mOutputBuffer.allocateBuffers();
71 }
72 
73 AUIO :: ~AUIO() { }
74 
75 void AUIO :: handleError(OSStatus err) throw(CException) {
76  logMsg(kLogError, "An error occured while using the AudioUnit");
77  logMsg(kLogError, "Error number: %d", (int) err);
78  throw IOError("AUIO error");
79 }
80 
81 // Open
82 
83 void AUIO :: open() throw(CException) { }
84 
85 // Start/stop plugs in the callback function
86 
87 void AUIO :: start() throw(CException) {
88  mNumFramesPlayed = 0;
89 #ifdef DO_TIMING
90  mThisSec = mTimeVals = mTimeSum = 0;
91 #endif
92  OSStatus result;
93  AURenderCallbackStruct renderCallback;
94 
95  renderCallback.inputProc = RenderCallback;
96  renderCallback.inputProcRefCon = this;
97  // plug in the audio renderer callback
98  result = AudioUnitSetProperty (mAudioUnit, kAudioUnitProperty_SetRenderCallback,
99  kAudioUnitScope_Input, 0, &renderCallback, sizeof(renderCallback));
100  if (noErr != result)
101  handleError(result);
102 }
103 
104 void AUIO :: stop() throw(CException) {
105  OSStatus result;
106  AURenderCallbackStruct renderCallback;
107 
108  renderCallback.inputProc = NULL; //clear the callback pointer
109  renderCallback.inputProcRefCon = this;
110 
111  result = AudioUnitSetProperty (mAudioUnit, kAudioUnitProperty_SetRenderCallback,
112  kAudioUnitScope_Input, 0, &renderCallback, sizeof(renderCallback));
113  if (noErr != result)
114  handleError(result);
115 }
116 
117 // Close -- don't need to do anything
118 
119 void AUIO :: close() throw(CException) { }
120 
121 // Answer the most recent input buffer
122 
123 Buffer & AUIO :: getInput() throw(CException) {
125 }
126 
127 // really get the desired format of input
128 
129 Buffer & AUIO :: getInput(unsigned numFrames, unsigned numChannels) throw(CException) {
130  if (mNumInChannels == 0)
131  throw IOError("Can't get unopened input");
132  mInputBuffer.mIsPopulated = true;
133  return(mInputBuffer);
134 }
135 
136 /////////////////////// iPhoneIO IO /////////////////////////////////
137 
138 // Constructor creates input/output device list
139 
140 extern vector < IODevice *> gIODevices; // Global list of all known IO devices
141 
142 // iphoneIO constructor -- verbose version loads a table of the iphoneIO devices
143 
145 
146 // this version is not used
147 
148 iPhoneIO :: iPhoneIO(unsigned s_rate, unsigned b_size,
149  int in_device, int out_device, unsigned in_chans, unsigned out_chans)
150  : AUIO(s_rate, b_size, in_device, out_device, in_chans, out_chans) {
151 // if (gIODevices.empty()) { // if we've never set up before
152 // IODevice * newDev = new IODevice("iPhoneIO", 0, 1, 2, true, true);
153 // newDev->mFrameRate = 44100;
154 // gIODevices.push_back(newDev); // push onto global list
155 // newDev->dump();
156 // } else {
157 // for (unsigned i = 0; i < gIODevices.size(); i++)
158 // gIODevices[i]->dump();
159 // }
160 }
161 
163 
164 // Error function
165 
166 void iPhoneIO :: handleError(OSStatus result) throw(CException) {
167  AudioUnitUninitialize(mAudioUnit);
168  AUIO::handleError(result);
169 }
170 
171 // Open sets up iPhoneIO
172 
173 void iPhoneIO :: open() throw(CException) { // Get the output audio unit
174  OSStatus result = noErr;
175  AudioComponentDescription desc;
176  desc.componentType = kAudioUnitType_Output; // set up the component description
177  // kAudioUnitType_Output = kAudioFormatFlagIsSignedInteger
178  // + kAudioFormatFlagIsPacked + kAudioFormatFlagIsNonInterleaved
179  // + (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift)
180  desc.componentSubType = kAudioUnitSubType_RemoteIO;
181  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
182  desc.componentFlags = 0;
183  desc.componentFlagsMask = 0;
184  // find a component
185  AudioComponent comp = AudioComponentFindNext(NULL, &desc);
186  if (comp == NULL) { // check it
187  logMsg(kLogError, "An error occured while finding the AudioUnit default output\n");
188  throw IOError("CoreAudio error in AudioComponentFindNext");
189  }
190  result = AudioComponentInstanceNew(comp, &mAudioUnit); // open it up
191  if (noErr != result)
192  handleError(result);
193 
194  result = AudioUnitInitialize(mAudioUnit); // AU init it
195  if (noErr != result)
196  handleError(result);
197 
198  AudioStreamBasicDescription audioFormat;
199  audioFormat.mSampleRate = (Float64) CGestalt::frameRate(); // FS
200  audioFormat.mFormatID = kAudioFormatLinearPCM;
201  audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
202  audioFormat.mFramesPerPacket = 1;
203  audioFormat.mChannelsPerFrame = 2; // stereo
204  audioFormat.mBitsPerChannel = 16; // 16-bit
205  audioFormat.mBytesPerPacket = 4;
206  audioFormat.mBytesPerFrame = 4;
207 
208  result = AudioUnitSetProperty(mAudioUnit,
209  kAudioUnitProperty_StreamFormat,
210  kAudioUnitScope_Output,
211  0,
212  &audioFormat,
213  sizeof(audioFormat));
214  if (noErr != result)
215  handleError(result);
216 
217 // result = AudioUnitInitialize (mAudioUnit); // AU init it
218 // if (noErr != result)
219 // handleError(result);
220 
221  AUIO::open(); // AU open
222 // logMsg("AUIO::open OK");
223 
224  // Initialize and configure the audio session
225  AudioSessionInitialize(NULL, NULL, NULL, this);
226 
227  // set the audio category
228  UInt32 audioCategory = kAudioSessionCategory_LiveAudio;
229  AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
230  UInt32 getAudioCategory = sizeof(audioCategory);
231  AudioSessionGetProperty(kAudioSessionProperty_AudioCategory, &getAudioCategory, &getAudioCategory);
232 
233  // set block rate
234  Float32 preferredBufferSize = (float) CGestalt::blockSize() / (float) CGestalt::frameRate();
235 
236  AudioSessionSetProperty (kAudioSessionProperty_PreferredHardwareIOBufferDuration,
237  sizeof(preferredBufferSize), &preferredBufferSize);
238 
239  // set the audio session active
240  AudioSessionSetActive(true);
241 
242  // ask whether we support stereo output
243 // UInt32 numOutputChannels;
244 // UInt32 dataSize = sizeof(UInt32);
245 // result = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels,
246 // & dataSize, & numOutputChannels);
247 // logMsg("AudioUnit outputs: %d\n", numOutputChannels);
248 }
249 
250 void iPhoneIO :: start() throw(CException) {
251  AUIO::start();
252  OSStatus result = AudioOutputUnitStart(mAudioUnit); // Start 'er up!
253  if (noErr != result)
254  handleError(result);
255  logMsg("iPhoneIO :: start");
256 }
257 
258 void iPhoneIO :: stop() throw(CException) {
259  AUIO::stop();
260  OSStatus result = AudioOutputUnitStop(mAudioUnit);
261  if (noErr != result)
262  handleError(result);
263  logMsg("iPhoneIO :: stop");
264 }
265 
266 void iPhoneIO :: close() throw(CException) {
267  AudioUnitUninitialize(mAudioUnit);
268  //CloseComponent(mAudioUnit);
269  AUIO::close();
270 }
void logMsg(const char *format,...)
These are the public logging messages.
Definition: CGestalt.cpp:292
long mTimeSum
for printing run-time statistics
Definition: CSL_Core.h:797
unsigned mNumFrames
num frames used in each buffer
Definition: CSL_Core.h:113
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Definition: Accessor.h:17
void pullInput(Buffer &outBuffer, SampleBuffer out=0)
get a buffer from the CSL graph
Definition: CSL_Core.cpp:1425
void handleError(OSStatus result)
Definition: iphoneIO.cpp:166
virtual SampleBuffer buffer(unsigned bufNum)
convenience accessors for sample buffers
Definition: CSL_Core.cpp:66
AUIO()
Definition: CAIO.cpp:33
virtual void start()
Definition: CAIO.cpp:65
void open()
open/close start/stop methods
Definition: iphoneIO.cpp:173
UnitGenerator * mGraph
the root of my client DSP graph, often a mixer or panner
Definition: CSL_Core.h:777
static unsigned blockSize()
the default block size
Definition: CGestalt.cpp:57
unsigned mNumChannels
num channels in buffer (num mono buffers)
Definition: CSL_Core.h:112
virtual void close()
open/close start/stop methods
Definition: CAIO.cpp:75
float sample
(could be changed to int, or double)
Definition: CSL_Types.h:191
virtual void stop()
Definition: CAIO.cpp:69
IO – the abstract I/O scheduling class; subclasses interface to specific I/O APIs.
Definition: CSL_Core.h:752
AudioUnit mAudioUnit
Definition: CAIO.h:37
static unsigned frameRate()
default frame rate
Definition: CGestalt.cpp:51
static OSStatus RenderCallback(void *userData, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
Definition: iphoneIO.cpp:20
void start()
Definition: iphoneIO.cpp:250
long mThisSec
Definition: CSL_Core.h:797
void close()
open/close start/stop methods
Definition: iphoneIO.cpp:266
unsigned mNumFramesPlayed
counter of frames I've played
Definition: CSL_Core.h:784
static unsigned mNumInChannels
The actual start-up values are defined in CSL_Types.h.
Definition: CGestalt.cpp:29
IO Error.
virtual void open()
open/close start/stop methods
Definition: CAIO.cpp:48
void handleError(OSStatus result)
Definition: CAIO.cpp:40
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
Definition: CSL_Core.h:106
Buffer mOutputBuffer
the output buffer I use (passed to nextBuffer calls)
Definition: CSL_Core.h:779
Buffer mInputBuffer
the most recent input buffer (if it's turned on)
Definition: CSL_Core.h:778
virtual Buffer & getInput()
get the current input buffer
Definition: CAIO.cpp:88
long mTimeVals
Definition: CSL_Core.h:797
General-purpose AudioUnit IO class.
Definition: CAIO.h:21
Base class of CSL exceptions (written upper-case). Has a string message.
vector< IODevice * > gIODevices
Definition: CSL_Core.cpp:1387