Make import GUI report if you are importing a file of a name that
[ardour.git] / libs / ardour / audio_unit.cc
index 502ce2c080c126b28475081a4236ab4415fb4ce8..5e0114c49d708e1fd6c90b169d16a76a883eb6e8 100644 (file)
@@ -32,6 +32,7 @@
 #include <ardour/utils.h>
 
 #include <appleutility/CAAudioUnit.h>
+#include <appleutility/CAAUParameter.h>
 
 #include <CoreServices/CoreServices.h>
 #include <AudioUnit/AudioUnit.h>
@@ -53,7 +54,7 @@ _render_callback(void *userData,
        return ((AUPlugin*)userData)->render_callback (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
 }
 
-AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp)
+AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAComponent> _comp)
        :
        Plugin (engine, session),
        comp (_comp),
@@ -65,12 +66,10 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp)
        current_buffers (0),
        frames_processed (0)
 {                      
-       OSErr err = CAAudioUnit::Open (*comp, *unit);
+       OSErr err = CAAudioUnit::Open (*(comp.get()), *unit);
 
        if (err != noErr) {
                error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg;
-               delete unit;
-               delete comp;
                throw failed_constructor ();
        }
        
@@ -82,11 +81,10 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp)
        if ((err = unit->SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
                                         0, (void*) &renderCallbackInfo, sizeof(renderCallbackInfo))) != 0) {
                cerr << "cannot install render callback (err = " << err << ')' << endl;
-               delete unit;
-               delete comp;
                throw failed_constructor();
        }
 
+       unit->GetElementCount (kAudioUnitScope_Global, global_elements);
        unit->GetElementCount (kAudioUnitScope_Input, input_elements);
        unit->GetElementCount (kAudioUnitScope_Output, output_elements);
 
@@ -104,30 +102,145 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp)
        streamFormat.mBytesPerFrame = 4;
        streamFormat.mChannelsPerFrame = 1;
 
+       format_set = 0;
+
        if (_set_block_size (_session.get_block_size())) {
                error << _("AUPlugin: cannot set processing block size") << endmsg;
-               delete unit;
-               delete comp;
                throw failed_constructor();
        }
