ntdll: Add a raise_status function and avoid exporting __regs_RtlRaiseException.
[wine/multimedia.git] / dlls / winecoreaudio.drv / audiounit.c
blob08e260720937f3b0afe761e620494c3b19398053
1 /*
2 * Wine Driver for CoreAudio / AudioUnit
4 * Copyright 2005, 2006 Emmanuel Maillard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H
25 #include <AudioUnit/AudioUnit.h>
26 #include <AudioToolbox/AudioToolbox.h>
28 #undef DPRINTF
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wave);
32 WINE_DECLARE_DEBUG_CHANNEL(midi);
34 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon,
35 AudioUnitRenderActionFlags *ioActionFlags,
36 const AudioTimeStamp *inTimeStamp,
37 UInt32 inBusNumber,
38 UInt32 inNumberFrames,
39 AudioBufferList *ioData);
41 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
42 AudioUnitRenderActionFlags *ioActionFlags,
43 const AudioTimeStamp *inTimeStamp,
44 UInt32 inBusNumber,
45 UInt32 inNumberFrames,
46 AudioBufferList *ioData);
48 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
50 OSStatus err;
51 Component comp;
52 ComponentDescription desc;
53 AURenderCallbackStruct callbackStruct;
55 desc.componentType = kAudioUnitType_Output;
56 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
57 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
58 desc.componentFlags = 0;
59 desc.componentFlagsMask = 0;
61 comp = FindNextComponent(NULL, &desc);
62 if (comp == NULL)
63 return 0;
65 err = OpenAComponent(comp, au);
66 if (comp == NULL)
67 return 0;
69 callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
70 callbackStruct.inputProcRefCon = wwo;
72 err = AudioUnitSetProperty( *au,
73 kAudioUnitProperty_SetRenderCallback,
74 kAudioUnitScope_Input,
75 0,
76 &callbackStruct,
77 sizeof(callbackStruct));
78 return (err == noErr);
81 int AudioUnit_CloseAudioUnit(AudioUnit au)
83 OSStatus err = CloseComponent(au);
84 return (err == noErr);
87 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
89 OSStatus err = noErr;
91 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
92 0, stream, sizeof(*stream));
94 if (err != noErr)
96 ERR("AudioUnitSetProperty return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
97 return 0;
100 err = AudioUnitInitialize(au);
101 if (err != noErr)
103 ERR("AudioUnitInitialize return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
104 return 0;
106 return 1;
109 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
111 OSStatus err = noErr;
113 err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
115 if (err != noErr)
117 ERR("AudioUnitSetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
118 return 0;
120 return 1;
123 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
125 OSStatus err = noErr;
127 err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
128 if (err != noErr)
130 ERR("AudioUnitGetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
131 return 0;
133 *right = *left;
134 return 1;
138 /* FIXME: implement sample rate conversion on input */
139 int AudioUnit_GetInputDeviceSampleRate(void)
141 AudioDeviceID defaultInputDevice;
142 UInt32 param;
143 Float64 sampleRate;
144 OSStatus err;
146 param = sizeof(defaultInputDevice);
147 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
148 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
150 ERR("Couldn't get the default audio input device ID: %08lx\n", err);
151 return 0;
154 param = sizeof(sampleRate);
155 err = AudioDeviceGetProperty(defaultInputDevice, 0, 1, kAudioDevicePropertyNominalSampleRate, &param, &sampleRate);
156 if (err != noErr)
158 ERR("Couldn't get the device sample rate: %08lx\n", err);
159 return 0;
162 return sampleRate;
166 int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
167 WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
168 UInt32* outFrameCount)
170 OSStatus err = noErr;
171 ComponentDescription description;
172 Component component;
173 AudioUnit au;
174 UInt32 param;
175 AURenderCallbackStruct callback;
176 AudioDeviceID defaultInputDevice;
177 AudioStreamBasicDescription desiredFormat;
180 if (!outFrameCount)
182 ERR("Invalid parameter\n");
183 return 0;
186 /* Open the AudioOutputUnit */
187 description.componentType = kAudioUnitType_Output;
188 description.componentSubType = kAudioUnitSubType_HALOutput;
189 description.componentManufacturer = kAudioUnitManufacturer_Apple;
190 description.componentFlags = 0;
191 description.componentFlagsMask = 0;
193 component = FindNextComponent(NULL, &description);
194 if (!component)
196 ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
197 return 0;
200 err = OpenAComponent(component, &au);
201 if (err != noErr || au == NULL)
203 ERR("OpenAComponent failed: %08lx\n", err);
204 return 0;
207 /* Configure the AudioOutputUnit */
208 /* The AUHAL has two buses (AKA elements). Bus 0 is output from the app
209 * to the device. Bus 1 is input from the device to the app. Each bus
210 * has two ends (AKA scopes). Data goes from the input scope to the
211 * output scope. The terminology is somewhat confusing because the terms
212 * "input" and "output" have two meanings. Here's a summary:
214 * Bus 0, input scope: refers to the source of data to be output as sound
215 * Bus 0, output scope: refers to the actual sound output device
216 * Bus 1, input scope: refers to the actual sound input device
217 * Bus 1, output scope: refers to the destination of data received by the input device
220 /* Enable input on the AUHAL */
221 param = 1;
222 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(param));
223 if (err != noErr)
225 ERR("Couldn't enable input on AUHAL: %08lx\n", err);
226 goto error;
229 /* Disable Output on the AUHAL */
230 param = 0;
231 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &param, sizeof(param));
232 if (err != noErr)
234 ERR("Couldn't disable output on AUHAL: %08lx\n", err);
235 goto error;
238 /* Find the default input device */
239 param = sizeof(defaultInputDevice);
240 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
241 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
243 ERR("Couldn't get the default audio device ID: %08lx\n", err);
244 goto error;
247 /* Set the current device to the default input device. */
248 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice));
249 if (err != noErr)
251 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
252 goto error;
255 /* Setup render callback */
256 /* This will be called when the AUHAL has input data. However, it won't
257 * be passed the data itself. The callback will have to all AudioUnitRender. */
258 callback.inputProc = CoreAudio_wiAudioUnitIOProc;
259 callback.inputProcRefCon = wwi;
260 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
261 if (err != noErr)
263 ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
264 goto error;
267 /* Setup the desired data format. */
268 /* FIXME: implement sample rate conversion on input. We shouldn't set
269 * the mSampleRate of this to the desired sample rate. We need to query
270 * the input device and use that. If they don't match, we need to set up
271 * an AUConverter to do the sample rate conversion on a separate thread. */
272 desiredFormat.mFormatID = kAudioFormatLinearPCM;
273 desiredFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
274 if (wBitsPerSample != 8)
275 desiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
276 desiredFormat.mSampleRate = nSamplesPerSec;
277 desiredFormat.mChannelsPerFrame = nChannels;
278 desiredFormat.mFramesPerPacket = 1;
279 desiredFormat.mBitsPerChannel = wBitsPerSample;
280 desiredFormat.mBytesPerFrame = desiredFormat.mBitsPerChannel * desiredFormat.mChannelsPerFrame / 8;
281 desiredFormat.mBytesPerPacket = desiredFormat.mBytesPerFrame * desiredFormat.mFramesPerPacket;
283 /* Set the AudioOutputUnit output data format */
284 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat));
285 if (err != noErr)
287 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
288 goto error;
291 /* Get the number of frames in the IO buffer(s) */
292 param = sizeof(*outFrameCount);
293 err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, outFrameCount, &param);
294 if (err != noErr)
296 ERR("Failed to get audio sample size: %08lx\n", err);
297 goto error;
300 TRACE("Frame count: %lu\n", *outFrameCount);
302 /* Initialize the AU */
303 err = AudioUnitInitialize(au);
304 if (err != noErr)
306 ERR("Failed to initialize AU: %08lx\n", err);
307 goto error;
310 *out_au = au;
312 return 1;
314 error:
315 if (au)
316 CloseComponent(au);
317 return 0;
321 * MIDI Synth Unit
323 int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
325 OSStatus err;
326 ComponentDescription desc;
327 AUNode synthNode;
328 AUNode outNode;
330 err = NewAUGraph(graph);
331 if (err != noErr)
333 ERR_(midi)("NewAUGraph return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
334 return 0;
337 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
338 desc.componentFlags = 0;
339 desc.componentFlagsMask = 0;
341 /* create synth node */
342 desc.componentType = kAudioUnitType_MusicDevice;
343 desc.componentSubType = kAudioUnitSubType_DLSSynth;
345 err = AUGraphNewNode(*graph, &desc, 0, NULL, &synthNode);
346 if (err != noErr)
348 ERR_(midi)("AUGraphNewNode cannot create synthNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
349 return 0;
352 /* create out node */
353 desc.componentType = kAudioUnitType_Output;
354 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
356 err = AUGraphNewNode(*graph, &desc, 0, NULL, &outNode);
357 if (err != noErr)
359 ERR_(midi)("AUGraphNewNode cannot create outNode %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
360 return 0;
363 err = AUGraphOpen(*graph);
364 if (err != noErr)
366 ERR_(midi)("AUGraphOpen return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
367 return 0;
370 /* connecting the nodes */
371 err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
372 if (err != noErr)
374 ERR_(midi)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
375 return 0;
378 /* Get the synth unit */
379 err = AUGraphGetNodeInfo(*graph, synthNode, 0, 0, 0, synth);
380 if (err != noErr)
382 ERR_(midi)("AUGraphGetNodeInfo return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
383 return 0;
386 return 1;
389 int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
391 OSStatus err = noErr;
393 err = AUGraphInitialize(graph);
394 if (err != noErr)
396 ERR_(midi)("AUGraphInitialize(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
397 return 0;
400 err = AUGraphStart(graph);
401 if (err != noErr)
403 ERR_(midi)("AUGraphStart(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
404 return 0;
407 return 1;
410 int SynthUnit_Close(AUGraph graph)
412 OSStatus err = noErr;
414 err = AUGraphStop(graph);
415 if (err != noErr)
417 ERR_(midi)("AUGraphStop(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
418 return 0;
421 err = DisposeAUGraph(graph);
422 if (err != noErr)
424 ERR_(midi)("DisposeAUGraph(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
425 return 0;
428 return 1;
431 #endif