0756f55a5912c5639839fcdfb3863788afc641ea
[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 (new CAAudioUnit)
45 {                       
46         OSErr err = CAAudioUnit::Open (*comp, *unit);
47         if (err != noErr) {
48                 error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg;
49                 delete unit;
50                 delete comp;
51                 throw failed_constructor ();
52         }
53         
54         unit->Initialize ();
55 }
56
57 AUPlugin::~AUPlugin ()
58 {
59         if (unit) {
60                 unit->Uninitialize ();
61                 delete unit;
62         }
63         
64         if (comp) {
65                 delete comp;
66         }
67 }
68
69 AUPluginInfo::~AUPluginInfo ()
70 {
71         if (desc) {
72                 delete desc;
73         }
74 }
75
76 uint32_t
77 AUPlugin::unique_id () const
78 {
79         return 0;
80 }
81
82 const char *
83 AUPlugin::label () const
84 {
85         return "";
86 }
87
88 const char *
89 AUPlugin::maker () const
90 {
91         return "";
92 }
93
94 uint32_t
95 AUPlugin::parameter_count () const
96 {
97         return 0;
98 }
99
100 float
101 AUPlugin::default_value (uint32_t port)
102 {
103         return 0.0;
104 }
105
106 jack_nframes_t
107 AUPlugin::latency () const
108 {
109         return 0;
110 }
111
112 void
113 AUPlugin::set_parameter (uint32_t which, float val)
114 {
115         
116 }
117
118 float
119 AUPlugin::get_parameter (uint32_t which) const
120 {
121         return 0.0;
122 }
123
124 int
125 AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const
126 {
127         return -1;
128 }
129
130 uint32_t
131 AUPlugin::nth_parameter (uint32_t which, bool& ok) const
132 {
133         return 0;
134 }
135
136 void
137 AUPlugin::activate ()
138 {
139         
140 }
141
142 void
143 AUPlugin::deactivate ()
144 {
145         
146 }
147
148 void
149 AUPlugin::set_block_size (jack_nframes_t nframes)
150 {
151         
152 }
153
154 int
155 AUPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset)
156 {
157         return -1;
158 }
159
160 set<uint32_t>
161 AUPlugin::automatable() const
162 {
163         set<uint32_t> automates;
164         
165         return automates;
166 }
167
168 void
169 AUPlugin::store_state (ARDOUR::PluginState&)
170 {
171         
172 }
173
174 void
175 AUPlugin::restore_state (ARDOUR::PluginState&)
176 {
177         
178 }
179
180 string
181 AUPlugin::describe_parameter (uint32_t)
182 {
183         return "";
184 }
185
186 void
187 AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const
188 {
189         
190 }
191
192 bool
193 AUPlugin::parameter_is_audio (uint32_t) const
194 {
195         return false;
196 }
197
198 bool
199 AUPlugin::parameter_is_control (uint32_t) const
200 {
201         return false;
202 }
203
204 bool
205 AUPlugin::parameter_is_input (uint32_t) const
206 {
207         return false;
208 }
209
210 bool
211 AUPlugin::parameter_is_output (uint32_t) const
212 {
213         return false;
214 }
215
216 XMLNode&
217 AUPlugin::get_state()
218 {
219         XMLNode* root = new XMLNode (state_node_name());
220         
221         return *root;
222 }
223
224 int
225 AUPlugin::set_state(const XMLNode& node)
226 {
227         return -1;
228 }
229
230 bool
231 AUPlugin::save_preset (string name)
232 {
233         return false;
234 }
235
236 bool
237 AUPlugin::load_preset (const string preset_label)
238 {
239         return false;
240 }
241
242 vector<string>
243 AUPlugin::get_presets ()
244 {
245         vector<string> presets;
246         
247         return presets;
248 }
249
250 bool
251 AUPlugin::has_editor () const
252 {
253         return false;
254 }
255
256 PluginPtr
257 AUPluginInfo::load (Session& session)
258 {
259         try {
260                 PluginPtr plugin;
261
262                 CAComponent* comp = new CAComponent(*desc);
263                 
264                 if (!comp->IsValid()) {
265                         error << ("AudioUnit: not a valid Component") << endmsg;
266                 } else {
267                         plugin.reset (new AUPlugin (session.engine(), session, comp));
268                 }
269                 
270                 plugin->set_info(PluginInfoPtr(new AUPluginInfo(*this)));
271                 return plugin;
272         }
273
274         catch (failed_constructor &err) {
275                 return PluginPtr ((Plugin*) 0);
276         }
277 }
278
279 PluginInfoList
280 AUPluginInfo::discover ()
281 {
282         PluginInfoList plugs;
283
284         int numTypes = 2;    // this magic number was retrieved from the apple AUHost example.
285
286         CAComponentDescription desc;
287         desc.componentFlags = 0;
288         desc.componentFlagsMask = 0;
289         desc.componentSubType = 0;
290         desc.componentManufacturer = 0;
291
292         for (int i = 0; i < numTypes; ++i) {
293                 if (i == 1) {
294                         desc.componentType = kAudioUnitType_MusicEffect;
295                 } else {
296                         desc.componentType = kAudioUnitType_Effect;
297                 }
298
299                 Component comp = 0;
300
301                 comp = FindNextComponent (NULL, &desc);
302                 while (comp != NULL) {
303                         CAComponentDescription temp;
304                         GetComponentInfo (comp, &temp, NULL, NULL, NULL);
305                         
306                         AUPluginInfoPtr plug(new AUPluginInfo);
307                         plug->name = AUPluginInfo::get_name (temp);
308                         plug->type = PluginInfo::AudioUnit;
309                         plug->n_inputs = 0;
310                         plug->n_outputs = 0;
311                         plug->category = "AudioUnit";
312                         plug->desc = new CAComponentDescription(temp);
313
314                         plugs.push_back(plug);
315                         
316                         comp = FindNextComponent (comp, &desc);
317                 }
318         }
319
320         return plugs;
321 }
322
323 string
324 AUPluginInfo::get_name (CAComponentDescription& comp_desc)
325 {
326         CFStringRef itemName = NULL;
327         // Marc Poirier -style item name
328         CAComponent auComponent (comp_desc);
329         if (auComponent.IsValid()) {
330                 CAComponentDescription dummydesc;
331                 Handle nameHandle = NewHandle(sizeof(void*));
332                 if (nameHandle != NULL) {
333                         OSErr err = GetComponentInfo(auComponent.Comp(), &dummydesc, nameHandle, NULL, NULL);
334                         if (err == noErr) {
335                                 ConstStr255Param nameString = (ConstStr255Param) (*nameHandle);
336                                 if (nameString != NULL) {
337                                         itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding());
338                                 }
339                         }
340                         DisposeHandle(nameHandle);
341                 }
342         }
343     
344         // if Marc-style fails, do the original way
345         if (itemName == NULL) {
346                 CFStringRef compTypeString = UTCreateStringForOSType(comp_desc.componentType);
347                 CFStringRef compSubTypeString = UTCreateStringForOSType(comp_desc.componentSubType);
348                 CFStringRef compManufacturerString = UTCreateStringForOSType(comp_desc.componentManufacturer);
349     
350                 itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"), 
351                         compTypeString, compManufacturerString, compSubTypeString);
352     
353                 if (compTypeString != NULL)
354                         CFRelease(compTypeString);
355                 if (compSubTypeString != NULL)
356                         CFRelease(compSubTypeString);
357                 if (compManufacturerString != NULL)
358                         CFRelease(compManufacturerString);
359         }
360         
361         return CFStringRefToStdString(itemName);
362 }