+
+       discover_parameters ();
+
+       Plugin::setup_controls ();
 }
 
 AUPlugin::~AUPlugin ()
 {
        if (unit) {
                unit->Uninitialize ();
-               delete unit;
        }
 
        if (buffers) {
                free (buffers);
        }
+}
+
+void
+AUPlugin::discover_parameters ()
+{
+       /* discover writable parameters */
        
-       if (comp) {
-               delete comp;
+       cerr << "get param info, there are " << global_elements << " global elements\n";
+
+       AudioUnitScope scopes[] = { 
+               kAudioUnitScope_Global,
+               kAudioUnitScope_Output,
+               kAudioUnitScope_Input
+       };
+
+       descriptors.clear ();
+
+       for (uint32_t i = 0; i < sizeof (scopes) / sizeof (scopes[0]); ++i) {
+
+               AUParamInfo param_info (unit->AU(), false, false, scopes[i]);
+               
+               cerr << "discovered " << param_info.NumParams() << " parameters in scope " << i << endl;
+               
+               for (uint32_t i = 0; i < param_info.NumParams(); ++i) {
+
+                       AUParameterDescriptor d;
+
+                       d.id = param_info.ParamID (i);
+
+                       const CAAUParameter* param = param_info.GetParamInfo (d.id);
+                       const AudioUnitParameterInfo& info (param->ParamInfo());
+
+                       const int len = CFStringGetLength (param->GetName());;
+                       char local_buffer[len*2];
+                       Boolean good = CFStringGetCString(param->GetName(),local_buffer,len*2,kCFStringEncodingMacRoman);
+                       if (!good) {
+                               d.label = "???";
+                       } else {
+                               d.label = local_buffer;
+                       }
+
+                       d.scope = param_info.GetScope ();
+                       d.element = param_info.GetElement ();
+
+                       /* info.units to consider */
+                       /*
+                         kAudioUnitParameterUnit_Generic             = 0
+                         kAudioUnitParameterUnit_Indexed             = 1
+                         kAudioUnitParameterUnit_Boolean             = 2
+                         kAudioUnitParameterUnit_Percent             = 3
+                         kAudioUnitParameterUnit_Seconds             = 4
+                         kAudioUnitParameterUnit_SampleFrames        = 5
+                         kAudioUnitParameterUnit_Phase               = 6
+                         kAudioUnitParameterUnit_Rate                = 7
+                         kAudioUnitParameterUnit_Hertz               = 8
+                         kAudioUnitParameterUnit_Cents               = 9
+                         kAudioUnitParameterUnit_RelativeSemiTones   = 10
+                         kAudioUnitParameterUnit_MIDINoteNumber      = 11
+                         kAudioUnitParameterUnit_MIDIController      = 12
+                         kAudioUnitParameterUnit_Decibels            = 13
+                         kAudioUnitParameterUnit_LinearGain          = 14
+                         kAudioUnitParameterUnit_Degrees             = 15
+                         kAudioUnitParameterUnit_EqualPowerCrossfade = 16
+                         kAudioUnitParameterUnit_MixerFaderCurve1    = 17
+                         kAudioUnitParameterUnit_Pan                 = 18
+                         kAudioUnitParameterUnit_Meters              = 19
+                         kAudioUnitParameterUnit_AbsoluteCents       = 20
+                         kAudioUnitParameterUnit_Octaves             = 21
+                         kAudioUnitParameterUnit_BPM                 = 22
+                         kAudioUnitParameterUnit_Beats               = 23
+                         kAudioUnitParameterUnit_Milliseconds        = 24
+                         kAudioUnitParameterUnit_Ratio               = 25
+                       */
+
+                       /* info.flags to consider */
+
+                       /*
+
+                         kAudioUnitParameterFlag_CFNameRelease       = (1L << 4)
+                         kAudioUnitParameterFlag_HasClump            = (1L << 20)
+                         kAudioUnitParameterFlag_HasName             = (1L << 21)
+                         kAudioUnitParameterFlag_DisplayLogarithmic  = (1L << 22)
+                         kAudioUnitParameterFlag_IsHighResolution    = (1L << 23)
+                         kAudioUnitParameterFlag_NonRealTime         = (1L << 24)
+                         kAudioUnitParameterFlag_CanRamp             = (1L << 25)
+                         kAudioUnitParameterFlag_ExpertMode          = (1L << 26)
+                         kAudioUnitParameterFlag_HasCFNameString     = (1L << 27)
+                         kAudioUnitParameterFlag_IsGlobalMeta        = (1L << 28)
+                         kAudioUnitParameterFlag_IsElementMeta       = (1L << 29)
+                         kAudioUnitParameterFlag_IsReadable          = (1L << 30)
+                         kAudioUnitParameterFlag_IsWritable          = (1L << 31)
+                       */
+
+                       d.integer_step = (info.unit & kAudioUnitParameterUnit_Indexed);
+                       d.toggled = (info.unit & kAudioUnitParameterUnit_Boolean);
+                       d.sr_dependent = (info.unit & kAudioUnitParameterUnit_SampleFrames);
+                       d.automatable = !d.toggled && 
+                               !(info.flags & kAudioUnitParameterFlag_NonRealTime) &&
+                               (info.flags & kAudioUnitParameterFlag_IsWritable);
+                       
+                       d.logarithmic = (info.flags & kAudioUnitParameterFlag_DisplayLogarithmic);
+                       d.unit = info.unit;
+
+                       d.lower = info.minValue;
+                       d.upper = info.maxValue;
+                       d.default_value = info.defaultValue;
+                       d.step = 1.0;
+                       d.smallstep = 0.1;
+                       d.largestep = 10.0;
+                       d.min_unbound = 0; // lower is bound
+                       d.max_unbound = 0; // upper is bound
+
+                       descriptors.push_back (d);
+               }
        }
 }
 
+
 string
 AUPlugin::unique_id () const
 {
@@ -143,13 +256,16 @@ AUPlugin::label () const
 uint32_t
 AUPlugin::parameter_count () const
 {
-       return 0;
+       return descriptors.size();
 }
 
 float
 AUPlugin::default_value (uint32_t port)
 {
-       // AudioUnits don't have default values.  Maybe presets though?
+       if (port < descriptors.size()) {
+               return descriptors[port].default_value;
+       }
+
        return 0;
 }
 
@@ -162,7 +278,7 @@ AUPlugin::latency () const
 void
 AUPlugin::set_parameter (uint32_t which, float val)
 {
-       // unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
+       // unit->SetParameter (id, 0, val);
 }
 
 float
@@ -176,14 +292,23 @@ AUPlugin::get_parameter (uint32_t which) const
 }
 
 int
-AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const
+AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& pd) const
 {
-       return 0;
+       if (which < descriptors.size()) {
+               pd = descriptors[which];
+               return 0;
+       } 
+       return -1;
 }
 
 uint32_t
 AUPlugin::nth_parameter (uint32_t which, bool& ok) const
 {
+       if (which < descriptors.size()) {
+               ok = true;
+               return which;
+       }
+       ok = false;
        return 0;
 }
 
@@ -224,9 +349,6 @@ AUPlugin::_set_block_size (nframes_t nframes)
                unit->Uninitialize ();
        }
 
