Start using libappleutility
[ardour.git] / libs / ardour / audio_unit.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3         Written by Taybin Rutkin
4         
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include <pbd/transmitter.h>
22 #include <pbd/xml++.h>
23
24 #include <ardour/audioengine.h>
25 #include <ardour/audio_unit.h>
26 #include <ardour/session.h>
27 #include <ardour/utils.h>
28
29 #include <appleutility/CAAudioUnit.h>
30
31 #include <CoreServices/CoreServices.h>
32 #include <AudioUnit/AudioUnit.h>
33
34 #include "i18n.h"
35
36 using namespace std;
37 using namespace PBD;
38 using namespace ARDOUR;
39
40 AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp)
41         :
42         Plugin (engine, session),
43         comp (_comp),
44         unit (0)
45 {
46         if (!unit->IsValid()) {
47                 error << _("AudioUnit: Not a proper AudioUnit plugin") << endmsg;
48                 throw failed_constructor ();
49         }
50                 
51         unit = new CAAudioUnit;
52         
53         OSErr err = CAAudioUnit::Open (*comp, *unit);
54         if (err != noErr) {
55                 error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg;
56                 delete unit;
57                 delete comp;
58                 throw failed_constructor ();
59         }
60         
61         unit->Initialize ();
62 }
63
64 AUPlugin::~AUPlugin ()
65 {
66         if (unit) {
67                 unit->Uninitialize ();
68                 delete unit;
69         }
70         
71         if (comp) {
72                 delete comp;
73         }
74 }
75
76 AUPluginInfo::~AUPluginInfo ()
77 {
78         if (desc) {
79                 delete desc;
80         }
81 }
82
83 uint32_t
84 AUPlugin::unique_id () const
85 {
86         return 0;
87 }
88
89 const char *
90 AUPlugin::label () const
91 {
92         return "";
93 }
94
95 const char *
96 AUPlugin::maker () const
97 {
98         return "";
99 }
100
101 uint32_t
102 AUPlugin::parameter_count () const
103 {
104         return 0;
105 }
106
107 float
108 AUPlugin::default_value (uint32_t port)
109 {
110         return 0.0;
111 }
112
113 jack_nframes_t
114 AUPlugin::latency () const
115 {
116         return 0;
117 }
118
119 void
120 AUPlugin::set_parameter (uint32_t which, float val)
121 {
122         
123 }
124
125 float
126 AUPlugin::get_parameter (uint32_t which) const
127 {
128         return 0.0;
129 }
130
131 int
132 AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const
133 {
134         return -1;
135 }
136
137 uint32_t
138 AUPlugin::nth_parameter (uint32_t which, bool& ok) const
139 {
140         return 0;
141 }
142
143 void
144 AUPlugin::activate ()
145 {
146         
147 }
148
149 void
150 AUPlugin::deactivate ()
151 {
152         
153 }
154
155 void
156 AUPlugin::set_block_size (jack_nframes_t nframes)
157 {
158         
159 }
160
161 int
162 AUPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset)
163 {
164         return -1;
165 }
166
167 set<uint32_t>
168 AUPlugin::automatable() const
169 {
170         set<uint32_t> automates;
171         
172         return automates;
173 }
174
175 void
176 AUPlugin::store_state (ARDOUR::PluginState&)
177 {
178         
179 }
180
181 void
182 AUPlugin::restore_state (ARDOUR::PluginState&)
183 {
184         
185 }
186
187 string
188 AUPlugin::describe_parameter (uint32_t)
189 {
190         return "";
191 }
192
193 void
194 AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const
195 {
196         
197 }
198
199 bool
200 AUPlugin::parameter_is_audio (uint32_t) const
201 {
202         return false;
203 }
204
205 bool
206 AUPlugin::parameter_is_control (uint32_t) const
207 {
208         return false;
209 }
210
211 bool
212 AUPlugin::parameter_is_input (uint32_t) const
213 {
214         return false;
215 }
216
217 bool
218 AUPlugin::parameter_is_output (uint32_t) const
219 {
220         return false;
221 }
222
223 XMLNode&
224 AUPlugin::get_state()
225 {
226         XMLNode* root = new XMLNode (state_node_name());
227         
228         return *root;
229 }
230
231 int
232 AUPlugin::set_state(const XMLNode& node)
233 {
234         return -1;
235 }
236
237 bool
238 AUPlugin::save_preset (string name)
239 {
240         return false;
241 }
242
243 bool
244 AUPlugin::load_preset (const string preset_label)
245 {
246         return false;
247 }
248
249 vector<string>
250 AUPlugin::get_presets ()
251 {
252         vector<string> presets;
253         
254         return presets;
255 }
256
257 bool
258 AUPlugin::has_editor () const
259 {
260         return false;
261 }
262
263 PluginPtr
264 AUPluginInfo::load (Session& session)
265 {
266         try {
267                 PluginPtr plugin;
268
269                 CAComponent* comp = new CAComponent(*desc);
270                 
271                 if (!comp->IsValid()) {
272                         error << ("AudioUnit: not a valid Component") << endmsg;
273                 } else {
274                         plugin.reset (new AUPlugin (session.engine(), session, comp));
275                 }
276                 
277                 plugin->set_info(PluginInfoPtr(new AUPluginInfo(*this)));
278                 return plugin;
279         }
280
281         catch (failed_constructor &err) {
282                 return PluginPtr ((Plugin*) 0);
283         }
284 }
285
286 PluginInfoList
287 AUPluginInfo::discover ()
288 {
289         PluginInfoList plugs;
290
291         int numTypes = 2;    // this magic number was retrieved from the apple AUHost example.
292
293         CAComponentDescription desc;
294         desc.componentFlags = 0;
295         desc.componentFlagsMask = 0;
296         desc.componentSubType = 0;
297         desc.componentManufacturer = 0;
298
299         for (int i = 0; i < numTypes; ++i) {
300                 if (i == 1) {
301                         desc.componentType = kAudioUnitType_MusicEffect;
302                 } else {
303                         desc.componentType = kAudioUnitType_Effect;
304                 }
305
306                 Component comp = 0;
307
308                 comp = FindNextComponent (NULL, &desc);
309                 while (comp != NULL) {
310                         CAComponentDescription temp;
311                         GetComponentInfo (comp, &temp, NULL, NULL, NULL);
312                         
313                         AUPluginInfoPtr plug(new AUPluginInfo);
314                         plug->name = AUPluginInfo::get_name (temp);
315                         plug->type = PluginInfo::AudioUnit;
316                         plug->n_inputs = 0;
317                         plug->n_outputs = 0;
318                         plug->category = "AudioUnit";
319                         plug->desc = new CAComponentDescription(temp);
320
321                         plugs.push_back(plug);
322                         
323                         comp = FindNextComponent (comp, &desc);
324                 }
325         }
326
327         return plugs;
328 }
329
330 string
331 AUPluginInfo::get_name (CAComponentDescription& comp_desc)
332 {
333         CFStringRef itemName = NULL;
334         // Marc Poirier -style item name
335         CAComponent auComponent (comp_desc);
336         if (auComponent.IsValid()) {
337                 CAComponentDescription dummydesc;
338                 Handle nameHandle = NewHandle(sizeof(void*));
339                 if (nameHandle != NULL) {
340                         OSErr err = GetComponentInfo(auComponent.Comp(), &dummydesc, nameHandle, NULL, NULL);
341                         if (err == noErr) {
342                                 ConstStr255Param nameString = (ConstStr255Param) (*nameHandle);
343                                 if (nameString != NULL) {
344                                         itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding());
345                                 }
346                         }
347                         DisposeHandle(nameHandle);
348                 }
349         }
350     
351         // if Marc-style fails, do the original way
352         if (itemName == NULL) {
353                 CFStringRef compTypeString = UTCreateStringForOSType(comp_desc.componentType);
354                 CFStringRef compSubTypeString = UTCreateStringForOSType(comp_desc.componentSubType);
355                 CFStringRef compManufacturerString = UTCreateStringForOSType(comp_desc.componentManufacturer);
356     
357                 itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"), 
358                         compTypeString, compManufacturerString, compSubTypeString);
359     
360                 if (compTypeString != NULL)
361                         CFRelease(compTypeString);
362                 if (compSubTypeString != NULL)
363                         CFRelease(compSubTypeString);
364                 if (compManufacturerString != NULL)
365                         CFRelease(compManufacturerString);
366         }
367         
368         return CFStringRefToStdString(itemName);
369 }