2 Copyright (C) 2006 Paul Davis
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.
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.
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.
22 #include <pbd/transmitter.h>
23 #include <pbd/xml++.h>
24 #include <pbd/whitespace.h>
26 #include <glibmm/thread.h>
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>
34 #include <appleutility/CAAudioUnit.h>
36 #include <CoreServices/CoreServices.h>
37 #include <AudioUnit/AudioUnit.h>
43 using namespace ARDOUR;
46 _render_callback(void *userData,
47 AudioUnitRenderActionFlags *ioActionFlags,
48 const AudioTimeStamp *inTimeStamp,
50 UInt32 inNumberFrames,
51 AudioBufferList* ioData)
53 return ((AUPlugin*)userData)->render_callback (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
56 AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAComponent> _comp)
58 Plugin (engine, session),
60 unit (new CAAudioUnit),
68 OSErr err = CAAudioUnit::Open (*(comp.get()), *unit);
71 error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg;
72 throw failed_constructor ();
75 AURenderCallbackStruct renderCallbackInfo;
77 renderCallbackInfo.inputProc = _render_callback;
78 renderCallbackInfo.inputProcRefCon = this;
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();
86 unit->GetElementCount (kAudioUnitScope_Input, input_elements);
87 unit->GetElementCount (kAudioUnitScope_Output, output_elements);
89 // set up the basic stream format. these fields do not change
91 streamFormat.mSampleRate = session.frame_rate();
92 streamFormat.mFormatID = kAudioFormatLinearPCM;
93 streamFormat.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved;
94 streamFormat.mBitsPerChannel = 32;
95 streamFormat.mFramesPerPacket = 1;
97 // subject to later modification as we discover channel counts
99 streamFormat.mBytesPerPacket = 4;
100 streamFormat.mBytesPerFrame = 4;
101 streamFormat.mChannelsPerFrame = 1;
105 if (_set_block_size (_session.get_block_size())) {
106 error << _("AUPlugin: cannot set processing block size") << endmsg;
107 throw failed_constructor();
111 AUPlugin::~AUPlugin ()
114 unit->Uninitialize ();
123 AUPlugin::unique_id () const
125 return AUPluginInfo::stringify_descriptor (comp->Desc());
129 AUPlugin::label () const
131 return _info->name.c_str();
135 AUPlugin::parameter_count () const
141 AUPlugin::default_value (uint32_t port)
143 // AudioUnits don't have default values. Maybe presets though?
148 AUPlugin::signal_latency () const
151 return _user_latency;
154 return unit->Latency ();
158 AUPlugin::set_parameter (uint32_t which, float val)
160 // unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
164 AUPlugin::get_parameter (uint32_t which) const
166 float outValue = 0.0;
168 // unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
174 AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const
180 AUPlugin::nth_parameter (uint32_t which, bool& ok) const
186 AUPlugin::activate ()
190 if ((err = unit->Initialize()) != noErr) {
191 error << string_compose (_("AUPlugin: cannot initialize plugin (err = %1)"), err) << endmsg;
193 frames_processed = 0;
200 AUPlugin::deactivate ()
202 unit->GlobalReset ();
206 AUPlugin::set_block_size (nframes_t nframes)
208 _set_block_size (nframes);
212 AUPlugin::_set_block_size (nframes_t nframes)
214 bool was_initialized = initialized;
215 UInt32 numFrames = nframes;
219 unit->Uninitialize ();
222 if ((err = unit->SetProperty (kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
223 0, &numFrames, sizeof (numFrames))) != noErr) {
224 cerr << "cannot set max frames (err = " << err << ')' << endl;
228 if (was_initialized) {
236 AUPlugin::can_support_input_configuration (int32_t in)
238 streamFormat.mChannelsPerFrame = in;
239 /* apple says that for non-interleaved data, these
240 values always refer to a single channel.
242 streamFormat.mBytesPerPacket = 4;
243 streamFormat.mBytesPerFrame = 4;
245 if (set_input_format () == 0) {
253 AUPlugin::set_input_format ()
255 return set_stream_format (kAudioUnitScope_Input, input_elements);
259 AUPlugin::set_output_format ()
261 return set_stream_format (kAudioUnitScope_Output, output_elements);
265 AUPlugin::set_stream_format (int scope, uint32_t cnt)
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;
277 if (scope == kAudioUnitScope_Input) {
287 AUPlugin::compute_output_streams (int32_t nplugins)
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.
293 if (set_output_format() == 0) {
300 buffers = (AudioBufferList *) malloc (offsetof(AudioBufferList, mBuffers) +
301 streamFormat.mChannelsPerFrame * sizeof(AudioBuffer));
303 Glib::Mutex::Lock em (_session.engine().process_lock());
304 IO::MoreOutputs (streamFormat.mChannelsPerFrame);
306 return streamFormat.mChannelsPerFrame;
313 AUPlugin::output_streams() const
315 if (!(format_set & 0x2)) {
316 warning << _("AUPlugin: output_streams() called without any format set!") << endmsg;
319 return streamFormat.mChannelsPerFrame;
324 AUPlugin::input_streams() const
326 if (!(format_set & 0x1)) {
327 warning << _("AUPlugin: input_streams() called without any format set!") << endmsg;
330 return streamFormat.mChannelsPerFrame;
334 AUPlugin::render_callback(AudioUnitRenderActionFlags *ioActionFlags,
335 const AudioTimeStamp *inTimeStamp,
337 UInt32 inNumberFrames,
338 AudioBufferList* ioData)
340 /* not much to do - the data is already in the buffers given to us in connect_and_run() */
342 if (current_maxbuf == 0) {
343 error << _("AUPlugin: render callback called illegally!") << endmsg;
344 return kAudioUnitErr_CannotDoInCurrentContext;
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;
353 cb_offset += inNumberFrames;
359 AUPlugin::connect_and_run (vector<Sample*>& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, nframes_t nframes, nframes_t offset)
361 AudioUnitRenderActionFlags flags = 0;
364 current_buffers = &bufs;
365 current_maxbuf = maxbuf;
366 current_offset = offset;
369 buffers->mNumberBuffers = maxbuf;
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;
377 ts.mSampleTime = frames_processed;
378 ts.mFlags = kAudioTimeStampSampleTimeValid;
380 if (unit->Render (&flags, &ts, 0, nframes, buffers) == noErr) {
383 frames_processed += nframes;
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));
397 AUPlugin::automatable() const
399 set<uint32_t> automates;
405 AUPlugin::store_state (ARDOUR::PluginState&)
411 AUPlugin::restore_state (ARDOUR::PluginState&)
417 AUPlugin::describe_parameter (uint32_t)
423 AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const
429 AUPlugin::parameter_is_audio (uint32_t) const
435 AUPlugin::parameter_is_control (uint32_t) const
441 AUPlugin::parameter_is_input (uint32_t) const
447 AUPlugin::parameter_is_output (uint32_t) const
453 AUPlugin::get_state()
455 XMLNode *root = new XMLNode (state_node_name());
456 LocaleGuard lg (X_("POSIX"));
461 AUPlugin::set_state(const XMLNode& node)
467 AUPlugin::save_preset (string name)
473 AUPlugin::load_preset (const string preset_label)
479 AUPlugin::get_presets ()
481 vector<string> presets;
487 AUPlugin::has_editor () const
489 // even if the plugin doesn't have its own editor, the AU API can be used
490 // to create one that looks native.
494 AUPluginInfo::AUPluginInfo (boost::shared_ptr<CAComponentDescription> d)
500 AUPluginInfo::~AUPluginInfo ()
505 AUPluginInfo::load (Session& session)
510 boost::shared_ptr<CAComponent> comp (new CAComponent(*descriptor));
512 if (!comp->IsValid()) {
513 error << ("AudioUnit: not a valid Component") << endmsg;
515 plugin.reset (new AUPlugin (session.engine(), session, comp));
518 plugin->set_info (PluginInfoPtr (new AUPluginInfo (*this)));
522 catch (failed_constructor &err) {
523 return PluginPtr ((Plugin*) 0);
528 AUPluginInfo::discover ()
530 PluginInfoList plugs;
533 discover_music (plugs);
539 AUPluginInfo::discover_music (PluginInfoList& plugs)
541 CAComponentDescription desc;
542 desc.componentFlags = 0;
543 desc.componentFlagsMask = 0;
544 desc.componentSubType = 0;
545 desc.componentManufacturer = 0;
546 desc.componentType = kAudioUnitType_MusicEffect;
548 discover_by_description (plugs, desc);
552 AUPluginInfo::discover_fx (PluginInfoList& plugs)
554 CAComponentDescription desc;
555 desc.componentFlags = 0;
556 desc.componentFlagsMask = 0;
557 desc.componentSubType = 0;
558 desc.componentManufacturer = 0;
559 desc.componentType = kAudioUnitType_Effect;
561 discover_by_description (plugs, desc);
565 AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescription& desc)
569 comp = FindNextComponent (NULL, &desc);
571 while (comp != NULL) {
572 CAComponentDescription temp;
573 GetComponentInfo (comp, &temp, NULL, NULL, NULL);
575 AUPluginInfoPtr info (new AUPluginInfo
576 (boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
578 /* no panners, format converters or i/o AU's for our purposes
581 switch (info->descriptor->Type()) {
582 case kAudioUnitType_Panner:
583 case kAudioUnitType_OfflineEffect:
584 case kAudioUnitType_FormatConverter:
590 switch (info->descriptor->SubType()) {
591 case kAudioUnitSubType_DefaultOutput:
592 case kAudioUnitSubType_SystemOutput:
593 case kAudioUnitSubType_GenericOutput:
594 case kAudioUnitSubType_AUConverter:
598 case kAudioUnitSubType_DLSSynth:
599 info->category = "DLSSynth";
602 case kAudioUnitType_MusicEffect:
603 info->category = "MusicEffect";
606 case kAudioUnitSubType_Varispeed:
607 info->category = "Varispeed";
610 case kAudioUnitSubType_Delay:
611 info->category = "Delay";
614 case kAudioUnitSubType_LowPassFilter:
615 info->category = "LowPassFilter";
618 case kAudioUnitSubType_HighPassFilter:
619 info->category = "HighPassFilter";
622 case kAudioUnitSubType_BandPassFilter:
623 info->category = "BandPassFilter";
626 case kAudioUnitSubType_HighShelfFilter:
627 info->category = "HighShelfFilter";
630 case kAudioUnitSubType_LowShelfFilter:
631 info->category = "LowShelfFilter";
634 case kAudioUnitSubType_ParametricEQ:
635 info->category = "ParametricEQ";
638 case kAudioUnitSubType_GraphicEQ:
639 info->category = "GraphicEQ";
642 case kAudioUnitSubType_PeakLimiter:
643 info->category = "PeakLimiter";
646 case kAudioUnitSubType_DynamicsProcessor:
647 info->category = "DynamicsProcessor";
650 case kAudioUnitSubType_MultiBandCompressor:
651 info->category = "MultiBandCompressor";
654 case kAudioUnitSubType_MatrixReverb:
655 info->category = "MatrixReverb";
658 case kAudioUnitType_Mixer:
659 info->category = "Mixer";
662 case kAudioUnitSubType_StereoMixer:
663 info->category = "StereoMixer";
666 case kAudioUnitSubType_3DMixer:
667 info->category = "3DMixer";
670 case kAudioUnitSubType_MatrixMixer:
671 info->category = "MatrixMixer";
678 AUPluginInfo::get_names (temp, info->name, info->creator);
680 info->type = ARDOUR::AudioUnit;
681 info->unique_id = stringify_descriptor (*info->descriptor);
683 /* mark the plugin as having flexible i/o */
686 info->n_outputs = -1;
689 plugs.push_back (info);
691 comp = FindNextComponent (comp, &desc);
696 AUPluginInfo::get_names (CAComponentDescription& comp_desc, std::string& name, Glib::ustring& maker)
698 CFStringRef itemName = NULL;
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);
708 ConstStr255Param nameString = (ConstStr255Param) (*nameHandle);
709 if (nameString != NULL) {
710 itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding());
713 DisposeHandle(nameHandle);
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);
723 itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
724 compTypeString, compManufacturerString, compSubTypeString);
726 if (compTypeString != NULL)
727 CFRelease(compTypeString);
728 if (compSubTypeString != NULL)
729 CFRelease(compSubTypeString);
730 if (compManufacturerString != NULL)
731 CFRelease(compManufacturerString);
734 string str = CFStringRefToStdString(itemName);
735 string::size_type colon = str.find (':');
738 name = str.substr (colon+1);
739 maker = str.substr (0, colon);
740 // strip_whitespace_edges (maker);
741 // strip_whitespace_edges (name);
748 // from CAComponentDescription.cpp (in libs/appleutility in ardour source)
749 extern char *StringForOSType (OSType t, char *writeLocation);
752 AUPluginInfo::stringify_descriptor (const CAComponentDescription& desc)
757 s << StringForOSType (desc.Type(), str);
760 s << StringForOSType (desc.SubType(), str);
763 s << StringForOSType (desc.Manu(), str);