-       set_input_format ();
-       set_output_format ();
-
        if ((err = unit->SetProperty (kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 
                                      0, &numFrames, sizeof (numFrames))) != noErr) {
                cerr << "cannot set max frames (err = " << err << ')' << endl;
@@ -242,10 +364,13 @@ AUPlugin::_set_block_size (nframes_t nframes)
 
 int32_t 
 AUPlugin::can_support_input_configuration (int32_t in)
-{
-       streamFormat.mBytesPerPacket = 4 * in;
-       streamFormat.mBytesPerFrame = 4 * in;
+{      
        streamFormat.mChannelsPerFrame = in;
+       /* apple says that for non-interleaved data, these
+          values always refer to a single channel.
+       */
+       streamFormat.mBytesPerPacket = 4;
+       streamFormat.mBytesPerFrame = 4;
 
        if (set_input_format () == 0) {
                return 1;
@@ -273,12 +398,18 @@ AUPlugin::set_stream_format (int scope, uint32_t cnt)
 
        for (uint32_t i = 0; i < cnt; ++i) {
                if ((result = unit->SetFormat (scope, i, streamFormat)) != 0) {
-                       error << string_compose (_("AUPlugin: could not set stream format for %1/%2"),
-                                                (scope == kAudioUnitScope_Input ? "input" : "output"), i) << endmsg;
+                       error << string_compose (_("AUPlugin: could not set stream format for %1/%2 (err = %3)"),
+                                                (scope == kAudioUnitScope_Input ? "input" : "output"), i, result) << endmsg;
                        return -1;
                }
        }
 
+       if (scope == kAudioUnitScope_Input) {
+               format_set |= 0x1;
+       } else {
+               format_set |= 0x2;
+       }
+
        return 0;
 }
 
@@ -311,8 +442,8 @@ AUPlugin::compute_output_streams (int32_t nplugins)
 uint32_t
 AUPlugin::output_streams() const
 {
-       if (!initialized) {
-               warning << _("AUPlugin: output_streams() called without calling Initialize!") << endmsg;
+       if (!(format_set & 0x2)) {
+               warning << _("AUPlugin: output_streams() called without any format set!") << endmsg;
                return 1;
        }
        return streamFormat.mChannelsPerFrame;
@@ -322,8 +453,8 @@ AUPlugin::output_streams() const
 uint32_t
 AUPlugin::input_streams() const
 {
-       if (!initialized) {
-               warning << _("AUPlugin: input_streams() called without calling Initialize!") << endmsg;
+       if (!(format_set & 0x1)) {
+               warning << _("AUPlugin: input_streams() called without any format set!") << endmsg;
                return 1;
        }
        return streamFormat.mChannelsPerFrame;
@@ -396,20 +527,26 @@ set<uint32_t>
 AUPlugin::automatable() const
 {
        set<uint32_t> automates;
-       
+
+       for (uint32_t i = 0; i < descriptors.size(); ++i) {
+               if (descriptors[i].automatable) {
+                       automates.insert (i);
+               }
+       }
+
        return automates;
 }
 
 string
-AUPlugin::describe_parameter (uint32_t)
+AUPlugin::describe_parameter (uint32_t param)
 {
-       return "";
+       return descriptors[param].label;
 }
 
 void
-AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const
+AUPlugin::print_parameter (uint32_t param, char* buf, uint32_t len) const
 {
-       
+       // NameValue stuff here
 }
 
 bool
@@ -421,7 +558,7 @@ AUPlugin::parameter_is_audio (uint32_t) const
 bool
 AUPlugin::parameter_is_control (uint32_t) const
 {
-       return false;
+       return true;
 }
 
 bool
@@ -478,7 +615,7 @@ AUPlugin::has_editor () const
        return true;
 }
 
-AUPluginInfo::AUPluginInfo (CAComponentDescription* d)
+AUPluginInfo::AUPluginInfo (boost::shared_ptr<CAComponentDescription> d)
        : descriptor (d)
 {
 
@@ -486,9 +623,6 @@ AUPluginInfo::AUPluginInfo (CAComponentDescription* d)
 
 AUPluginInfo::~AUPluginInfo ()
 {
-       if (descriptor) {
-               delete descriptor;
-       }
 }
 
 PluginPtr
@@ -497,7 +631,7 @@ AUPluginInfo::load (Session& session)
        try {
                PluginPtr plugin;
 
-               CAComponent* comp = new CAComponent(*descriptor);
+               boost::shared_ptr<CAComponent> comp (new CAComponent(*descriptor));
                
                if (!comp->IsValid()) {
                        error << ("AudioUnit: not a valid Component") << endmsg;
@@ -505,7 +639,7 @@ AUPluginInfo::load (Session& session)
                        plugin.reset (new AUPlugin (session.engine(), session, comp));
                }
                
-               plugin->set_info(PluginInfoPtr(new AUPluginInfo(*this)));
+               plugin->set_info (PluginInfoPtr (new AUPluginInfo (*this)));
                return plugin;
        }
 
@@ -518,7 +652,7 @@ PluginInfoList
 AUPluginInfo::discover ()
 {
        PluginInfoList plugs;
-
+       
        discover_fx (plugs);
        discover_music (plugs);
 
@@ -562,7 +696,8 @@ AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescrip
                CAComponentDescription temp;
                GetComponentInfo (comp, &temp, NULL, NULL, NULL);
 
-               AUPluginInfoPtr info (new AUPluginInfo (new CAComponentDescription(temp)));
+               AUPluginInfoPtr info (new AUPluginInfo 
+                                     (boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
 
                /* no panners, format converters or i/o AU's for our purposes
                 */