kernel32: Add stub for SetThreadStackGuarantee.
[wine] / dlls / winecoreaudio.drv / audiounit.c
1 /*
2  * Wine Driver for CoreAudio / AudioUnit
3  *
4  * Copyright 2005, 2006 Emmanuel Maillard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
23 #define ULONG CoreFoundation_ULONG
24 #define HRESULT CoreFoundation_HRESULT
25 #ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
26 #include <CoreServices/CoreServices.h>
27 #endif
28 #include <AudioUnit/AudioUnit.h>
29 #include <AudioToolbox/AudioToolbox.h>
30 #undef ULONG
31 #undef HRESULT
32
33 #undef DPRINTF
34 #undef STDMETHODCALLTYPE
35 #include "coreaudio.h"
36 #include "wine/debug.h"
37
38 #ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
39 /* Define new AudioComponent Manager functions for compatibility's sake */
40 typedef Component AudioComponent;
41 typedef ComponentDescription AudioComponentDescription;
42 typedef ComponentInstance AudioComponentInstance;
43
44 static inline AudioComponent AudioComponentFindNext(AudioComponent ac, AudioComponentDescription *desc)
45 {
46     return FindNextComponent(ac, desc);
47 }
48
49 static inline OSStatus AudioComponentInstanceNew(AudioComponent ac, AudioComponentInstance *aci)
50 {
51     return OpenAComponent(ac, aci);
52 }
53
54 static inline OSStatus AudioComponentInstanceDispose(AudioComponentInstance aci)
55 {
56     return CloseComponent(aci);
57 }
58 #endif
59
60 #ifndef HAVE_AUGRAPHADDNODE
61 static inline OSStatus AUGraphAddNode(AUGraph graph, const AudioComponentDescription *desc, AUNode *node)
62 {
63     return AUGraphNewNode(graph, desc, 0, NULL, node);
64 }
65
66 static inline OSStatus AUGraphNodeInfo(AUGraph graph, AUNode node, AudioComponentDescription *desc, AudioUnit *au)
67 {
68     return AUGraphGetNodeInfo(graph, node, desc, 0, NULL, au);
69 }
70 #endif
71
72 WINE_DEFAULT_DEBUG_CHANNEL(wave);
73 WINE_DECLARE_DEBUG_CHANNEL(midi);
74
75 static const char *streamDescription(const AudioStreamBasicDescription* stream)
76 {
77     return wine_dbg_sprintf("\n mSampleRate : %f\n mFormatID : %s\n mFormatFlags : %lX\n mBytesPerPacket : %lu\n mFramesPerPacket : %lu\n mBytesPerFrame : %lu\n mChannelsPerFrame : %lu\n mBitsPerChannel : %lu\n",
78         stream->mSampleRate,
79         wine_dbgstr_fourcc(stream->mFormatID),
80         stream->mFormatFlags,
81         stream->mBytesPerPacket,
82         stream->mFramesPerPacket,
83         stream->mBytesPerFrame,
84         stream->mChannelsPerFrame,
85         stream->mBitsPerChannel);
86 }
87
88 int AudioUnit_CloseAudioUnit(AudioUnit au)
89 {
90     OSStatus err = AudioComponentInstanceDispose(au);
91     return (err == noErr);
92 }
93
94 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
95 {
96     OSStatus err = noErr;
97         
98     TRACE("input format: %s\n", streamDescription(stream));
99
100     err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
101                                 0, stream, sizeof(*stream));
102
103     if (err != noErr)
104     {
105         ERR("AudioUnitSetProperty return an error %s\n", wine_dbgstr_fourcc(err));
106         return 0;
107     }
108     
109     err = AudioUnitInitialize(au);
110     if (err != noErr)
111     {
112         ERR("AudioUnitInitialize return an error %s\n", wine_dbgstr_fourcc(err));
113         return 0;
114     }
115     return 1;
116 }
117
118 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
119 {
120     OSStatus err = noErr;
121     static int once;
122
123     if (!once++) FIXME("independent left/right volume not implemented (%f, %f)\n", left, right);
124    
125     err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
126                                 
127     if (err != noErr)
128     {
129         ERR("AudioUnitSetParameter return an error %s\n", wine_dbgstr_fourcc(err));
130         return 0;
131     }
132     return 1;
133 }
134
135 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
136 {
137     OSStatus err = noErr;
138     static int once;
139
140     if (!once++) FIXME("independent left/right volume not implemented\n");
141     
142     err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
143     if (err != noErr)
144     {
145         ERR("AudioUnitGetParameter return an error %s\n", wine_dbgstr_fourcc(err));
146         return 0;
147     }
148     *right = *left;
149     return 1;
150 }
151
152
153 /* FIXME: implement sample rate conversion on input */
154 int AudioUnit_GetInputDeviceSampleRate(void)
155 {
156     AudioDeviceID               defaultInputDevice;
157     UInt32                      param;
158     AudioObjectPropertyAddress  propertyAddress;
159     Float64                     sampleRate;
160     OSStatus                    err;
161
162     param = sizeof(defaultInputDevice);
163     propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
164     propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
165     propertyAddress.mElement = kAudioObjectPropertyElementMaster;
166     err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &param, &defaultInputDevice);
167     if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
168     {
169         ERR("Couldn't get the default audio input device ID: %08lx\n", err);
170         return 0;
171     }
172
173     param = sizeof(sampleRate);
174     propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
175     propertyAddress.mScope = kAudioDevicePropertyScopeInput;
176     err = AudioObjectGetPropertyData(defaultInputDevice, &propertyAddress, 0, NULL, &param, &sampleRate);
177     if (err != noErr)
178     {
179         ERR("Couldn't get the device sample rate: %08lx\n", err);
180         return 0;
181     }
182
183     return sampleRate;
184 }
185
186 /*
187  *  MIDI Synth Unit
188  */
189 int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
190 {
191     OSStatus err;
192     AudioComponentDescription desc;
193     AUNode synthNode;
194     AUNode outNode;
195
196     err = NewAUGraph(graph);
197     if (err != noErr)
198     {
199         ERR_(midi)("NewAUGraph return %s\n", wine_dbgstr_fourcc(err));
200         return 0;
201     }
202
203     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
204     desc.componentFlags = 0;
205     desc.componentFlagsMask = 0;
206
207     /* create synth node */
208     desc.componentType = kAudioUnitType_MusicDevice;
209     desc.componentSubType = kAudioUnitSubType_DLSSynth;
210
211     err = AUGraphAddNode(*graph, &desc, &synthNode);
212     if (err != noErr)
213     {
214         ERR_(midi)("AUGraphAddNode cannot create synthNode : %s\n", wine_dbgstr_fourcc(err));
215         return 0;
216     }
217
218     /* create out node */
219     desc.componentType = kAudioUnitType_Output;
220     desc.componentSubType = kAudioUnitSubType_DefaultOutput;
221
222     err = AUGraphAddNode(*graph, &desc, &outNode);
223     if (err != noErr)
224     {
225         ERR_(midi)("AUGraphAddNode cannot create outNode %s\n", wine_dbgstr_fourcc(err));
226         return 0;
227     }
228
229     err = AUGraphOpen(*graph);
230     if (err != noErr)
231     {
232         ERR_(midi)("AUGraphOpen return %s\n", wine_dbgstr_fourcc(err));
233         return 0;
234     }
235
236     /* connecting the nodes */
237     err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
238     if (err != noErr)
239     {
240         ERR_(midi)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n", wine_dbgstr_fourcc(err));
241         return 0;
242     }
243
244     /* Get the synth unit */
245     err = AUGraphNodeInfo(*graph, synthNode, 0, synth);
246     if (err != noErr)
247     {
248         ERR_(midi)("AUGraphNodeInfo return %s\n", wine_dbgstr_fourcc(err));
249         return 0;
250     }
251
252     return 1;
253 }
254
255 int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
256 {
257     OSStatus err = noErr;
258
259     err = AUGraphInitialize(graph);
260     if (err != noErr)
261     {
262         ERR_(midi)("AUGraphInitialize(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
263         return 0;
264     }
265
266     err = AUGraphStart(graph);
267     if (err != noErr)
268     {
269         ERR_(midi)("AUGraphStart(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
270         return 0;
271     }
272
273     return 1;
274 }
275
276 int SynthUnit_Close(AUGraph graph)
277 {
278     OSStatus err = noErr;
279
280     err = AUGraphStop(graph);
281     if (err != noErr)
282     {
283         ERR_(midi)("AUGraphStop(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
284         return 0;
285     }
286
287     err = DisposeAUGraph(graph);
288     if (err != noErr)
289     {
290         ERR_(midi)("DisposeAUGraph(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
291         return 0;
292     }
293
294     return 1;
295 }