pull from trunk
[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 "AUPlugin label";
86 }
87
88 const char *
89 AUPlugin::maker () const
90 {
91         return "AUplugin maker";
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         // AudioUnits don't have default values.  Maybe presets though?
104         return 0;
105 }
106
107 jack_nframes_t
108 AUPlugin::latency () const
109 {
110         return unit->Latency ();
111 }
112
113 void
114 AUPlugin::set_parameter (uint32_t which, float val)
115 {
116         unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
117 }
118
119 float
120 AUPlugin::get_parameter (uint32_t which) const
121 {
122         float outValue = 0.0;
123         
124         unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
125         
126         return outValue;
127 }
128
129 int
130 AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const
131 {
132         return -1;
133 }
134
135 uint32_t
136 AUPlugin::nth_parameter (uint32_t which, bool& ok) const
137 {
138         return 0;
139 }
140
141 void
142 AUPlugin::activate ()
143 {
144         unit->GlobalReset ();
145 }
146
147 void
148 AUPlugin::deactivate ()
149 {
150         // not needed.  GlobalReset () takes care of it.
151 }
152
153 void
154 AUPlugin::set_block_size (jack_nframes_t nframes)
155 {
156         
157 }
158
159 int
160 AUPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset)
161 {
162         AudioUnitRenderActionFlags flags = 0;
163         AudioTimeStamp ts;
164         
165         AudioBufferList abl;
166         abl.mNumberBuffers = 1;
167         abl.mBuffers[0].mNumberChannels = 1;
168         abl.mBuffers[0].mDataByteSize = nframes * sizeof(Sample);
169         abl.mBuffers[0].mData = &bufs[0];
170         
171         
172         unit->Render (&flags, &ts, 0, 0, &abl);
173         
174         return 0;
175 }
176
177 set<uint32_t>
178 AUPlugin::automatable() const
179 {
180         set<uint32_t> automates;
181         
182         return automates;
183 }
184
185 void
186 AUPlugin::store_state (ARDOUR::PluginState&)
187 {
188         
189 }
190
191 void
192 AUPlugin::restore_state (ARDOUR::PluginState&)
193 {
194         
195 }
196
197 string
198 AUPlugin::describe_parameter (uint32_t)
199 {
200         return "";
201 }
202
203 void
204 AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const
205 {
206         
207 }
208
209 bool
210 AUPlugin::parameter_is_audio (uint32_t) const
211 {
212         return false;
213 }
214
215 bool
216 AUPlugin::parameter_is_control (uint32_t) const
217 {
218         return false;
219 }
220
221 bool
222 AUPlugin::parameter_is_input (uint32_t) const
223 {
224         return false;
225 }
226
227 bool
228 AUPlugin::parameter_is_output (uint32_t) const
229 {
230         return false;
231 }
232
233 XMLNode&
234 AUPlugin::get_state()
235 {
236         XMLNode* root = new XMLNode (state_node_name());
237         
238         return *root;
239 }
240
241 int
242 AUPlugin::set_state(const XMLNode& node)
243 {
244         return -1;
245 }
246
247 bool
248 AUPlugin::save_preset (string name)
249 {
250         return false;
251 }
252
253 bool
254 AUPlugin::load_preset (const string preset_label)
255 {
256         return false;
257 }
258
259 vector<string>
260 AUPlugin::get_presets ()
261 {
262         vector<string> presets;
263         
264         return presets;
265 }
266
267 bool
268 AUPlugin::has_editor () const
269 {
270         return false;
271 }
272
273 PluginPtr
274 AUPluginInfo::load (Session& session)
275 {
276         try {
277                 PluginPtr plugin;
278
279                 CAComponent* comp = new CAComponent(*desc);
280                 
281                 if (!comp->IsValid()) {
282                         error << ("AudioUnit: not a valid Component") << endmsg;
283                 } else {
284                         plugin.reset (new AUPlugin (session.engine(), session, comp));
285                 }
286                 
287                 plugin->set_info(PluginInfoPtr(new AUPluginInfo(*this)));
288                 return plugin;
289         }
290
291         catch (failed_constructor &err) {
292                 return PluginPtr ((Plugin*) 0);
293         }
294 }
295
296 PluginInfoList
297 AUPluginInfo::discover ()
298 {
299         PluginInfoList plugs;
300
301         CAComponentDescription desc;
302         desc.componentFlags = 0;
303         desc.componentFlagsMask = 0;
304         desc.componentSubType = 0;
305         desc.componentManufacturer = 0;
306         desc.componentType = kAudioUnitType_Effect;
307
308         Component comp = 0;
309
310         comp = FindNextComponent (NULL, &desc);
311         while (comp != NULL) {
312                 CAComponentDescription temp;
313                 GetComponentInfo (comp, &temp, NULL, NULL, NULL);
314                 
315                 AUPluginInfoPtr plug(new AUPluginInfo);
316                 plug->name = AUPluginInfo::get_name (temp);
317                 plug->type = PluginInfo::AudioUnit;
318                 plug->n_inputs = 0;
319                 plug->n_outputs = 0;
320                 plug->category = "AudioUnit";
321                 plug->desc = new CAComponentDescription(temp);
322
323                 plugs.push_back(plug);
324                 
325                 comp = FindNextComponent (comp, &desc);
326         }
327
328         return plugs;
329 }
330
331 string
332 AUPluginInfo::get_name (CAComponentDescription& comp_desc)
333 {
334         CFStringRef itemName = NULL;
335         // Marc Poirier -style item name
336         CAComponent auComponent (comp_desc);
337         if (auComponent.IsValid()) {
338                 CAComponentDescription dummydesc;
339                 Handle nameHandle = NewHandle(sizeof(void*));
340                 if (nameHandle != NULL) {
341                         OSErr err = GetComponentInfo(auComponent.Comp(), &dummydesc, nameHandle, NULL, NULL);
342                         if (err == noErr) {
343                                 ConstStr255Param nameString = (ConstStr255Param) (*nameHandle);
344                                 if (nameString != NULL) {
345                                         itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding());
346                                 }
347                         }
348                         DisposeHandle(nameHandle);
349                 }
350         }
351     
352         // if Marc-style fails, do the original way
353         if (itemName == NULL) {
354                 CFStringRef compTypeString = UTCreateStringForOSType(comp_desc.componentType);
355                 CFStringRef compSubTypeString = UTCreateStringForOSType(comp_desc.componentSubType);
356                 CFStringRef compManufacturerString = UTCreateStringForOSType(comp_desc.componentManufacturer);
357     
358                 itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"), 
359                         compTypeString, compManufacturerString, compSubTypeString);
360     
361                 if (compTypeString != NULL)
362                         CFRelease(compTypeString);
363                 if (compSubTypeString != NULL)
364                         CFRelease(compSubTypeString);
365                 if (compManufacturerString != NULL)
366                         CFRelease(compManufacturerString);
367         }
368         
369         return CFStringRefToStdString(itemName);
370 }