f86e78416955b5f8ed71c5739c85a59631af7ad2
[ardour.git] / libs / ardour / audio_unit.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3         
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <sstream>
21
22 #include <pbd/transmitter.h>
23 #include <pbd/xml++.h>
24 #include <pbd/whitespace.h>
25
26 #include <glibmm/thread.h>
27
28 #include <ardour/audioengine.h>
29 #include <ardour/io.h>
30 #include <ardour/audio_unit.h>
31 #include <ardour/session.h>
32 #include <ardour/utils.h>
33
34 #include <appleutility/CAAudioUnit.h>
35
36 #include <CoreServices/CoreServices.h>
37 #include <AudioUnit/AudioUnit.h>
38
39 #include "i18n.h"
40
41 using namespace std;
42 using namespace PBD;
43 using namespace ARDOUR;
44
45 static OSStatus 
46 _render_callback(void *userData,
47                  AudioUnitRenderActionFlags *ioActionFlags,
48                  const AudioTimeStamp    *inTimeStamp,
49                  UInt32       inBusNumber,
50                  UInt32       inNumberFrames,
51                  AudioBufferList*       ioData)
52 {
53         return ((AUPlugin*)userData)->render_callback (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
54 }
55
56 AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAComponent> _comp)
57         :
58         Plugin (engine, session),
59         comp (_comp),
60         unit (new CAAudioUnit),
61         initialized (false),
62         buffers (0),
63         current_maxbuf (0),
64         current_offset (0),
65         current_buffers (0),
66         frames_processed (0)
67 {                       
68         OSErr err = CAAudioUnit::Open (*(comp.get()), *unit);
69
70         if (err != noErr) {
71                 error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg;
72                 throw failed_constructor ();
73         }
74         
75         AURenderCallbackStruct renderCallbackInfo;
76
77         renderCallbackInfo.inputProc = _render_callback;
78         renderCallbackInfo.inputProcRefCon = this;
79
80         if ((err = unit->SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
81                                          0, (void*) &renderCallbackInfo, sizeof(renderCallbackInfo))) != 0) {
82                 cerr << "cannot install render callback (err = " << err << ')' << endl;
83                 throw failed_constructor();
84         }
85
86         unit->GetElementCount (kAudioUnitScope_Input, input_elements);
87         unit->GetElementCount (kAudioUnitScope_Output, output_elements);
88
89         // set up the basic stream format. these fields do not change
90                             
91         streamFormat.mSampleRate = session.frame_rate();
92         streamFormat.mFormatID = kAudioFormatLinearPCM;
93         streamFormat.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved;
94         streamFormat.mBitsPerChannel = 32;
95         streamFormat.mFramesPerPacket = 1;
96
97         // subject to later modification as we discover channel counts
98
99         streamFormat.mBytesPerPacket = 4;
100         streamFormat.mBytesPerFrame = 4;
101         streamFormat.mChannelsPerFrame = 1;
102
103         format_set = 0;
104
105         if (_set_block_size (_session.get_block_size())) {
106                 error << _("AUPlugin: cannot set processing block size") << endmsg;
107                 throw failed_constructor();
108         }
109 }
110
111 AUPlugin::~AUPlugin ()
112 {
113         if (unit) {
114                 unit->Uninitialize ();
115         }
116
117         if (buffers) {
118                 free (buffers);
119         }
120 }
121
122 string
123 AUPlugin::unique_id () const
124 {
125         return AUPluginInfo::stringify_descriptor (comp->Desc());
126 }
127
128 const char *
129 AUPlugin::label () const
130 {
131         return _info->name.c_str();
132 }
133
134 uint32_t
135 AUPlugin::parameter_count () const
136 {
137         return 0;
138 }
139
140 float
141 AUPlugin::default_value (uint32_t port)
142 {
143         // AudioUnits don't have default values.  Maybe presets though?
144         return 0;
145 }
146
147 nframes_t
148 AUPlugin::signal_latency () const
149 {
150         if (_user_latency) {
151                 return _user_latency;
152         }
153
154         return unit->Latency ();
155 }
156
157 void
158 AUPlugin::set_parameter (uint32_t which, float val)
159 {
160         // unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
161 }
162
163 float
164 AUPlugin::get_parameter (uint32_t which) const
165 {
166         float outValue = 0.0;
167         
168         // unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
169         
170         return outValue;
171 }
172
173 int
174 AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const
175 {
176         return 0;
177 }
178
179 uint32_t
180 AUPlugin::nth_parameter (uint32_t which, bool& ok) const
181 {
182         return 0;
183 }
184
185 void
186 AUPlugin::activate ()
187 {
188         if (!initialized) {
189                 OSErr err;
190                 if ((err = unit->Initialize()) != noErr) {
191                         error << string_compose (_("AUPlugin: cannot initialize plugin (err = %1)"), err) << endmsg;
192                 } else {
193                         frames_processed = 0;
194                         initialized = true;
195                 }
196         }
197 }
198
199 void
200 AUPlugin::deactivate ()
201 {
202         unit->GlobalReset ();
203 }
204
205 void
206 AUPlugin::set_block_size (nframes_t nframes)
207 {
208         _set_block_size (nframes);
209 }
210
211 int
212 AUPlugin::_set_block_size (nframes_t nframes)
213 {
214         bool was_initialized = initialized;
215         UInt32 numFrames = nframes;
216         OSErr err;
217
218         if (initialized) {
219                 unit->Uninitialize ();
220         }
221
222         if ((err = unit->SetProperty (kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 
223                                       0, &numFrames, sizeof (numFrames))) != noErr) {
224                 cerr << "cannot set max frames (err = " << err << ')' << endl;
225                 return -1;
226         }
227
228         if (was_initialized) {
229                 activate ();
230         }
231
232         return 0;
233 }
234
235 int32_t 
236 AUPlugin::can_support_input_configuration (int32_t in)
237 {       
238         streamFormat.mChannelsPerFrame = in;
239         /* apple says that for non-interleaved data, these
240            values always refer to a single channel.
241         */
242         streamFormat.mBytesPerPacket = 4;
243         streamFormat.mBytesPerFrame = 4;
244
245         if (set_input_format () == 0) {
246                 return 1;
247         } else {
248                 return -1;
249         }
250 }
251
252 int
253 AUPlugin::set_input_format ()
254 {
255         return set_stream_format (kAudioUnitScope_Input, input_elements);
256 }
257
258 int
259 AUPlugin::set_output_format ()
260 {
261         return set_stream_format (kAudioUnitScope_Output, output_elements);
262 }
263
264 int
265 AUPlugin::set_stream_format (int scope, uint32_t cnt)
266 {
267         OSErr result;
268
269         for (uint32_t i = 0; i < cnt; ++i) {
270                 if ((result = unit->SetFormat (scope, i, streamFormat)) != 0) {
271                         error << string_compose (_("AUPlugin: could not set stream format for %1/%2 (err = %3)"),
272                                                  (scope == kAudioUnitScope_Input ? "input" : "output"), i, result) << endmsg;
273                         return -1;
274                 }
275         }
276
277         if (scope == kAudioUnitScope_Input) {
278                 format_set |= 0x1;
279         } else {
280                 format_set |= 0x2;
281         }
282
283         return 0;
284 }
285
286 int32_t 
287 AUPlugin::compute_output_streams (int32_t nplugins)
288 {
289         /* we will never replicate AU plugins - either they can do the I/O we need
290            or not. thus, we can ignore nplugins entirely.
291         */
292         
293         if (set_output_format() == 0) {
294
295                 if (buffers) {
296                         free (buffers);
297                         buffers = 0;
298                 }
299
300                 buffers = (AudioBufferList *) malloc (offsetof(AudioBufferList, mBuffers) + 
301                                                       streamFormat.mChannelsPerFrame * sizeof(AudioBuffer));
302
303                 Glib::Mutex::Lock em (_session.engine().process_lock());
304                 IO::MoreOutputs (streamFormat.mChannelsPerFrame);
305
306                 return streamFormat.mChannelsPerFrame;
307         } else {
308                 return -1;
309         }
310 }
311
312 uint32_t
313 AUPlugin::output_streams() const
314 {
315         if (!(format_set & 0x2)) {
316                 warning << _("AUPlugin: output_streams() called without any format set!") << endmsg;
317                 return 1;
318         }
319         return streamFormat.mChannelsPerFrame;
320 }
321
322
323 uint32_t
324 AUPlugin::input_streams() const
325 {
326         if (!(format_set & 0x1)) {
327                 warning << _("AUPlugin: input_streams() called without any format set!") << endmsg;
328                 return 1;
329         }
330         return streamFormat.mChannelsPerFrame;
331 }
332
333 OSStatus 
334 AUPlugin::render_callback(AudioUnitRenderActionFlags *ioActionFlags,
335                           const AudioTimeStamp    *inTimeStamp,
336                           UInt32       inBusNumber,
337                           UInt32       inNumberFrames,
338                           AudioBufferList*       ioData)
339 {
340         /* not much to do - the data is already in the buffers given to us in connect_and_run() */
341
342         if (current_maxbuf == 0) {
343                 error << _("AUPlugin: render callback called illegally!") << endmsg;
344                 return kAudioUnitErr_CannotDoInCurrentContext;
345         }
346
347         for (uint32_t i = 0; i < current_maxbuf; ++i) {
348                 ioData->mBuffers[i].mNumberChannels = 1;
349                 ioData->mBuffers[i].mDataByteSize = sizeof (Sample) * inNumberFrames;
350                 ioData->mBuffers[i].mData = (*current_buffers)[i] + cb_offset + current_offset;
351         }
352
353         cb_offset += inNumberFrames;
354
355         return noErr;
356 }
357
358 int
359 AUPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, nframes_t nframes, nframes_t offset)
360 {
361         AudioUnitRenderActionFlags flags = 0;
362         AudioTimeStamp ts;
363
364         current_buffers = &bufs;
365         current_maxbuf = maxbuf;
366         current_offset = offset;
367         cb_offset = 0;
368
369         buffers->mNumberBuffers = maxbuf;
370
371         for (uint32_t i = 0; i < maxbuf; ++i) {
372                 buffers->mBuffers[i].mNumberChannels = 1;
373                 buffers->mBuffers[i].mDataByteSize = nframes * sizeof (Sample);
374                 buffers->mBuffers[i].mData = 0;
375         }
376
377         ts.mSampleTime = frames_processed;
378         ts.mFlags = kAudioTimeStampSampleTimeValid;
379
380         if (unit->Render (&flags, &ts, 0, nframes, buffers) == noErr) {
381
382                 current_maxbuf = 0;
383                 frames_processed += nframes;
384                 
385                 for (uint32_t i = 0; i < maxbuf; ++i) {
386                         if (bufs[i] + offset != buffers->mBuffers[i].mData) {
387                                 memcpy (bufs[i]+offset, buffers->mBuffers[i].mData, nframes * sizeof (Sample));
388                         }
389                 }
390                 return 0;
391         }
392
393         return -1;
394 }
395
396 set<uint32_t>
397 AUPlugin::automatable() const
398 {
399         set<uint32_t> automates;
400         
401         return automates;
402 }
403
404 void
405 AUPlugin::store_state (ARDOUR::PluginState&)
406 {
407         
408 }
409
410 void
411 AUPlugin::restore_state (ARDOUR::PluginState&)
412 {
413         
414 }
415
416 string
417 AUPlugin::describe_parameter (uint32_t)
418 {
419         return "";
420 }
421
422 void
423 AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const
424 {
425         
426 }
427
428 bool
429 AUPlugin::parameter_is_audio (uint32_t) const
430 {
431         return false;
432 }
433
434 bool
435 AUPlugin::parameter_is_control (uint32_t) const
436 {
437         return false;
438 }
439
440 bool
441 AUPlugin::parameter_is_input (uint32_t) const
442 {
443         return false;
444 }
445
446 bool
447 AUPlugin::parameter_is_output (uint32_t) const
448 {
449         return false;
450 }
451
452 XMLNode&
453 AUPlugin::get_state()
454 {
455         XMLNode *root = new XMLNode (state_node_name());
456         LocaleGuard lg (X_("POSIX"));
457         return *root;
458 }
459
460 int
461 AUPlugin::set_state(const XMLNode& node)
462 {
463         return -1;
464 }
465
466 bool
467 AUPlugin::save_preset (string name)
468 {
469         return false;
470 }
471
472 bool
473 AUPlugin::load_preset (const string preset_label)
474 {
475         return false;
476 }
477
478 vector<string>
479 AUPlugin::get_presets ()
480 {
481         vector<string> presets;
482         
483         return presets;
484 }
485
486 bool
487 AUPlugin::has_editor () const
488 {
489         // even if the plugin doesn't have its own editor, the AU API can be used
490         // to create one that looks native.
491         return true;
492 }
493
494 AUPluginInfo::AUPluginInfo (boost::shared_ptr<CAComponentDescription> d)
495         : descriptor (d)
496 {
497
498 }
499
500 AUPluginInfo::~AUPluginInfo ()
501 {
502 }
503
504 PluginPtr
505 AUPluginInfo::load (Session& session)
506 {
507         try {
508                 PluginPtr plugin;
509
510                 boost::shared_ptr<CAComponent> comp (new CAComponent(*descriptor));
511                 
512                 if (!comp->IsValid()) {
513                         error << ("AudioUnit: not a valid Component") << endmsg;
514                 } else {
515                         plugin.reset (new AUPlugin (session.engine(), session, comp));
516                 }
517                 
518                 plugin->set_info (PluginInfoPtr (new AUPluginInfo (*this)));
519                 return plugin;
520         }
521
522         catch (failed_constructor &err) {
523                 return PluginPtr ((Plugin*) 0);
524         }
525 }
526
527 PluginInfoList
528 AUPluginInfo::discover ()
529 {
530         PluginInfoList plugs;
531
532         discover_fx (plugs);
533         discover_music (plugs);
534
535         return plugs;
536 }
537
538 void
539 AUPluginInfo::discover_music (PluginInfoList& plugs)
540 {
541         CAComponentDescription desc;
542         desc.componentFlags = 0;
543         desc.componentFlagsMask = 0;
544         desc.componentSubType = 0;
545         desc.componentManufacturer = 0;
546         desc.componentType = kAudioUnitType_MusicEffect;
547
548         discover_by_description (plugs, desc);
549 }
550
551 void
552 AUPluginInfo::discover_fx (PluginInfoList& plugs)
553 {
554         CAComponentDescription desc;
555         desc.componentFlags = 0;
556         desc.componentFlagsMask = 0;
557         desc.componentSubType = 0;
558         desc.componentManufacturer = 0;
559         desc.componentType = kAudioUnitType_Effect;
560
561         discover_by_description (plugs, desc);
562 }
563
564 void
565 AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescription& desc)
566 {
567         Component comp = 0;
568
569         comp = FindNextComponent (NULL, &desc);
570
571         while (comp != NULL) {
572                 CAComponentDescription temp;
573                 GetComponentInfo (comp, &temp, NULL, NULL, NULL);
574
575                 AUPluginInfoPtr info (new AUPluginInfo 
576                                       (boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
577
578                 /* no panners, format converters or i/o AU's for our purposes
579                  */
580
581                 switch (info->descriptor->Type()) {
582                 case kAudioUnitType_Panner:
583                 case kAudioUnitType_OfflineEffect:
584                 case kAudioUnitType_FormatConverter:
585                         continue;
586                 default:
587                         break;
588                 }
589
590                 switch (info->descriptor->SubType()) {
591                 case kAudioUnitSubType_DefaultOutput:
592                 case kAudioUnitSubType_SystemOutput:
593                 case kAudioUnitSubType_GenericOutput:
594                 case kAudioUnitSubType_AUConverter:
595                         continue;
596                         break;
597
598                 case kAudioUnitSubType_DLSSynth:
599                         info->category = "DLSSynth";
600                         break;
601
602                 case kAudioUnitType_MusicEffect:
603                         info->category = "MusicEffect";
604                         break;
605
606                 case kAudioUnitSubType_Varispeed:
607                         info->category = "Varispeed";
608                         break;
609
610                 case kAudioUnitSubType_Delay:
611                         info->category = "Delay";
612                         break;
613
614                 case kAudioUnitSubType_LowPassFilter:
615                         info->category = "LowPassFilter";
616                         break;
617
618                 case kAudioUnitSubType_HighPassFilter:
619                         info->category = "HighPassFilter";
620                         break;
621
622                 case kAudioUnitSubType_BandPassFilter:
623                         info->category = "BandPassFilter";
624                         break;
625
626                 case kAudioUnitSubType_HighShelfFilter:
627                         info->category = "HighShelfFilter";
628                         break;
629
630                 case kAudioUnitSubType_LowShelfFilter:
631                         info->category = "LowShelfFilter";
632                         break;
633
634                 case kAudioUnitSubType_ParametricEQ:
635                         info->category = "ParametricEQ";
636                         break;
637
638                 case kAudioUnitSubType_GraphicEQ:
639                         info->category = "GraphicEQ";
640                         break;
641
642                 case kAudioUnitSubType_PeakLimiter:
643                         info->category = "PeakLimiter";
644                         break;
645
646                 case kAudioUnitSubType_DynamicsProcessor:
647                         info->category = "DynamicsProcessor";
648                         break;
649
650                 case kAudioUnitSubType_MultiBandCompressor:
651                         info->category = "MultiBandCompressor";
652                         break;
653
654                 case kAudioUnitSubType_MatrixReverb:
655                         info->category = "MatrixReverb";
656                         break;
657
658                 case kAudioUnitType_Mixer:
659                         info->category = "Mixer";
660                         break;
661
662                 case kAudioUnitSubType_StereoMixer:
663                         info->category = "StereoMixer";
664                         break;
665
666                 case kAudioUnitSubType_3DMixer:
667                         info->category = "3DMixer";
668                         break;
669
670                 case kAudioUnitSubType_MatrixMixer:
671                         info->category = "MatrixMixer";
672                         break;
673
674                 default:
675                         info->category = "";
676                 }
677
678                 AUPluginInfo::get_names (temp, info->name, info->creator);
679
680                 info->type = ARDOUR::AudioUnit;
681                 info->unique_id = stringify_descriptor (*info->descriptor);
682
683                 /* mark the plugin as having flexible i/o */
684                 
685                 info->n_inputs = -1;
686                 info->n_outputs = -1;
687
688
689                 plugs.push_back (info);
690                 
691                 comp = FindNextComponent (comp, &desc);
692         }
693 }
694
695 void
696 AUPluginInfo::get_names (CAComponentDescription& comp_desc, std::string& name, Glib::ustring& maker)
697 {
698         CFStringRef itemName = NULL;
699
700         // Marc Poirier-style item name
701         CAComponent auComponent (comp_desc);
702         if (auComponent.IsValid()) {
703                 CAComponentDescription dummydesc;
704                 Handle nameHandle = NewHandle(sizeof(void*));
705                 if (nameHandle != NULL) {
706                         OSErr err = GetComponentInfo(auComponent.Comp(), &dummydesc, nameHandle, NULL, NULL);
707                         if (err == noErr) {
708                                 ConstStr255Param nameString = (ConstStr255Param) (*nameHandle);
709                                 if (nameString != NULL) {
710                                         itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding());
711                                 }
712                         }
713                         DisposeHandle(nameHandle);
714                 }
715         }
716     
717         // if Marc-style fails, do the original way
718         if (itemName == NULL) {
719                 CFStringRef compTypeString = UTCreateStringForOSType(comp_desc.componentType);
720                 CFStringRef compSubTypeString = UTCreateStringForOSType(comp_desc.componentSubType);
721                 CFStringRef compManufacturerString = UTCreateStringForOSType(comp_desc.componentManufacturer);
722     
723                 itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"), 
724                         compTypeString, compManufacturerString, compSubTypeString);
725     
726                 if (compTypeString != NULL)
727                         CFRelease(compTypeString);
728                 if (compSubTypeString != NULL)
729                         CFRelease(compSubTypeString);
730                 if (compManufacturerString != NULL)
731                         CFRelease(compManufacturerString);
732         }
733         
734         string str = CFStringRefToStdString(itemName);
735         string::size_type colon = str.find (':');
736
737         if (colon) {
738                 name = str.substr (colon+1);
739                 maker = str.substr (0, colon);
740                 // strip_whitespace_edges (maker);
741                 // strip_whitespace_edges (name);
742         } else {
743                 name = str;
744                 maker = "unknown";
745         }
746 }
747
748 // from CAComponentDescription.cpp (in libs/appleutility in ardour source)
749 extern char *StringForOSType (OSType t, char *writeLocation);
750
751 std::string
752 AUPluginInfo::stringify_descriptor (const CAComponentDescription& desc)
753 {
754         char str[24];
755         stringstream s;
756
757         s << StringForOSType (desc.Type(), str);
758         s << " - ";
759                 
760         s << StringForOSType (desc.SubType(), str);
761         s << " - ";
762                 
763         s << StringForOSType (desc.Manu(), str);
764
765         return s.str();
766 }