blob: 6968719ff3035fe1c6e4504b1f6ca1e1ad84309a [file] [log] [blame]
Emmanuel Maillard144a5352006-05-28 22:46:23 +02001/*
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
Alexandre Julliardea501962006-06-01 13:15:54 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Emmanuel Maillard144a5352006-05-28 22:46:23 +020019 */
20
21#include "config.h"
Emmanuel Maillard144a5352006-05-28 22:46:23 +020022
Ken Thomases131a0462009-05-01 23:01:18 -050023#define ULONG CoreFoundation_ULONG
24#define HRESULT CoreFoundation_HRESULT
Charles Davis459d9422011-01-29 16:45:53 -070025#ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
Ken Thomases131a0462009-05-01 23:01:18 -050026#include <CoreServices/CoreServices.h>
Charles Davis459d9422011-01-29 16:45:53 -070027#endif
Emmanuel Maillard144a5352006-05-28 22:46:23 +020028#include <AudioUnit/AudioUnit.h>
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +020029#include <AudioToolbox/AudioToolbox.h>
Ken Thomases131a0462009-05-01 23:01:18 -050030#undef ULONG
31#undef HRESULT
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +020032
Alexandre Julliardab1040b2009-01-02 13:54:49 +010033#undef DPRINTF
Ken Thomases131a0462009-05-01 23:01:18 -050034#undef STDMETHODCALLTYPE
Ken Thomases1b5ca012009-10-11 14:11:19 -050035#include "coreaudio.h"
Andrew Talbot1d5d2372008-12-20 15:02:41 +000036#include "wine/debug.h"
37
Charles Davis459d9422011-01-29 16:45:53 -070038#ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
39/* Define new AudioComponent Manager functions for compatibility's sake */
40typedef Component AudioComponent;
41typedef ComponentDescription AudioComponentDescription;
42typedef ComponentInstance AudioComponentInstance;
43
44static inline AudioComponent AudioComponentFindNext(AudioComponent ac, AudioComponentDescription *desc)
45{
46 return FindNextComponent(ac, desc);
47}
48
49static inline OSStatus AudioComponentInstanceNew(AudioComponent ac, AudioComponentInstance *aci)
50{
51 return OpenAComponent(ac, aci);
52}
53
54static inline OSStatus AudioComponentInstanceDispose(AudioComponentInstance aci)
55{
56 return CloseComponent(aci);
57}
58#endif
59
Charles Davisb149d7b2011-01-29 16:45:54 -070060#ifndef HAVE_AUGRAPHADDNODE
61static inline OSStatus AUGraphAddNode(AUGraph graph, const AudioComponentDescription *desc, AUNode *node)
62{
63 return AUGraphNewNode(graph, desc, 0, NULL, node);
64}
65
66static 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
Andrew Talbot1d5d2372008-12-20 15:02:41 +000072WINE_DEFAULT_DEBUG_CHANNEL(wave);
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +020073WINE_DECLARE_DEBUG_CHANNEL(midi);
Emmanuel Maillard144a5352006-05-28 22:46:23 +020074
Ken Thomasese690d7c2009-10-11 14:11:37 -050075static 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
Emmanuel Maillard144a5352006-05-28 22:46:23 +020088int AudioUnit_CloseAudioUnit(AudioUnit au)
89{
Charles Davis459d9422011-01-29 16:45:53 -070090 OSStatus err = AudioComponentInstanceDispose(au);
Emmanuel Maillard144a5352006-05-28 22:46:23 +020091 return (err == noErr);
92}
93
Alexandre Julliard11fe6572006-05-31 14:52:58 +020094int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
Emmanuel Maillard144a5352006-05-28 22:46:23 +020095{
96 OSStatus err = noErr;
97
Ken Thomasese690d7c2009-10-11 14:11:37 -050098 TRACE("input format: %s\n", streamDescription(stream));
99
Emmanuel Maillard144a5352006-05-28 22:46:23 +0200100 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
Alexandre Julliard11fe6572006-05-31 14:52:58 +0200101 0, stream, sizeof(*stream));
102
Emmanuel Maillard144a5352006-05-28 22:46:23 +0200103 if (err != noErr)
104 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500105 ERR("AudioUnitSetProperty return an error %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard144a5352006-05-28 22:46:23 +0200106 return 0;
107 }
108
109 err = AudioUnitInitialize(au);
110 if (err != noErr)
111 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500112 ERR("AudioUnitInitialize return an error %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard144a5352006-05-28 22:46:23 +0200113 return 0;
114 }
115 return 1;
116}
117
118int AudioUnit_SetVolume(AudioUnit au, float left, float right)
119{
120 OSStatus err = noErr;
Ken Thomasesf639c4d2009-10-15 19:19:20 -0500121 static int once;
122
123 if (!once++) FIXME("independent left/right volume not implemented (%f, %f)\n", left, right);
Emmanuel Maillard144a5352006-05-28 22:46:23 +0200124
125 err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
126
127 if (err != noErr)
128 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500129 ERR("AudioUnitSetParameter return an error %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard144a5352006-05-28 22:46:23 +0200130 return 0;
131 }
132 return 1;
133}
134
135int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
136{
137 OSStatus err = noErr;
Ken Thomasesf639c4d2009-10-15 19:19:20 -0500138 static int once;
139
140 if (!once++) FIXME("independent left/right volume not implemented\n");
Emmanuel Maillard144a5352006-05-28 22:46:23 +0200141
142 err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
143 if (err != noErr)
144 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500145 ERR("AudioUnitGetParameter return an error %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard144a5352006-05-28 22:46:23 +0200146 return 0;
147 }
148 *right = *left;
149 return 1;
150}
Ken Thomases30a1b292006-12-28 11:05:24 -0600151
152
Ken Thomases0e52c422006-12-28 11:07:24 -0600153/* FIXME: implement sample rate conversion on input */
154int AudioUnit_GetInputDeviceSampleRate(void)
155{
156 AudioDeviceID defaultInputDevice;
157 UInt32 param;
Charles Davisb149d7b2011-01-29 16:45:54 -0700158 AudioObjectPropertyAddress propertyAddress;
Ken Thomases0e52c422006-12-28 11:07:24 -0600159 Float64 sampleRate;
160 OSStatus err;
161
162 param = sizeof(defaultInputDevice);
Charles Davisb149d7b2011-01-29 16:45:54 -0700163 propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
164 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
165 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
166 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &param, &defaultInputDevice);
Ken Thomases0e52c422006-12-28 11:07:24 -0600167 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);
Charles Davisb149d7b2011-01-29 16:45:54 -0700174 propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
175 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
176 err = AudioObjectGetPropertyData(defaultInputDevice, &propertyAddress, 0, NULL, &param, &sampleRate);
Ken Thomases0e52c422006-12-28 11:07:24 -0600177 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
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200186/*
187 * MIDI Synth Unit
188 */
189int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
190{
191 OSStatus err;
Charles Davis459d9422011-01-29 16:45:53 -0700192 AudioComponentDescription desc;
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200193 AUNode synthNode;
194 AUNode outNode;
195
196 err = NewAUGraph(graph);
197 if (err != noErr)
198 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500199 ERR_(midi)("NewAUGraph return %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200200 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
Charles Davisb149d7b2011-01-29 16:45:54 -0700211 err = AUGraphAddNode(*graph, &desc, &synthNode);
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200212 if (err != noErr)
213 {
Charles Davisb149d7b2011-01-29 16:45:54 -0700214 ERR_(midi)("AUGraphAddNode cannot create synthNode : %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200215 return 0;
216 }
217
218 /* create out node */
219 desc.componentType = kAudioUnitType_Output;
220 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
221
Charles Davisb149d7b2011-01-29 16:45:54 -0700222 err = AUGraphAddNode(*graph, &desc, &outNode);
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200223 if (err != noErr)
224 {
Charles Davisb149d7b2011-01-29 16:45:54 -0700225 ERR_(midi)("AUGraphAddNode cannot create outNode %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200226 return 0;
227 }
228
229 err = AUGraphOpen(*graph);
230 if (err != noErr)
231 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500232 ERR_(midi)("AUGraphOpen return %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200233 return 0;
234 }
235
236 /* connecting the nodes */
237 err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
238 if (err != noErr)
239 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500240 ERR_(midi)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200241 return 0;
242 }
243
244 /* Get the synth unit */
Charles Davisb149d7b2011-01-29 16:45:54 -0700245 err = AUGraphNodeInfo(*graph, synthNode, 0, synth);
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200246 if (err != noErr)
247 {
Charles Davisb149d7b2011-01-29 16:45:54 -0700248 ERR_(midi)("AUGraphNodeInfo return %s\n", wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200249 return 0;
250 }
251
252 return 1;
253}
254
255int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
256{
257 OSStatus err = noErr;
258
259 err = AUGraphInitialize(graph);
260 if (err != noErr)
261 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500262 ERR_(midi)("AUGraphInitialize(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200263 return 0;
264 }
265
266 err = AUGraphStart(graph);
267 if (err != noErr)
268 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500269 ERR_(midi)("AUGraphStart(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200270 return 0;
271 }
272
273 return 1;
274}
275
276int SynthUnit_Close(AUGraph graph)
277{
278 OSStatus err = noErr;
279
280 err = AUGraphStop(graph);
281 if (err != noErr)
282 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500283 ERR_(midi)("AUGraphStop(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200284 return 0;
285 }
286
287 err = DisposeAUGraph(graph);
288 if (err != noErr)
289 {
Ken Thomases1b5ca012009-10-11 14:11:19 -0500290 ERR_(midi)("DisposeAUGraph(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
Emmanuel Maillard7ad29c82007-04-25 00:55:33 +0200291 return 0;
292 }
293
294 return 1;
295}