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