Merge with 2.0-ongoing R3071.
authorDavid Robillard <d@drobilla.net>
Sat, 16 Feb 2008 22:55:47 +0000 (22:55 +0000)
committerDavid Robillard <d@drobilla.net>
Sat, 16 Feb 2008 22:55:47 +0000 (22:55 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@3074 d708f5d6-7413-0410-9779-e7cbd77b26cf

57 files changed:
SConstruct
ardour.rc.in
gtk2_ardour/audio_region_view.cc
libs/appleutility/AUParamInfo.cpp [new file with mode: 0644]
libs/appleutility/AUParamInfo.h [new file with mode: 0644]
libs/appleutility/CAAUParameter.cpp [new file with mode: 0644]
libs/appleutility/CAAUParameter.h [new file with mode: 0644]
libs/ardour/SConscript
libs/ardour/analyser.cc
libs/ardour/ardour/ardour.h
libs/ardour/ardour/audio_unit.h
libs/ardour/ardour/audiosource.h
libs/ardour/ardour/automatable.h
libs/ardour/ardour/configuration_vars.h
libs/ardour/ardour/io.h
libs/ardour/ardour/io_processor.h
libs/ardour/ardour/playlist.h
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/ardour/types.h
libs/ardour/ardour/utils.h
libs/ardour/audio_track.cc
libs/ardour/audio_unit.cc
libs/ardour/audioengine.cc
libs/ardour/audiofilesource.cc
libs/ardour/audioregion.cc
libs/ardour/audiosource.cc
libs/ardour/automatable.cc
libs/ardour/filter.cc
libs/ardour/globals.cc
libs/ardour/import.cc
libs/ardour/io.cc
libs/ardour/playlist.cc
libs/ardour/plugin.cc
libs/ardour/region.cc
libs/ardour/route.cc
libs/ardour/session.cc
libs/ardour/session_state.cc
libs/ardour/session_transport.cc
libs/ardour/source.cc
libs/ardour/transient_detector.cc
libs/ardour/utils.cc
libs/gtkmm2/pango/SConscript
libs/gtkmm2ext/SConscript
libs/gtkmm2ext/gtk_ui.cc
libs/gtkmm2ext/gtkmm2ext/pixfader.h
libs/gtkmm2ext/gtkmm2ext/slider_controller.h
libs/gtkmm2ext/gtkmm2ext/sync-menu.h [new file with mode: 0644]
libs/gtkmm2ext/pixfader.cc
libs/gtkmm2ext/slider_controller.cc
libs/gtkmm2ext/sync-menu.c [new file with mode: 0644]
libs/pbd/misc.c
libs/vamp-plugins/SConscript
svn_revision.h
tools/osx_packaging/app_build.rb
tools/osx_packaging/bin/exporter
vst/SConscript

index 33cb8b7feb3bd0410f153e5004ad06ffa967ea1c..cb070e2ec55a65fb4c0d2a0baa7278abd6067b85 100644 (file)
@@ -31,6 +31,7 @@ opts.AddOptions(
     BoolOption('COREAUDIO', 'Compile with Apple\'s CoreAudio library', 0),
     BoolOption('GTKOSX', 'Compile for use with GTK-OSX, not GTK-X11', 0),
     BoolOption('NATIVE_OSX_KEYS', 'Build key bindings file that matches OS X conventions', 0),
+    BoolOption('OLDFONTS', 'Old school font sizes', 0),
     BoolOption('DEBUG', 'Set to build with debugging information and no optimizations', 0),
     PathOption('DESTDIR', 'Set the intermediate install "prefix"', '/'),
     EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'leopard', 'none' ), ignorecase=2),
@@ -538,7 +539,7 @@ if env['LV2']:
        else:
                print 'Building Ardour with LV2 support requires SLV2 >= 0.6.0'
                print 'WARNING: SLV2 not found, or too old.  Ardour will be built without LV2 support.'
-               print 'Until the 2.3 release, Ardour requires SLV2 out of SVN.'
+               print 'Until the 2.4 release, Ardour requires SLV2 out of SVN.'
                print 'Testing would be very much appreciated!  svn co http://svn.drobilla.net/lad/slv2'
                env['LV2'] = 0
        conf.Finish()
index ed40ac465a2d07a0af085447aa2d4de4ca98df96..5c35fd45aa9d82086cfa0892e1c528ee079e8c9b 100644 (file)
@@ -21,6 +21,7 @@
     <Option name="plugins-stop-with-transport" value="no"/>
     <Option name="no-sw-monitoring" value="no"/>
     <Option name="stop-recording-on-xrun" value="no"/>
+       <Option name="create-xrun-marker" value="yes"/>
     <Option name="stop-at-session-end" value="no"/>
     <Option name="auto-xfade" value="yes"/>
     <Option name="crossfades-active" value="1"/>
index 901b52ec1df3772b2a977a2a4beed0be442023fe..2b4b4bbe3fdc2a012face3eb5aa997236845ca6a 100644 (file)
@@ -809,6 +809,8 @@ AudioRegionView::create_waves ()
 
        ChanCount nchans = atv.get_diskstream()->n_channels();
 
+       cerr << "creating waves for " << _region->name() << " with wfd = " << wait_for_data << " and channels = " << nchans << endl;
+       
        /* in tmp_waves, set up null pointers for each channel so the vector is allocated */
        for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
                tmp_waves.push_back (0);
@@ -822,15 +824,20 @@ AudioRegionView::create_waves ()
                
                wave_caches.push_back (WaveView::create_cache ());
 
+               cerr << "\tchannel " << n << endl;
+
                if (wait_for_data) {
                        if (audio_region()->audio_source(n)->peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) {
+                               cerr << "\tData is ready\n";
                                create_one_wave (n, true);
                        } else {
+                               cerr << "\tdata is not ready\n";
                                // we'll get a PeaksReady signal from the source in the future
                                // and will call create_one_wave(n) then.
                        }
                        
                } else {
+                       cerr << "\tdon't delay, display today!\n";
                        create_one_wave (n, true);
                }
 
diff --git a/libs/appleutility/AUParamInfo.cpp b/libs/appleutility/AUParamInfo.cpp
new file mode 100644 (file)
index 0000000..9b00461
--- /dev/null
@@ -0,0 +1,134 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       AUParamInfo.cpp
+       
+=============================================================================*/
+#include "AUParamInfo.h"
+#include "CAXException.h"
+
+AUParamInfo::AUParamInfo (AudioUnit                            inAU, 
+                                                       bool                            inIncludeExpert, 
+                                                       bool                            inIncludeReadOnly,
+                                                       AudioUnitScope          inScope,
+                                                       AudioUnitElement        inElement)
+       : mAU (inAU),
+         mNumParams (0),
+         mParamListID(NULL),
+         mScope (inScope),
+         mElement (inElement)
+{
+       UInt32 size;
+       OSStatus result = AudioUnitGetPropertyInfo(mAU, kAudioUnitProperty_ParameterList, inScope, mElement, &size, NULL);
+               if (size == 0 || result) return;
+       
+       int nparams = size / sizeof(AudioUnitPropertyID);
+       mParamListID = new AudioUnitParameterID[nparams];
+
+       memset (mParamListID, 0xFF, size);
+
+       AudioUnitParameterID *paramList = new AudioUnitParameterID[nparams];
+       
+       result = AudioUnitGetProperty(mAU, kAudioUnitProperty_ParameterList, mScope, mElement, paramList, &size);
+       if (result) {
+               delete [] mParamListID;
+               delete [] paramList;
+               mParamListID = NULL;
+               return;
+       }
+       
+       ParameterMap params;
+       for (int i = 0; i < nparams; ++i) 
+       {
+               CAAUParameter auvp (mAU, paramList[i], mScope, mElement); // took out only using global scope in CAAUParameter creation
+               const AudioUnitParameterInfo &paramInfo = auvp.ParamInfo();
+                       
+               //      don't include if parameter can't be read or written
+               if (!(paramInfo.flags & kAudioUnitParameterFlag_IsWritable) 
+                       && !(paramInfo.flags & kAudioUnitParameterFlag_IsReadable))
+                       continue;
+
+               // only include if expert params wanted
+               if (!inIncludeExpert && auvp.IsExpert())
+                       continue;
+               
+               // only include if read only params are wanted
+               if (!(paramInfo.flags & kAudioUnitParameterFlag_IsWritable) 
+                       && (paramInfo.flags & kAudioUnitParameterFlag_IsReadable))
+               {       
+                       if (!inIncludeReadOnly)
+                               continue;
+               }
+               
+               mParamListID[mNumParams] = paramList[i];
+               mNumParams++;
+               
+               // ok - if we're here, then we have a parameter we are going to display.
+               UInt32 clump = 0;
+               auvp.GetClumpID (clump);
+               mParams[clump].push_back (auvp);
+       }
+
+       delete [] paramList;
+}
+
+AUParamInfo::~AUParamInfo()
+{
+       delete [] mParamListID;
+}
+
+UInt32                 AUParamInfo::NumParamsForClump (UInt32 inClump) const
+{ 
+       ParameterMap::const_iterator it = mParams.find(inClump);
+       if (it != mParams.end()) 
+               return (*it).second.size();
+       return 0;
+}
+
+const CAAUParameter*   AUParamInfo::GetParamInfo (AudioUnitParameterID inParamID) const
+{
+       for (ParameterMap::const_iterator it = mParams.begin(); it != mParams.end(); ++it) {
+               const ParameterList &list = (*it).second;
+               for (ParameterList::const_iterator iter = list.begin(); iter != list.end(); ++iter) {
+                       if (inParamID == (*iter).mParameterID) {
+                               return &(*iter);
+                       }
+               }
+       }
+       return NULL;
+}
diff --git a/libs/appleutility/AUParamInfo.h b/libs/appleutility/AUParamInfo.h
new file mode 100644 (file)
index 0000000..9d34208
--- /dev/null
@@ -0,0 +1,107 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       AUParamInfo.h
+       
+=============================================================================*/
+#include <map>
+#include <vector>
+#include <AudioUnit/AudioUnit.h>
+#include "CAAUParameter.h"
+
+/*
+       The ParameterMap returned by the Map() method is a map where 
+               - the key is the clumpID
+               - the value is a ParameterList (vector<CAAUParameter>)
+               
+       If you have parameters on multiple scopes (or elements within a scope), then you should create one of these 
+       for each scope-element pair
+*/
+
+class AUParamInfo {
+
+public:
+       typedef std::vector <CAAUParameter> ParameterList;
+       typedef std::map <UInt32, ParameterList, std::less<UInt32> > ParameterMap;
+
+
+
+                                                       AUParamInfo (AudioUnit          inAU, 
+                                                                       bool                            inIncludeExpert, 
+                                                                       bool                            inIncludeReadOnly, 
+                                                                       AudioUnitScope          inScope = kAudioUnitScope_Global,
+                                                                       AudioUnitElement        inElement = 0);
+                                                                       
+                                                       ~AUParamInfo();
+                                                       
+       const ParameterMap&             Map () const { return mParams; }
+       
+       // some convenience methods
+       UInt32                                  NumParams () const { return mNumParams; }
+       
+       AudioUnitParameterID    ParamID (UInt32 inIndex) const 
+                                                       { 
+                                                               if (inIndex < mNumParams) return mParamListID[inIndex]; 
+                                                               return 0xFFFFFFFF; 
+                                                       }
+                                                        
+       UInt32                                  NumClumps () const { return mParams.size(); }
+
+       UInt32                                  NumParamsForClump (UInt32 inClump) const;
+       
+                       // returns NULL if there's no info for the parameter
+       const CAAUParameter*    GetParamInfo (AudioUnitParameterID inParamID) const;
+       
+       AudioUnitScope                  GetScope () const { return mScope; }
+       AudioUnitElement                GetElement () const { return mElement; }
+       
+private:
+
+       AudioUnit                               mAU;
+       UInt32                                  mNumParams;
+       AudioUnitParameterID *  mParamListID;
+       
+       ParameterMap                    mParams;
+       AudioUnitScope                  mScope;
+       AudioUnitElement                mElement;
+               
+               // disallow
+       AUParamInfo () {}
+       AUParamInfo (const AUParamInfo &c) {}
+       AUParamInfo& operator= (const AUParamInfo& c) { return *this; }
+};
diff --git a/libs/appleutility/CAAUParameter.cpp b/libs/appleutility/CAAUParameter.cpp
new file mode 100644 (file)
index 0000000..b99b6ab
--- /dev/null
@@ -0,0 +1,316 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       CAAUParameter.cpp
+       
+=============================================================================*/
+
+#include "CAAUParameter.h"
+
+CAAUParameter::CAAUParameter() 
+{
+       memset(this, 0, sizeof(CAAUParameter));
+}
+
+CAAUParameter::CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element)
+{
+       memset(this, 0, sizeof(CAAUParameter));
+       Init (au, param, scope, element);
+}
+
+CAAUParameter::CAAUParameter (AudioUnitParameter &inParam)
+{
+       memset(this, 0, sizeof(CAAUParameter));
+       Init (inParam.mAudioUnit, inParam.mParameterID, inParam.mScope, inParam.mElement);
+}
+
+CAAUParameter::CAAUParameter(const CAAUParameter &a) 
+{
+       memset(this, 0, sizeof(CAAUParameter));
+       *this = a;
+}
+
+CAAUParameter &        CAAUParameter::operator = (const CAAUParameter &a)
+{
+       if (mParamName) CFRelease(mParamName);
+       if (mParamTag) CFRelease(mParamTag);
+       if (mNamedParams) CFRelease(mNamedParams);
+       
+       memcpy(this, &a, sizeof(CAAUParameter));
+
+       if (mParamName) CFRetain(mParamName);
+       if (mParamTag) CFRetain(mParamTag);
+       if (mNamedParams) CFRetain(mNamedParams);
+       
+       return *this;
+}
+
+CAAUParameter::~CAAUParameter()
+{
+       if (mParamName) CFRelease(mParamName);
+       if (mParamTag) CFRelease(mParamTag);
+       if (mNamedParams) CFRelease (mNamedParams);
+}
+
+void           CAAUParameter::Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element)
+{
+       mAudioUnit = au;
+       mParameterID = param;
+       mScope = scope;
+       mElement = element;
+       
+       UInt32 propertySize = sizeof(mParamInfo);
+       OSStatus err = AudioUnitGetProperty(au, kAudioUnitProperty_ParameterInfo,
+                       scope, param, &mParamInfo, &propertySize);
+       if (err)
+               memset(&mParamInfo, 0, sizeof(mParamInfo));
+       if (mParamInfo.flags & kAudioUnitParameterFlag_HasCFNameString) {
+               mParamName = mParamInfo.cfNameString;
+               if (!(mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease)) 
+                       CFRetain (mParamName);
+       } else
+               mParamName = CFStringCreateWithCString(NULL, mParamInfo.name, kCFStringEncodingUTF8);
+       
+       char* str = 0;
+       switch (mParamInfo.unit)
+       {
+               case kAudioUnitParameterUnit_Boolean:
+                       str = "T/F";
+                       break;
+               case kAudioUnitParameterUnit_Percent:
+               case kAudioUnitParameterUnit_EqualPowerCrossfade:
+                       str = "%";
+                       break;
+               case kAudioUnitParameterUnit_Seconds:
+                       str = "Secs";
+                       break;
+               case kAudioUnitParameterUnit_SampleFrames:
+                       str = "Samps";
+                       break;
+               case kAudioUnitParameterUnit_Phase:
+               case kAudioUnitParameterUnit_Degrees:
+                       str = "Degr.";
+                       break;
+               case kAudioUnitParameterUnit_Hertz:
+                       str = "Hz";
+                       break;
+               case kAudioUnitParameterUnit_Cents:
+               case kAudioUnitParameterUnit_AbsoluteCents:
+                       str = "Cents";
+                       break;
+               case kAudioUnitParameterUnit_RelativeSemiTones:
+                       str = "S-T";
+                       break;
+               case kAudioUnitParameterUnit_MIDINoteNumber:
+               case kAudioUnitParameterUnit_MIDIController:
+                       str = "MIDI";
+                               //these are inclusive, so add one value here
+                       mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue);
+                       break;
+               case kAudioUnitParameterUnit_Decibels:
+                       str = "dB";
+                       break;
+               case kAudioUnitParameterUnit_MixerFaderCurve1:
+               case kAudioUnitParameterUnit_LinearGain:
+                       str = "Gain";
+                       break;
+               case kAudioUnitParameterUnit_Pan:
+                       str = "L/R";
+                       break;
+               case kAudioUnitParameterUnit_Meters:
+                       str = "Mtrs";
+                       break;
+               case kAudioUnitParameterUnit_Octaves:
+                       str = "8ve";
+                       break;
+               case kAudioUnitParameterUnit_BPM:
+                       str = "BPM";
+                       break;
+               case kAudioUnitParameterUnit_Beats:
+                       str = "Beats";
+                       break;
+               case kAudioUnitParameterUnit_Milliseconds:
+                       str = "msecs";
+                       break;
+               case kAudioUnitParameterUnit_Ratio:
+                       str = "ratio";
+                       break;
+               case kAudioUnitParameterUnit_Indexed:
+                       {
+                               propertySize = sizeof(mNamedParams);
+                               err = AudioUnitGetProperty (au, 
+                                                                       kAudioUnitProperty_ParameterValueStrings,
+                                                                       scope, 
+                                                                       param, 
+                                                                       &mNamedParams, 
+                                                                       &propertySize);
+                               if (!err && mNamedParams) {
+                                       mNumIndexedParams = CFArrayGetCount(mNamedParams);
+                               } else {
+                                               //these are inclusive, so add one value here
+                                       mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue);
+                               }
+                               str = NULL;
+                       }
+                       break;
+               case kAudioUnitParameterUnit_CustomUnit:
+               {
+                       CFStringRef unitName = mParamInfo.unitName;
+                       static char paramStr[256];
+                       CFStringGetCString (unitName, paramStr, 256, kCFStringEncodingUTF8);
+                       if (mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease)
+                               CFRelease (unitName);
+                       str = paramStr;
+                       break;
+               }
+               case kAudioUnitParameterUnit_Generic:
+               case kAudioUnitParameterUnit_Rate:
+               default:
+                       str = NULL;
+                       break;
+       }
+       
+       if (str)
+               mParamTag = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
+       else
+               mParamTag = NULL;
+}
+
+
+Float32                CAAUParameter::GetValue() const
+{
+       Float32 value = 0.;
+       //OSStatus err = 
+       AudioUnitGetParameter(mAudioUnit, mParameterID, mScope, mElement, &value);
+       return value;
+}
+
+CFStringRef CAAUParameter::GetStringFromValueCopy(const Float32 *value) const
+{
+       if (HasNamedParams())
+       {
+               Float32 val = (value == NULL ? GetValue() : *value);
+               int index = int(mParamInfo.minValue) + int(val);
+               CFStringRef str = GetParamName (index);
+               if (str) {
+                       CFRetain (str);
+                       return str;
+               }
+       }
+       else if (ValuesHaveStrings()) 
+       {
+               AudioUnitParameterStringFromValue stringValue;
+               stringValue.inParamID = mParameterID;
+               stringValue.inValue = value;
+               stringValue.outString = NULL;
+               UInt32 propertySize = sizeof(stringValue);
+               
+               OSStatus err = AudioUnitGetProperty (mAudioUnit, 
+                                                                                       kAudioUnitProperty_ParameterStringFromValue,
+                                                                                       mScope, 
+                                                                                       mParameterID, 
+                                                                                       &stringValue, 
+                                                                                       &propertySize);
+               
+               if (err == noErr && stringValue.outString != NULL)
+                       return stringValue.outString;
+       }
+       
+       Float32 val = (value == NULL ? GetValue() : *value);
+       char valstr[32];
+       AUParameterFormatValue (val, this, valstr, 4);
+       return CFStringCreateWithCString(NULL, valstr, kCFStringEncodingUTF8);
+}
+
+Float32 CAAUParameter::GetValueFromString(CFStringRef str) const
+{
+       if (ValuesHaveStrings()) 
+       {
+               AudioUnitParameterValueFromString valueString;
+               valueString.inParamID = mParameterID;
+               valueString.inString = str;
+               UInt32 propertySize = sizeof(valueString);
+               
+               OSStatus err = AudioUnitGetProperty (mAudioUnit, 
+                                                                               kAudioUnitProperty_ParameterValueFromString,
+                                                                               mScope, 
+                                                                               mParameterID, 
+                                                                               &valueString, 
+                                                                               &propertySize);
+                                                                               
+               if (err == noErr) {
+                       return valueString.outValue;
+               }
+       }
+       
+       Float32 paramValue = mParamInfo.defaultValue;
+       char valstr[32];
+       CFStringGetCString(str, valstr, sizeof(valstr), kCFStringEncodingUTF8);
+       sscanf(valstr, "%f", &paramValue);
+       return paramValue;
+}
+
+void           CAAUParameter::SetValue(        AUParameterListenerRef          inListener, 
+                                                                       void *                                                  inObject,
+                                                                       Float32                                                 inValue) const
+{
+    // clip inValue as: maxValue >= inValue >= minValue before setting
+    Float32 valueToSet = inValue;
+    if (valueToSet > mParamInfo.maxValue)
+        valueToSet = mParamInfo.maxValue;
+    if (valueToSet < mParamInfo.minValue)
+        valueToSet = mParamInfo.minValue;
+    
+       AUParameterSet(inListener, inObject, this, valueToSet, 0);
+}
+
+#if DEBUG
+void   CAAUParameter::Print() const
+{
+       UInt32 clump = 0;
+       GetClumpID (clump);
+       
+       UInt32 len = CFStringGetLength(mParamName);
+       char* chars = (char*)malloc (len * 2); // give us plenty of room for unichar chars
+       if (!CFStringGetCString (mParamName, chars, len * 2, kCFStringEncodingUTF8))
+               chars[0] = 0;
+       
+       printf ("ID: %ld, Clump: %ld, Name: %s\n", mParameterID, clump, chars);
+       free (chars);
+}
+#endif
diff --git a/libs/appleutility/CAAUParameter.h b/libs/appleutility/CAAUParameter.h
new file mode 100644 (file)
index 0000000..4f35b26
--- /dev/null
@@ -0,0 +1,187 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       CAAUParameter.h
+       
+=============================================================================*/
+
+#ifndef __CAAUParameter_h__
+#define __CAAUParameter_h__
+
+#include <AudioToolbox/AudioUnitUtilities.h>
+
+// ____________________________________________________________________________
+//     CAAUParameter
+//     complete parameter specification
+       /*! @class CAAUParameter */
+class CAAUParameter : public AudioUnitParameter {
+public:
+                                                               /*! @ctor CAAUParameter.0 */
+                                                               CAAUParameter();
+                                                               /*! @ctor CAAUParameter.1 */
+                                                               CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element);
+                                                               /*! @ctor CAAUParameter.2 */
+                                                               CAAUParameter(AudioUnitParameter &inParam);
+                                                               /*! @ctor CAAUParameter.3 */
+                                                               CAAUParameter(const CAAUParameter &a);
+                                                               /*! @dtor ~CAAUParameter */
+                                                               ~CAAUParameter();
+               
+       /*! @method operator <@ */
+       bool                                            operator < (const CAAUParameter &a) const 
+                                                               { 
+                                                                       return memcmp(this, &a, sizeof(AudioUnitParameter)) < 0; 
+                                                               }
+
+       /*! @method operator ==@ */
+       bool                                            operator == (const CAAUParameter &a) const 
+                                                               { 
+                                                                       return !memcmp(this, &a, sizeof(AudioUnitParameter)); 
+                                                               }
+       
+       /*! @method operator =@ */
+       CAAUParameter &                         operator = (const CAAUParameter &a);
+       
+       /*! @method GetValue */
+       Float32                                         GetValue() const;
+       /*! @method SetValue */
+       void                                            SetValue(       AUParameterListenerRef                  inListener, 
+                                                                                       void *                                                  inObject,
+                                                                                       Float32                                                 inValue) const;
+       
+       /*! @method GetName */
+       CFStringRef                                     GetName() const { return mParamName; }  
+                                                                               // borrowed reference!
+
+       /*! @method GetStringFromValueCopy */
+       CFStringRef                                     GetStringFromValueCopy(const Float32 *value = NULL) const;      
+                                                                               // returns a copy of the name of the current parameter value
+                                                                               // or null if there is no name associated
+                                                                               // caller must release
+       /*! @method ValuesHaveStrings */
+       bool                                            ValuesHaveStrings () const 
+                                                               { 
+                                                                       return (mParamInfo.flags & kAudioUnitParameterFlag_ValuesHaveStrings) != 0; 
+                                                               }
+       
+       /*! @method GetValueFromString */
+       Float32                                         GetValueFromString (CFStringRef str) const;                                     
+                                                                       // caller must release
+
+       /*! @method ParamInfo */
+       const AudioUnitParameterInfo &          
+                                                               ParamInfo()     const { return mParamInfo; }
+
+       /*! @method GetParamTag */
+       CFStringRef                                     GetParamTag() const     { return mParamTag; }
+                                                                       // this may return null! - 
+                                                                       // in which case there is no descriptive tag for the parameter
+
+       /*! @method GetParamName */
+       CFStringRef                                     GetParamName (int inIndex) const
+                                                                       // this can return null if there is no name for the parameter
+                                                               { 
+                                                                       return (mNamedParams && inIndex < mNumIndexedParams) 
+                                                                                               ? (CFStringRef) CFArrayGetValueAtIndex(mNamedParams, inIndex)
+                                                                                               : 0; 
+                                                               }
+       
+       /*! @method GetNumIndexedParams */
+       int                                                     GetNumIndexedParams () const { return mNumIndexedParams; }
+       
+       /*! @method IsIndexedParam */
+       bool                                            IsIndexedParam () const { return mNumIndexedParams != 0; }
+       
+       /*! @method HasNamedParams */
+       bool                                            HasNamedParams () const { return IsIndexedParam() && mNamedParams; }
+       
+       /*! @method GetClumpID */
+       bool                                            GetClumpID (UInt32 &outClumpID) const 
+                                                               { 
+                                                                       if (mParamInfo.flags & kAudioUnitParameterFlag_HasClump) {
+                                                                               outClumpID = mParamInfo.clumpID;
+                                                                               return true;
+                                                                       }
+                                                                       return false;
+                                                               }
+                                                               
+       /*! @method HasDisplayTransformation */
+       bool                                            HasDisplayTransformation () const 
+                                                               { 
+                                                                       return GetAudioUnitParameterDisplayType (mParamInfo.flags); 
+                                                               }
+
+       /*! @method IsExpert */
+       bool                                            IsExpert () const 
+                                                               { 
+                                                                       return mParamInfo.flags & kAudioUnitParameterFlag_ExpertMode; 
+                                                               }
+#if DEBUG
+       void                                            Print () const;
+#endif
+       
+               // these methods are defined in CAPersistence.cpp
+               // they will persist and restore only the scope, element and param ID's of the AudioUnitParameter
+               // however, this is sufficient to be able to save/restore a CAAUParameter object
+       void                                            Save (CFPropertyListRef &outData) const;
+       
+       static void                                     Save (const AudioUnitParameter &inParam, CFPropertyListRef &outData);
+       
+       static OSStatus                         Restore (const CFPropertyListRef inData, AudioUnitParameter &outParam);
+
+protected:
+       // cached parameter info
+       /*! @var mParamInfo */
+       AudioUnitParameterInfo          mParamInfo;
+       /*! @var mParamName */
+       CFStringRef                                     mParamName;
+       /*! @var mParamTag */
+       CFStringRef                                     mParamTag;
+       /*! @var mNumIndexedParams */
+       short                                           mNumIndexedParams;
+       /*! @var mNamedParams */
+       CFArrayRef                                      mNamedParams;
+       
+private:
+       void                                            Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element);
+
+};
+
+
+
+#endif // __CAAUParameter_h__
index 529a7789420df5009bc3a7fe050bd71a3e13af4c..7521bd728a6192ed14737853d6297828a2bdb6f0 100644 (file)
@@ -20,6 +20,9 @@ ardour.Append(CXXFLAGS=["-DLIBSIGC_DISABLE_DEPRECATED", "-DGLIBMM_EXCEPTIONS_ENA
 ardour.Append(PACKAGE = domain)
 ardour.Append(POTFILE = domain + '.pot')
 
+if ardour['IS_OSX']:
+       ardour.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
+
 #
 # explicitly reference the control protocol LGPL library for includes
 # 
@@ -312,7 +315,7 @@ ardour.Merge ([
             libraries['sndfile-ardour'],
             libraries['vamp'],
             libraries['vamphost'],
-            libraries['xml'],
+            libraries['xml']
             ])
 
 if ardour['RUBBERBAND']:
@@ -380,5 +383,10 @@ env.Alias('tarball', env.Distribute (env['DISTTREE'],
                                     [ 'SConscript', 'i18n.h', 'gettext.h' ] + 
                                     [ 'sse_functions_xmm.cc', 'sse_functions.s', 'sse_functions_64bit.s' ] +
                                     [ 'rb_effect.cc', 'st_stretch.cc', 'st_pitch.cc' ] +
-                                    ardour_files + osc_files + vst_files + coreaudio_files + audiounit_files +
+                                    ardour_files + 
+                                    osc_files + 
+                                    vst_files + 
+                                    coreaudio_files + 
+                                    audiounit_files +
+                                    lv2_files +
                                     glob.glob('po/*.po') + glob.glob('ardour/*.h')))
index 7ddb5428e97d35737d4c1ff938f9a4ee3e4babf1..2e14c74b86e267016340b9d7764e5f41c33b3694 100644 (file)
@@ -95,7 +95,7 @@ Analyser::work ()
 
                boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
 
-               if (afs) {
+               if (afs && afs->length()) {
                        analyse_audio_file_source (afs);
                }
        }
index fcec83394f14ee7d56bc3cd3659c375eebe352f9..6f653f10bfe37d5554938f00bc9145b22be880b3 100644 (file)
 #ifndef __ardour_ardour_h__
 #define __ardour_ardour_h__
 
-#include <limits.h>
+#include <map>
 #include <string>
+
+#include <limits.h>
 #include <signal.h>
 
 #include <pbd/error.h>
@@ -43,12 +45,15 @@ namespace ARDOUR {
        extern OSC* osc;
 
        static const nframes_t max_frames = JACK_MAX_FRAMES;
+       extern sigc::signal<void,std::string> BootMessage;
 
        int init (bool with_vst, bool try_optimization);
        int cleanup ();
 
        std::string get_ardour_revision ();
        
+       void find_bindings_files (std::map<std::string,std::string>&);
+       
        const layer_t max_layer = UCHAR_MAX;
 
        microseconds_t get_microseconds ();
index c781e8200dd90c349b4f15e12e3fe9dab4328ad0..bdeac0477bbd21a5121cc0f981bd5a37a8e81381 100644 (file)
@@ -32,6 +32,7 @@
 #include <ardour/plugin.h>
 
 #include <AudioUnit/AudioUnit.h>
+#include <appleutility/AUParamInfo.h>
 
 #include <boost/shared_ptr.hpp>
 
@@ -45,6 +46,16 @@ namespace ARDOUR {
 class AudioEngine;
 class Session;
 
+struct AUParameterDescriptor : public Plugin::ParameterDescriptor {
+       // additional fields to make operations more efficient
+       AudioUnitParameterID id;
+       AudioUnitScope scope;
+       AudioUnitElement element;
+       float default_value;
+       bool automatable;
+       AudioUnitParameterUnit unit;
+};
+
 class AUPlugin : public ARDOUR::Plugin
 {
   public:
@@ -105,7 +116,7 @@ class AUPlugin : public ARDOUR::Plugin
   private:
         boost::shared_ptr<CAComponent> comp;
         boost::shared_ptr<CAAudioUnit> unit;
-       
+
        AudioStreamBasicDescription streamFormat;
         bool initialized;
         int format_set;
@@ -119,6 +130,7 @@ class AUPlugin : public ARDOUR::Plugin
        int set_input_format ();
        int set_stream_format (int scope, uint32_t cnt);
         int _set_block_size (nframes_t nframes);
+       void discover_parameters ();
 
        std::vector<std::pair<uint32_t, uint32_t> > parameter_map;
        uint32_t current_maxbuf;
@@ -126,6 +138,8 @@ class AUPlugin : public ARDOUR::Plugin
         nframes_t cb_offset;
         vector<Sample*>* current_buffers;
         nframes_t frames_processed;
+       
+       std::vector<AUParameterDescriptor> descriptors;
 };
        
 typedef boost::shared_ptr<AUPlugin> AUPluginPtr;
index 1589841baad27b9afa654d4ad6d994f02833997d..d11b8296948436341048a4477af9cbcb7681eb1b 100644 (file)
@@ -116,7 +116,6 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
        static bool _build_peakfiles;
 
        bool                 _peaks_built;
-       bool                 _analysed;
        mutable Glib::Mutex  _lock;
        mutable Glib::Mutex  _peaks_ready_lock;
        Glib::ustring         peakpath;
index f96ecc0bd139150aea0bf9b74b6582573b67e3d0..a2c1d98ae77b82b30e9f794180f95b77383c53ad 100644 (file)
@@ -57,7 +57,10 @@ public:
 
        virtual void add_control(boost::shared_ptr<AutomationControl>);
 
-       virtual void automation_snapshot(nframes_t now);
+       virtual void automation_snapshot(nframes_t now, bool force);
+       bool should_snapshot (nframes_t now) {
+               return (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval);
+       }
        virtual void transport_stopped(nframes_t now);
 
        virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;
index 134557daebed971c1a0440b72438fdfe2304ff5d..015c6174250803a78ce8ea608d60f8393dfd608f 100644 (file)
@@ -105,6 +105,7 @@ CONFIG_VARIABLE (bool, punch_out, "punch-out", false)
 CONFIG_VARIABLE (bool, plugins_stop_with_transport, "plugins-stop-with-transport", false)
 CONFIG_VARIABLE (bool, do_not_record_plugins, "do-not-record-plugins", false)
 CONFIG_VARIABLE (bool, stop_recording_on_xrun, "stop-recording-on-xrun", false)
+CONFIG_VARIABLE (bool, create_xrun_marker, "create-xrun-marker", true)
 CONFIG_VARIABLE (bool, stop_at_session_end, "stop-at-session-end", true)
 CONFIG_VARIABLE (bool, seamless_loop, "seamless-loop", false)
 CONFIG_VARIABLE (nframes_t, preroll, "preroll", 0)
index 0b82844f6111ec7317b366ffaa9da4b33f4d55ff..83b6378daee4a93f22b2fe3b6843672be14bb76a 100644 (file)
@@ -251,8 +251,8 @@ class IO : public Automatable, public Latent
        
        void set_parameter_automation_state (Parameter, AutoState);
 
-       virtual void transport_stopped (nframes_t now); // interface: matches Insert
-       void automation_snapshot (nframes_t now); // interface: matches Automatable
+       virtual void transport_stopped (nframes_t now);
+       virtual void automation_snapshot (nframes_t now, bool force);
 
        void start_pan_touch (uint32_t which);
        void end_pan_touch (uint32_t which);
index 409ad91b15f48778ef745256c33934b4db810efc..a535ce3bb495da596264b873c737b9128941d186 100644 (file)
@@ -65,7 +65,7 @@ class IOProcessor : public Processor
        boost::shared_ptr<IO>       io()       { return _io; }
        boost::shared_ptr<const IO> io() const { return _io; }
        
-       virtual void automation_snapshot (nframes_t now) { _io->automation_snapshot(now); }
+       virtual void automation_snapshot (nframes_t now, bool force) { _io->automation_snapshot(now, force); }
 
        virtual void run_in_place (BufferSet& in, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset) = 0;
 
index d8a38841f80933e3333a548f07ddc839743facc7..4640a8e32fbed7b3e54063b31db2a093b8389f47 100644 (file)
@@ -126,7 +126,6 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
        sigc::signal<void>      LengthChanged;
 
        static string bump_name (string old_name, Session&);
-       static string bump_name_once (string old_name);
 
        void freeze ();
        void thaw ();
index 2466f3799672c0a5c4d09440587f4b639200b533..c7c0b77102f441b5d9c72369a621ff632ac932cb 100644 (file)
@@ -75,6 +75,8 @@ class Route : public IO
        Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
        virtual ~Route();
 
+       static std::string ensure_track_or_route_name(std::string, Session &);
+
        std::string comment() { return _comment; }
        void set_comment (std::string str, void *src);
 
@@ -247,7 +249,7 @@ class Route : public IO
                return _mute_control;
        }
        
-       void automation_snapshot (nframes_t now);
+       void automation_snapshot (nframes_t now, bool force=false);
        void protect_automation ();
        
        void set_remote_control_id (uint32_t id);
index c0c178eb02c70ef9ed677af93b915dc12013afb5..10167ae5b324c900c8bab9ea8793403268d1a258 100644 (file)
@@ -353,7 +353,7 @@ class Session : public PBD::StatefulDestructible
        sigc::signal<void> TransportStateChange; /* generic */
        sigc::signal<void,nframes_t> PositionChanged; /* sent after any non-sequential motion */
        sigc::signal<void> DurationChanged;
-       sigc::signal<void> HaltOnXrun;
+       sigc::signal<void,nframes_t> Xrun;
        sigc::signal<void> TransportLooped;
 
        sigc::signal<void,RouteList&> RouteAdded;
@@ -563,8 +563,11 @@ class Session : public PBD::StatefulDestructible
        
        /* region info  */
 
-       sigc::signal<void,boost::shared_ptr<Region> > RegionAdded;
-       sigc::signal<void,boost::shared_ptr<Region> > RegionRemoved;
+       void add_regions (std::vector<boost::shared_ptr<Region> >&);
+       
+       sigc::signal<void,boost::weak_ptr<Region> > RegionAdded;
+       sigc::signal<void,std::vector<boost::weak_ptr<Region> >& > RegionsAdded;
+       sigc::signal<void,boost::weak_ptr<Region> > RegionRemoved;
 
        int region_name (string& result, string base = string(""), bool newlevel = false) const;
        string new_region_name (string);
@@ -586,10 +589,10 @@ class Session : public PBD::StatefulDestructible
            string doing_what;
            
            /* control info */
-           bool sample_convert;
            SrcQuality quality;
            volatile bool freeze;
            std::vector<Glib::ustring> paths;
+           bool replace_existing_source;
            
            /* result */
            SourceList sources;
@@ -1480,6 +1483,12 @@ class Session : public PBD::StatefulDestructible
 
        SourceMap sources;
 
+  public:
+       SourceMap get_sources() { return sources; }
+    
+  private:
+
+
        int load_sources (const XMLNode& node);
        XMLNode& get_sources_as_xml ();
 
index fdf8d0b4390e5b598febcf333c65a1f1e9b64858..efc2e35ecc7ff1ecbe08bea6c827b9a0f6edff37 100644 (file)
@@ -257,7 +257,8 @@ namespace ARDOUR {
 
        enum EditMode {
                Slide,
-               Splice
+               Splice,
+               Lock
        };
 
        enum RegionPoint { 
index e52274eb1f1968664c45b5e6dd6ff53886acc4f3..eecde2e85f0bc37c80bad475955bcbab6b1f9fc3 100644 (file)
@@ -45,6 +45,8 @@ static inline float f_max(float x, float a) {
        return (x);
 }
 
+std::string bump_name_once(std::string s);
+
 int cmp_nocase (const std::string& s, const std::string& s2);
 
 int touch_file(Glib::ustring path);
index bc2f0d9feba60c79aa43a6a34d873f278581d482..7d55cc343a8cc8f64b18e2b7cfd2c7bb9554289c 100644 (file)
@@ -519,7 +519,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
                if (lm.locked()) {
                        // automation snapshot can also be called from the non-rt context
                        // and it uses the redirect list, so we take the lock out here
-                       automation_snapshot (start_frame);
+                       automation_snapshot (start_frame, false);
                }
        }
 
index 387c7f1238cf75be2a35adb122a1192204e492cc..91329577430770125eb37ea6dd54adfdb74a4bf3 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>
@@ -83,6 +84,7 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAC
                throw failed_constructor();
        }
 
+       unit->GetElementCount (kAudioUnitScope_Global, global_elements);
        unit->GetElementCount (kAudioUnitScope_Input, input_elements);
        unit->GetElementCount (kAudioUnitScope_Output, output_elements);
 
@@ -106,6 +108,10 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAC
                error << _("AUPlugin: cannot set processing block size") << endmsg;
                throw failed_constructor();
        }
+
+       discover_parameters ();
+
+       Plugin::setup_controls ();
 }
 
 AUPlugin::~AUPlugin ()
@@ -119,6 +125,124 @@ AUPlugin::~AUPlugin ()
        }
 }
 
+void
+AUPlugin::discover_parameters ()
+{
+       /* discover writable parameters */
+       
+       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.lower = info.minValue;
+                       d.upper = info.maxValue;
+                       d.default_value = info.defaultValue;
+
+                       d.integer_step = (info.unit & kAudioUnitParameterUnit_Indexed);
+                       d.toggled = (info.unit & kAudioUnitParameterUnit_Boolean) ||
+                               (d.integer_step && ((d.upper - d.lower) == 1.0));
+                       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.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
 {
@@ -134,13 +258,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;
 }
 
@@ -157,28 +284,41 @@ AUPlugin::signal_latency () const
 void
 AUPlugin::set_parameter (uint32_t which, float val)
 {
-       // unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
+       if (which < descriptors.size()) {
+               const AUParameterDescriptor& d (descriptors[which]);
+               unit->SetParameter (d.id, d.scope, d.element, val);
+       }
 }
 
 float
 AUPlugin::get_parameter (uint32_t which) const
 {
-       float outValue = 0.0;
-       
-       // unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
-       
-       return outValue;
+       float val = 0.0;
+       if (which < descriptors.size()) {
+               const AUParameterDescriptor& d (descriptors[which]);
+               unit->GetParameter(d.id, d.scope, d.element, val);
+       }
+       return val;
 }
 
 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;
 }
 
@@ -397,20 +537,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
@@ -422,7 +568,7 @@ AUPlugin::parameter_is_audio (uint32_t) const
 bool
 AUPlugin::parameter_is_control (uint32_t) const
 {
-       return false;
+       return true;
 }
 
 bool
index da4f8a642ca1aebf8e9d229ff09d31a522398b03..8d2589db0e76f67329fd3f63425ccc013c984abb 100644 (file)
@@ -126,6 +126,8 @@ AudioEngine::start ()
                if (session) {
                        nframes_t blocksize = jack_get_buffer_size (_jack);
 
+                       BootMessage (_("Connect session to engine"));
+
                        session->set_block_size (blocksize);
                        session->set_frame_rate (jack_get_sample_rate (_jack));
 
index 81ad45e08a5fcb473f26ccb1bfeee40a8bf4a5da..00e0f925df54395eb02217d482207266719f58cb 100644 (file)
@@ -677,20 +677,18 @@ bool
 AudioFileSource::safe_file_extension(ustring file)
 {
        return !(file.rfind(".wav") == ustring::npos &&
-                file.rfind(".aiff")== ustring::npos &&
-                file.rfind(".aif") == ustring::npos &&
-                file.rfind(".snd") == ustring::npos &&
-                file.rfind(".au")  == ustring::npos &&
-                file.rfind(".raw") == ustring::npos &&
-                file.rfind(".sf")  == ustring::npos &&
-                file.rfind(".cdr") == ustring::npos &&
-                file.rfind(".smp") == ustring::npos &&
-                file.rfind(".maud")== ustring::npos &&
-                file.rfind(".vwe") == ustring::npos &&
-                file.rfind(".paf") == ustring::npos &&
-                /* protools convention */
-                file.rfind(".L") == ustring::npos &&
-                file.rfind(".R") == ustring::npos &&
+               file.rfind(".aiff")== ustring::npos &&
+               file.rfind(".aif") == ustring::npos &&
+               file.rfind(".amb") == ustring::npos &&
+               file.rfind(".snd") == ustring::npos &&
+               file.rfind(".au")  == ustring::npos &&
+               file.rfind(".raw") == ustring::npos &&
+               file.rfind(".sf")  == ustring::npos &&
+               file.rfind(".cdr") == ustring::npos &&
+               file.rfind(".smp") == ustring::npos &&
+               file.rfind(".maud")== ustring::npos &&
+               file.rfind(".vwe") == ustring::npos &&
+               file.rfind(".paf") == ustring::npos &&
 #ifdef HAVE_FLAC
                 file.rfind(".flac")== ustring::npos &&
 #endif // HAVE_FLAC
index 20115ff944049911338da9d5cc89e33b12b15137..7e2b709abd30e0d2d392bc3b74e8c84b10eec3c8 100644 (file)
@@ -1316,6 +1316,8 @@ AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
                return 0;
        }
 
+       cerr << "startup analysis of " << _name << endl;
+
        TransientDetector t (pl->session().frame_rate());
        bool existing_results = !results.empty();
 
@@ -1328,10 +1330,14 @@ AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
 
                t.reset ();
 
+               cerr << "working on channel " << i << endl;
+
                if (t.run ("", this, i, these_results)) {
                        return -1;
                }
 
+               cerr << "done\n";
+
                /* translate all transients to give absolute position */
                
                for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
@@ -1357,6 +1363,11 @@ AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
                /* make sure ours are clean too */
 
                TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
+
+       } else {
+
+               TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
+               results = _transients;
        }
 
        _valid_transients = true;
index cd71dd21e405b78fa585e4b1482af629a5ddcd0b..01dea08d3e2fc15f48e74c3e30bf872c538f95a8 100644 (file)
@@ -70,6 +70,7 @@ AudioSource::AudioSource (Session& s, ustring name)
 AudioSource::AudioSource (Session& s, const XMLNode& node) 
        : Source (s, node)
 {
+       
        _peaks_built = false;
        _peak_byte_max = 0;
        peakfile = -1;
@@ -213,7 +214,7 @@ AudioSource::initialize_peakfile (bool newfile, ustring audio_path)
                
                /* we found it in the peaks dir, so check it out */
                
-               if (statbuf.st_size == 0) {
+               if (statbuf.st_size == 0 || (statbuf.st_size < ((length() / _FPP) * sizeof (PeakData)))) {
                        // empty
                        _peaks_built = false;
                } else {
@@ -221,12 +222,22 @@ AudioSource::initialize_peakfile (bool newfile, ustring audio_path)
                        struct stat stat_file;
                        int err = stat (audio_path.c_str(), &stat_file);
                        
-                       if (!err && stat_file.st_mtime > statbuf.st_mtime){
+                       if (err) {
                                _peaks_built = false;
                                _peak_byte_max = 0;
                        } else {
-                               _peaks_built = true;
-                               _peak_byte_max = statbuf.st_size;
+
+                               /* allow 6 seconds slop on checking peak vs. file times because of various
+                                  disk action "races"
+                               */
+
+                               if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
+                                       _peaks_built = false;
+                                       _peak_byte_max = 0;
+                               } else {
+                                       _peaks_built = true;
+                                       _peak_byte_max = statbuf.st_size;
+                               }
                        }
                }
        }
index 45b19d1997aea345f44bbba2bdbc9975f06e478b..8b8b843384480d1936269fbd02f4852f4ce84a6f 100644 (file)
@@ -422,9 +422,9 @@ Automatable::protect_automation ()
 }
 
 void
-Automatable::automation_snapshot (nframes_t now)
+Automatable::automation_snapshot (nframes_t now, bool force)
 {
-       if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
+       if (force || _last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
 
                for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) {
                        if (i->second->list()->automation_write()) {
index dc8185db9572632bce376504c895405bd9c55d86..be382f72da32948af50b98a282979da66a99997c 100644 (file)
@@ -28,6 +28,7 @@
 #include <ardour/filter.h>
 #include <ardour/region_factory.h>
 #include <ardour/source_factory.h>
+#include <ardour/analyser.h>
 
 #include "i18n.h"
 
@@ -101,6 +102,10 @@ Filter::finish (boost::shared_ptr<Region> region, SourceList& nsrcs, string regi
                        smfs->set_timeline_position (region->position());
                        smfs->flush_footer ();
                }
+               
+               /* now that there is data there, requeue the file for analysis */
+               
+               Analyser::queue_source_for_analysis (*si, false);
        }
 
        /* create a new region */
index 6aba688cae9e2da38c61064b0c45d521d8bfd824..02c4a5ced604c8897e468596c08f27c588b7b408 100644 (file)
 #include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <locale.h>
+#include <errno.h>
 
 #ifdef VST_SUPPORT
 #include <fst.h>
 #include <xmmintrin.h>
 #endif
 
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
+
 #include <lrdf.h>
 
 #include <pbd/error.h>
 #include <pbd/id.h>
 #include <pbd/strsplit.h>
 #include <pbd/fpu.h>
+#include <pbd/file_utils.h>
 
 #include <midi++/port.h>
 #include <midi++/manager.h>
@@ -54,6 +61,7 @@
 #include <ardour/source_factory.h>
 #include <ardour/control_protocol_manager.h>
 #include <ardour/audioengine.h>
+#include <ardour/filesystem_paths.h>
 
 #ifdef HAVE_LIBLO
 #include <ardour/osc.h>
@@ -96,6 +104,8 @@ apply_gain_to_buffer_t  ARDOUR::apply_gain_to_buffer = 0;
 mix_buffers_with_gain_t ARDOUR::mix_buffers_with_gain = 0;
 mix_buffers_no_gain_t   ARDOUR::mix_buffers_no_gain = 0;
 
+sigc::signal<void,std::string> ARDOUR::BootMessage;
+
 #ifdef HAVE_LIBLO
 static int
 setup_osc ()
@@ -107,6 +117,7 @@ setup_osc ()
        osc = new OSC (Config->get_osc_port());
        
        if (Config->get_use_osc ()) {
+               BootMessage (_("Starting OSC"));
                return osc->start ();
        } else {
                return 0;
@@ -122,6 +133,8 @@ setup_midi ()
                return 0;
        }
 
+       BootMessage (_("Configuring MIDI ports"));
+
        for (std::map<string,XMLNode>::iterator i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
                MIDI::Manager::instance()->add_port (i->second);
        }
@@ -253,6 +266,33 @@ setup_hardware_optimization (bool try_optimization)
        }
 }
 
+static void
+lotsa_files_please ()
+{
+       struct rlimit rl;
+
+       if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
+
+               rl.rlim_cur = rl.rlim_max;
+
+               if (setrlimit (RLIMIT_NOFILE, &rl) != 0) {
+                       if (rl.rlim_cur == RLIM_INFINITY) {
+                               error << _("Could not set system open files limit to \"unlimited\"") << endmsg;
+                       } else {
+                               error << string_compose (_("Could not set system open files limit to %1"), rl.rlim_cur) << endmsg;
+                       }
+               } else {
+                       if (rl.rlim_cur == RLIM_INFINITY) {
+                               info << _("Removed open file count limit. Excellent!") << endmsg;
+                       } else {
+                               info << string_compose (_("Ardour will be limited to %1 open files"), rl.rlim_cur) << endmsg;
+                       }
+               }
+       } else {
+               error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
+       }
+}
+
 int
 ARDOUR::init (bool use_vst, bool try_optimization)
 {
@@ -262,9 +302,14 @@ ARDOUR::init (bool use_vst, bool try_optimization)
 
        setup_enum_writer ();
 
+       // allow ardour the absolute maximum number of open files
+       lotsa_files_please ();
+
        lrdf_init();
        Library = new AudioLibrary;
 
+       BootMessage (_("Loading configuration"));
+
        Config = new Configuration;
 
        if (Config->load_state ()) {
@@ -367,6 +412,34 @@ ARDOUR::get_ardour_revision ()
        return "$Rev$";
 }
 
+void
+ARDOUR::find_bindings_files (map<string,string>& files)
+{
+       vector<sys::path> found;
+
+       SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
+
+       if (getenv ("ARDOUR_SAE")) {
+               Glib::PatternSpec pattern("*SAE-*.bindings");
+               find_matching_files_in_search_path (spath, pattern, found);
+       } else {
+               Glib::PatternSpec pattern("*.bindings");
+               find_matching_files_in_search_path (spath, pattern, found);
+       }
+
+       if (found.empty()) {
+               return;
+       }
+       
+       for (vector<sys::path>::iterator x = found.begin(); x != found.end(); ++x) {
+               sys::path path = *x;
+               pair<string,string> namepath;
+               namepath.second = path.to_string();
+               namepath.first = path.leaf().substr (0, path.leaf().find_first_of ('.'));
+               files.insert (namepath);
+       }
+}
+
 ARDOUR::LocaleGuard::LocaleGuard (const char* str)
 {
        old = strdup (setlocale (LC_NUMERIC, NULL));
index 91e5b9850c0bf176069136574e2e1a0e4925e78c..2bc3a00a7a1ab849244268a10fc3b6ed440cd22d 100644 (file)
@@ -46,6 +46,7 @@
 #include <ardour/region_factory.h>
 #include <ardour/source_factory.h>
 #include <ardour/resampled_source.h>
+#include <ardour/analyser.h>
 
 #include "i18n.h"
 
@@ -65,7 +66,7 @@ open_importable_source (const string& path, nframes_t samplerate, ARDOUR::SrcQua
 }
 
 static std::string
-get_non_existent_filename (const std::string& basename, uint channel, uint channels)
+get_non_existent_filename (const bool allow_replacing, const std::string destdir, const std::string& basename, uint channel, uint channels)
 {
        char buf[PATH_MAX+1];
        bool goodfile = false;
@@ -84,7 +85,9 @@ get_non_existent_filename (const std::string& basename, uint channel, uint chann
                        snprintf (buf, sizeof(buf), "%s.wav", base.c_str());
                }
                
-               if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
+
+               string tempname = destdir + "/" + buf;
+               if (!allow_replacing && Glib::file_test (tempname, Glib::FILE_TEST_EXISTS)) {
 
                        /* if the file already exists, we must come up with
                         *  a new name for it.  for now we just keep appending
@@ -104,7 +107,7 @@ get_non_existent_filename (const std::string& basename, uint channel, uint chann
 }
 
 static vector<string>
-get_paths_for_new_sources (const string& import_file_path, const string& session_dir, uint channels)
+get_paths_for_new_sources (const bool allow_replacing, const string& import_file_path, const string& session_dir, uint channels)
 {
        vector<string> new_paths;
        const string basename = basename_nosuffix (import_file_path);
@@ -115,7 +118,7 @@ get_paths_for_new_sources (const string& import_file_path, const string& session
 
                filepath = session_dir;
                filepath += '/';
-               filepath += get_non_existent_filename (basename, n, channels); 
+               filepath += get_non_existent_filename (allow_replacing, session_dir, basename, n, channels); 
 
                new_paths.push_back (filepath);
        }
@@ -123,6 +126,25 @@ get_paths_for_new_sources (const string& import_file_path, const string& session
        return new_paths;
 }
 
+static bool
+map_existing_mono_sources (const vector<string>& new_paths, Session& sess,
+                          uint samplerate, vector<boost::shared_ptr<AudioFileSource> >& newfiles, Session *session)
+{
+       for (vector<string>::const_iterator i = new_paths.begin();
+                       i != new_paths.end(); ++i)
+       {
+               boost::shared_ptr<Source> source = session->source_by_path_and_channel(*i, 0);
+
+               if (source == 0) {
+                       error << string_compose(_("Could not find a source for %1 even though we are updating this file!"), (*i)) << endl;
+                       return false;
+               }
+
+               newfiles.push_back(boost::dynamic_pointer_cast<AudioFileSource>(source));
+       }
+       return true;
+}
+
 static bool
 create_mono_sources_for_writing (const vector<string>& new_paths, Session& sess,
                uint samplerate, vector<boost::shared_ptr<AudioFileSource> >& newfiles)
@@ -228,6 +250,10 @@ remove_file_source (boost::shared_ptr<AudioFileSource> file_source)
        ::unlink (file_source->path().c_str());
 }
 
+// This function is still unable to cleanly update an existing source, even though
+// it is possible to set the import_status flag accordingly. The functinality
+// is disabled at the GUI until the Source implementations are able to provide
+// the necessary API.
 void
 Session::import_audiofiles (import_status& status)
 {
@@ -254,13 +280,19 @@ Session::import_audiofiles (import_status& status)
                        return;
                }
 
-               vector<string> new_paths = get_paths_for_new_sources (*p,
+               vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source,
+                                                                     *p,
                                get_best_session_directory_for_new_source (),
                                source->channels());
                
                AudioSources newfiles;
 
-               status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles);
+               if (status.replace_existing_source) {
+                       fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endl;
+                       status.cancel = !map_existing_mono_sources (new_paths, *this, frame_rate(), newfiles, this);
+               } else {
+                       status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles);
+               }
 
                // copy on cancel/failure so that any files that were created will be removed below
                std::copy (newfiles.begin(), newfiles.end(), std::back_inserter(all_new_sources));
@@ -286,11 +318,14 @@ Session::import_audiofiles (import_status& status)
 
                /* flush the final length(s) to the header(s) */
 
-               for (AudioSources::iterator x = all_new_sources.begin();
-                               x != all_new_sources.end(); ++x)
+               for (AudioSources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ++x)
                {
                        (*x)->update_header(0, *now, xnow);
                        (*x)->done_with_peakfile_writes ();
+                       
+                       /* now that there is data there, requeue the file for analysis */
+                       
+                       Analyser::queue_source_for_analysis (boost::static_pointer_cast<Source>(*x), false);
                }
 
                /* save state so that we don't lose these new Sources */
index babf1e451fac07ca888b42acc07bd01e1bc48b59..f57d5b39de1343b19c78edbe928308ea7d37ee16 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <ardour/audioengine.h>
 #include <ardour/io.h>
+#include <ardour/route.h>
 #include <ardour/port.h>
 #include <ardour/audio_port.h>
 #include <ardour/midi_port.h>
@@ -1800,14 +1801,22 @@ IO::parse_gain_string (const string& str, vector<string>& ports)
 }
 
 bool
-IO::set_name (const string& str)
+IO::set_name (const string& requested_name)
 {
-       if (str == _name) {
+       if (requested_name == _name) {
                return true;
        }
        
+       string name;
+       Route *rt;
+       if ( (rt = dynamic_cast<Route *>(this))) {
+               name = Route::ensure_track_or_route_name(requested_name, _session);
+       } else {
+               name = requested_name;
+       }
+
+
        /* replace all colons in the name. i wish we didn't have to do this */
-       string name = str;
 
        if (replace_all (name, ":", "-")) {
                warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
@@ -2224,13 +2233,16 @@ IO::end_pan_touch (uint32_t which)
 }
 
 void
-IO::automation_snapshot (nframes_t now)
+IO::automation_snapshot (nframes_t now, bool force)
 {
-       Automatable::automation_snapshot (now);
+       Automatable::automation_snapshot (now, force);
 
        if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
                _panner->snapshot (now);
        }
+       
+       _panner->snapshot (now);
+       _last_automation_snapshot = now;
 }
 
 void
index da3a812123b0744cb1b1526b5eac7a4e5ef2965b..65279499ec957355f11ff3ed17fde765f3e30033 100644 (file)
@@ -1814,50 +1814,12 @@ Playlist::bump_name (string name, Session &session)
        string newname = name;
 
        do {
-               newname = Playlist::bump_name_once (newname);
+               newname = bump_name_once (newname);
        } while (session.playlist_by_name (newname)!=NULL);
 
        return newname;
 }
 
-string
-Playlist::bump_name_once (string name)
-{
-       string::size_type period;
-       string newname;
-
-       if ((period = name.find_last_of ('.')) == string::npos) {
-               newname  = name;
-               newname += ".1";
-       } else {
-               int isnumber = 1;
-               const char *last_element = name.c_str() + period + 1;
-               for (size_t i = 0; i < strlen(last_element); i++) {
-                       if (!isdigit(last_element[i])) {
-                               isnumber = 0;
-                               break;
-                       }
-               }
-
-               errno = 0;
-               long int version = strtol (name.c_str()+period+1, (char **)NULL, 10);
-
-               if (isnumber == 0 || errno != 0) {
-                       // last_element is not a number, or is too large
-                       newname  = name;
-                       newname += ".1";
-               } else {
-                       char buf[32];
-
-                       snprintf (buf, sizeof(buf), "%ld", version+1);
-               
-                       newname  = name.substr (0, period+1);
-                       newname += buf;
-               }
-       }
-
-       return newname;
-}
 
 layer_t
 Playlist::top_layer() const
index 95629f256150efd36801eeb4a0f690177dbe673a..3d218448dddad09c36ed3858b757b77e5ebc78ae 100644 (file)
@@ -224,6 +224,19 @@ ARDOUR::find_plugin(Session& session, string identifier, PluginType type)
                        return (*i)->load (session);
                }
        }
+
+#ifdef VST_SUPPORT
+       /* hmm, we didn't find it. could be because in older versions of Ardour.
+          we used to store the name of a VST plugin, not its unique ID. so try
+          again.
+       */
+
+       for (i = plugs.begin(); i != plugs.end(); ++i) {
+               if (identifier == (*i)->name){
+                       return (*i)->load (session);
+               }
+       }
+#endif
        
        return PluginPtr ((Plugin*) 0);
 }
index 2193a69908e6f185361af6a1c38540c6cdce619e..508f09a48011af42a3769c71279c04096f6d0d3d 100644 (file)
@@ -957,14 +957,14 @@ Region::adjust_to_sync (nframes_t pos)
        // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
        
        if (sync_dir > 0) {
-               if (max_frames - pos > offset) {
+               if (pos > offset) {
                        pos -= offset;
+               } else {
+                       pos = 0;
                }
        } else {
-               if (pos > offset) {
+               if (max_frames - pos > offset) {
                        pos += offset;
-               } else {
-                       pos = 0;
                }
        }
 
index fd0d99e87a942ffa080c29aae62417a44e5b9233..560946d9dabce94248e330a1b1f55da01bc3f0b8 100644 (file)
@@ -46,6 +46,9 @@
 #include <ardour/amp.h>
 #include <ardour/meter.h>
 #include <ardour/buffer_set.h>
+#include <ardour/mix.h>
+#include <ardour/profile.h>
+
 #include "i18n.h"
 
 using namespace std;
@@ -190,6 +193,20 @@ Route::sync_order_keys ()
        }
 }
 
+string
+Route::ensure_track_or_route_name(string name, Session &session)
+{
+       string newname = name;
+
+       while (session.route_by_name (newname)!=NULL)
+       {
+               newname = bump_name_once (newname);
+       }
+
+       return newname;
+}
+
+
 void
 Route::inc_gain (gain_t fraction, void *src)
 {
@@ -843,8 +860,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
                reset_panner ();
        }
 
-
        processors_changed (); /* EMIT SIGNAL */
+       
        return 0;
 }
 
@@ -2291,7 +2308,7 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
                Glib::RWLock::ReaderLock lm (_processor_lock);
 
                if (!did_locate) {
-                       automation_snapshot (now);
+                       automation_snapshot (now, true);
                }
 
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -2398,7 +2415,7 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nfra
                if (lm.locked()) {
                        // automation snapshot can also be called from the non-rt context
                        // and it uses the processor list, so we take the lock out here
-                       automation_snapshot (_session.transport_frame());
+                       automation_snapshot (_session.transport_frame(), false);
                }
        }
 
@@ -2569,12 +2586,15 @@ Route::set_latency_delay (nframes_t longest_session_latency)
 }
 
 void
-Route::automation_snapshot (nframes_t now)
+Route::automation_snapshot (nframes_t now, bool force)
 {
-       IO::automation_snapshot (now);
+       if (!force && !should_snapshot(now)) {
+               return;
+       }
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->automation_snapshot (now);
+               // IO::automation_snapshot (now, force);  ?
+               (*i)->automation_snapshot (now, force);
        }
 }
 
index 5a3144b828a29c52bfa1fc289c5dd813fa53f4a1..4cfcda992e4884abb34bd20a1d9dfbb1f7fe4a18 100644 (file)
@@ -504,9 +504,13 @@ Session::when_engine_running ()
 
        /* we don't want to run execute this again */
 
+       BootMessage (_("Set block size and sample rate"));
+
        set_block_size (_engine.frames_per_cycle());
        set_frame_rate (_engine.frame_rate());
 
+       BootMessage (_("Using configuration"));
+
        Config->map_parameters (mem_fun (*this, &Session::config_changed));
 
        /* every time we reconnect, recompute worst case output latencies */
@@ -562,6 +566,8 @@ Session::when_engine_running ()
                error << _("cannot setup Click I/O") << endmsg;
        }
 
+       BootMessage (_("Compute I/O Latencies"));
+
        set_worst_io_latencies ();
 
        if (_clicking) {
@@ -572,6 +578,8 @@ Session::when_engine_running ()
           to the physical outputs currently available
        */
 
+       BootMessage (_("Set up standard connections"));
+
        /* ONE: MONO */
 
        for (uint32_t np = 0; np < n_physical_outputs; ++np) {
@@ -672,11 +680,15 @@ Session::when_engine_running ()
                }
                add_bundle (c);
        } 
+       
+       BootMessage (_("Connect ports"));
 
        hookup_io ();
 
        /* catch up on send+insert cnts */
 
+       BootMessage (_("Catch up with send/insert state"));
+
        insert_cnt = 0;
        
        for (list<PortInsert*>::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) {
@@ -704,14 +716,17 @@ Session::when_engine_running ()
        
        _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
 
-
        /* hook us up to the engine */
 
+       BootMessage (_("Connect to engine"));
+
        _engine.set_session (this);
 
 #ifdef HAVE_LIBLO
        /* and to OSC */
 
+       BootMessage (_("OSC startup"));
+
        osc->set_session (*this);
 #endif
     
@@ -2545,42 +2560,55 @@ Session::region_name (string& result, string base, bool newlevel) const
 
 void
 Session::add_region (boost::shared_ptr<Region> region)
+{
+       vector<boost::shared_ptr<Region> > v;
+       v.push_back (region);
+       add_regions (v);
+}
+               
+void
+Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
 {
        bool added = false;
 
        { 
                Glib::Mutex::Lock lm (region_lock);
 
-               if (region == 0) {
-                       error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
-               } else {
-
-                       RegionList::iterator x;
-
-                       for (x = regions.begin(); x != regions.end(); ++x) {
-
-                               if (region->region_list_equivalent (x->second)) {
-                                       break;
-                               }
-                       }
-
-                       if (x == regions.end()) {
-
-                               pair<RegionList::key_type,RegionList::mapped_type> entry;
-
-                               entry.first = region->id();
-                               entry.second = region;
+               for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+               
+                       boost::shared_ptr<Region> region = *ii;
+                       
+                       if (region == 0) {
 
-                               pair<RegionList::iterator,bool> x = regions.insert (entry);
+                               error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
 
+                       } else {
                                
-                               if (!x.second) {
-                                       return;
+                               RegionList::iterator x;
+                               
+                               for (x = regions.begin(); x != regions.end(); ++x) {
+                                       
+                                       if (region->region_list_equivalent (x->second)) {
+                                               break;
+                                       }
                                }
-
-                               added = true;
-                       } 
-
+                               
+                               if (x == regions.end()) {
+                                       
+                                       pair<RegionList::key_type,RegionList::mapped_type> entry;
+                                       
+                                       entry.first = region->id();
+                                       entry.second = region;
+                                       
+                                       pair<RegionList::iterator,bool> x = regions.insert (entry);
+                                       
+                                       if (!x.second) {
+                                               return;
+                                       }
+                                       
+                                       added = true;
+                               } 
+                       }
                }
        }
 
@@ -2591,9 +2619,33 @@ Session::add_region (boost::shared_ptr<Region> region)
        set_dirty();
        
        if (added) {
-               region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
-               region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
-               RegionAdded (region); /* EMIT SIGNAL */
+
+               vector<boost::weak_ptr<Region> > v;
+               boost::shared_ptr<Region> first_r;
+
+               for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+
+                       boost::shared_ptr<Region> region = *ii;
+
+                       if (region == 0) {
+
+                               error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
+
+                       } else {
+                               v.push_back (region);
+
+                               if (!first_r) {
+                                       first_r = region;
+                               }
+                       }
+
+                       region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
+                       region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
+               }
+               
+               if (!v.empty()) {
+                       RegionsAdded (v); /* EMIT SIGNAL */
+               }
        }
 }
 
@@ -2680,18 +2732,12 @@ Session::destroy_region (boost::shared_ptr<Region> region)
        vector<boost::shared_ptr<Source> > srcs;
                
        {
-               boost::shared_ptr<AudioRegion> aregion;
-               
-               if ((aregion = boost::dynamic_pointer_cast<AudioRegion> (region)) == 0) {
-                       return 0;
-               }
-               
-               if (aregion->playlist()) {
-                       aregion->playlist()->destroy_region (region);
+               if (region->playlist()) {
+                       region->playlist()->destroy_region (region);
                }
                
-               for (uint32_t n = 0; n < aregion->n_channels(); ++n) {
-                       srcs.push_back (aregion->source (n));
+               for (uint32_t n = 0; n < region->n_channels(); ++n) {
+                       srcs.push_back (region->source (n));
                }
        }
 
@@ -2699,17 +2745,10 @@ Session::destroy_region (boost::shared_ptr<Region> region)
 
        for (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
 
-               if (!(*i)->used()) {
-                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*i);
-                       
-                       if (afs) {
-                               (afs)->mark_for_remove ();
-                       }
-                       
+                       (*i)->mark_for_remove ();
                        (*i)->drop_references ();
                        
                        cerr << "source was not used by any playlist\n";
-               }
        }
 
        return 0;
index af4be07dc466ad14cfe506c326eea3f0aee68ecc..c4448640fd438f827d4eb2499b6934976036c855 100644 (file)
@@ -350,11 +350,15 @@ Session::second_stage_init (bool new_session)
                return -1;
        }
 
+       BootMessage (_("Reset Remote Controls"));
+
        //send_full_time_code ();
        _engine.transport_locate (0);
        deliver_mmc (MIDI::MachineControl::cmdMmcReset, 0);
        deliver_mmc (MIDI::MachineControl::cmdLocate, 0);
 
+       BootMessage (_("Reset Control Protocols"));
+
        ControlProtocolManager::instance().set_session (*this);
 
        if (new_session) {
@@ -364,7 +368,6 @@ Session::second_stage_init (bool new_session)
        }
 
        _state_of_the_state = Clean;
-
        
        DirtyChanged (); /* EMIT SIGNAL */
 
@@ -374,6 +377,8 @@ Session::second_stage_init (bool new_session)
                state_was_pending = false;
        }
        
+       BootMessage (_("Session loading complete"));
+
        return 0;
 }
 
@@ -1373,6 +1378,8 @@ Session::load_routes (const XMLNode& node)
                        return -1;
                }
 
+               BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
+
                new_routes.push_back (route);
        }
 
index d422698f302c2e626c4b4961e13d31edea8bbdf4..e6318f5503b53a84cde573634ce92f245f401fd3 100644 (file)
@@ -1267,9 +1267,9 @@ Session::engine_halted ()
 void
 Session::xrun_recovery ()
 {
-       if (Config->get_stop_recording_on_xrun() && actively_recording()) {
+       Xrun (transport_frame()); //EMIT SIGNAL
 
-                HaltOnXrun (); /* EMIT SIGNAL */
+       if (Config->get_stop_recording_on_xrun() && actively_recording()) {
 
                /* it didn't actually halt, but we need
                   to handle things in the same way.
index 7941eb693b23aedf0f825b9bc0cea18a8faa3fec..f08d08b86e4e529fe316923ee3052265ef542ecc 100644 (file)
@@ -195,6 +195,7 @@ Source::set_been_analysed (bool yn)
        }
        
        if (yn) {
+               load_transients (get_transients_path());
                AnalysisChanged(); // EMIT SIGNAL
        }
 }
@@ -265,3 +266,4 @@ Source::check_for_analysis_data_on_disk ()
        set_been_analysed (ok);
        return ok;
 }
+
index b92bf5fb2de61a2034154c901f79881efca0b4db..d24c4c9442f678cf1016be4ac8e2558cccc63e20 100644 (file)
@@ -6,18 +6,20 @@ using namespace Vamp;
 using namespace ARDOUR;
 using namespace std;
 
-string TransientDetector::_op_id;
+/* need a static initializer function for this */
+
+string TransientDetector::_op_id = X_("libardourvampplugins:percussiononsets:2");
 
 TransientDetector::TransientDetector (float sr)
        : AudioAnalyser (sr, X_("libardourvampplugins:percussiononsets"))
 {
-       if (_op_id.empty()) {
-               _op_id = X_("libardourvampplugins:percussiononsets");
-
-               // XXX this should load the above-named plugin and get the current version
+       /* update the op_id */
 
-               _op_id += ":2";
-       }
+       _op_id = X_("libardourvampplugins:percussiononsets");
+       
+       // XXX this should load the above-named plugin and get the current version
+       
+       _op_id += ":2";
 }
 
 TransientDetector::~TransientDetector()
index cfd38c5099d7f451ef4e05f17b9b9c741d03ce24..99a6dbbc88a55a2c6420139a3ee54d174bd9a90c 100644 (file)
@@ -86,6 +86,45 @@ legalize_for_path (string str)
 }
 #endif
 
+string bump_name_once(std::string name)
+{
+       string::size_type period;
+       string newname;
+
+       if ((period = name.find_last_of ('.')) == string::npos) {
+               newname  = name;
+               newname += ".1";
+       } else {
+               int isnumber = 1;
+               const char *last_element = name.c_str() + period + 1;
+               for (size_t i = 0; i < strlen(last_element); i++) {
+                       if (!isdigit(last_element[i])) {
+                               isnumber = 0;
+                               break;
+                       }
+               }
+
+               errno = 0;
+               long int version = strtol (name.c_str()+period+1, (char **)NULL, 10);
+
+               if (isnumber == 0 || errno != 0) {
+                       // last_element is not a number, or is too large
+                       newname  = name;
+                       newname += ".1";
+               } else {
+                       char buf[32];
+
+                       snprintf (buf, sizeof(buf), "%ld", version+1);
+               
+                       newname  = name.substr (0, period+1);
+                       newname += buf;
+               }
+       }
+
+       return newname;
+
+}
+
 ostream&
 operator<< (ostream& o, const BBT_Time& bbt)
 {
@@ -289,6 +328,8 @@ string_to_edit_mode (string str)
                return Splice;
        } else if (str == _("Slide Edit")) {
                return Slide;
+       } else if (str == _("Lock Edit")) {
+               return Lock;
        }
        fatal << string_compose (_("programming error: unknown edit mode string \"%1\""), str) << endmsg;
        /*NOTREACHED*/
@@ -302,6 +343,9 @@ edit_mode_to_string (EditMode mode)
        case Slide:
                return _("Slide Edit");
 
+       case Lock:
+               return _("Lock Edit");
+
        default:
        case Splice:
                return _("Splice Edit");
index 1caa21376cff7e5a5baf561e34f29ac72e20656a..b08b8b21451e2812b67aec07c462207a482d087e 100644 (file)
@@ -10,6 +10,9 @@ Import('env libraries install_prefix')
 pangomm = env.Copy()
 pangomm.Merge([libraries['glibmm2'], libraries['pango'], libraries['sigc2'], libraries['cairomm'], libraries['cairo']])
 
+if pangomm['IS_OSX']:
+       pangomm.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
+
 libpangomm = pangomm.SharedLibrary('pangomm', pangomm_files)
 Default(libpangomm)
 
index 829182c71e327d2adef2e83c1cb90cb3baa9e5a6..fad538a40e626d67b213a82d0b16997af2f3da63 100644 (file)
@@ -32,6 +32,8 @@ gtkmm2ext.Append(CXXFLAGS=["-DLIBSIGC_DISABLE_DEPRECATED", "-DGLIBMM_DEFAULT_SIG
 gtkmm2ext.Append(PACKAGE=domain)
 gtkmm2ext.Append(POTFILE=domain + '.pot')
 
+extra_sources = []
+
 gtkmm2ext_files = Split("""
 auto_spin.cc
 barcontroller.cc
@@ -61,12 +63,21 @@ version.cc
 window_title.cc
 """)
 
+gtkosx_files=Split("""
+sync-menu.c
+""")
+
+if gtkmm2ext['GTKOSX']:
+    extra_sources += gtkosx_files
+    gtkmm2ext.Append (CCFLAGS="-DTOP_MENUBAR -DGTKOSX")
+    gtkmm2ext.Append (LINKFLAGS="-framework Carbon")
+
 gtkmm2ext.VersionBuild(['version.cc','gtkmm2ext/version.h'], [])
 
 gtkmm2ext.Append(CCFLAGS="-D_REENTRANT")
 gtkmm2ext.Append(CCFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
 
-libgtkmm2ext = gtkmm2ext.SharedLibrary('gtkmm2ext', gtkmm2ext_files)
+libgtkmm2ext = gtkmm2ext.SharedLibrary('gtkmm2ext', gtkmm2ext_files + extra_sources)
 
 Default(libgtkmm2ext)
 
@@ -78,5 +89,6 @@ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ar
 env.Alias('tarball', env.Distribute (env['DISTTREE'],
                                      [ 'SConscript', 'i18n.h', 'gettext.h'] +
                                      gtkmm2ext_files +
+                                    gtkosx_files + 
                                      glob.glob('po/*.po') +
                                      glob.glob('gtkmm2ext/*.h')))
index 660ea32ad1aa2a4b0142a702350b92eb851cf7d3..f00c6cd1e1673042c2b9be17f041b43a6f41ff37 100644 (file)
@@ -560,10 +560,31 @@ UI::popup_error (const char *text)
        pup->touch ();
 }
 
+#ifdef GTKOSX
+extern "C" {
+       int gdk_quartz_in_carbon_menu_event_handler ();
+}
+#endif
 
 void
 UI::flush_pending ()
 {
+#ifdef GTKOSX
+       /* as of february 11th 2008, gtk/osx has a problem in that mac menu events
+          are handled using Carbon with an "internal" event handling system that 
+          doesn't pass things back to the glib/gtk main loop. this makes
+          gtk_main_iteration() block if we call it while in a menu event handler 
+          because glib gets confused and thinks there are two threads running
+          g_main_poll_func(). 
+
+          this hack (relies on code in gtk2_ardour/sync-menu.c) works
+          around that.
+       */
+
+       if (gdk_quartz_in_carbon_menu_event_handler()) {
+               return;
+       }
+#endif
        if (!caller_is_ui_thread()) {
                error << "non-UI threads cannot call UI::flush_pending()"
                      << endmsg;
index d974f5d5bc64b153d7028ca5d51596c9039d0c75..519e1c9e1e6acf657d1f77a33c4b300d9657c26c 100644 (file)
@@ -30,7 +30,7 @@ namespace Gtkmm2ext {
 
 class PixFader : public Gtk::DrawingArea {
   public:
-       PixFader (Glib::RefPtr<Gdk::Pixbuf> belt_image, Gtk::Adjustment& adjustment);
+       PixFader (Glib::RefPtr<Gdk::Pixbuf> belt_image, Gtk::Adjustment& adjustment, int orientation);
        virtual ~PixFader ();
        
   protected:
@@ -44,23 +44,32 @@ class PixFader : public Gtk::DrawingArea {
        bool on_motion_notify_event (GdkEventMotion*);
        bool on_scroll_event (GdkEventScroll* ev);
 
-  private:  
+       enum Orientation {
+               VERT=1,
+               HORIZ=2,
+       };
+
+  private:
        Glib::RefPtr<Gdk::Pixbuf> pixbuf;
-       gint pixheight;
+       int span, girth;
+       int _orien;
 
        GdkRectangle view;
 
        GdkWindow* grab_window;
-       double grab_y;
+       double grab_loc;
        double grab_start;
        int last_drawn;
        bool dragging;
        float default_value;
-       int unity_y;
+       int unity_loc;
 
        void adjustment_changed ();
 
-       int display_height ();
+       int display_span ();
+
+       static int fine_scale_modifier;
+       static int extra_fine_scale_modifier;
 };
 
 
index 74ff36816b5b6bf1ffacfbd4411ebff9dcb7264d..60c8eef660aaf332edac9c930fb8404ccbc4e436 100644 (file)
@@ -38,7 +38,7 @@ class SliderController : public Gtkmm2ext::PixFader
 {
   public:
        SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
-                         Gtk::Adjustment* adj,
+                         Gtk::Adjustment* adj, int orientation,
                          PBD::Controllable&,
                          bool with_numeric = true);
 
diff --git a/libs/gtkmm2ext/gtkmm2ext/sync-menu.h b/libs/gtkmm2ext/gtkmm2ext/sync-menu.h
new file mode 100644 (file)
index 0000000..2be5e71
--- /dev/null
@@ -0,0 +1,44 @@
+/* GTK+ Integration for the Mac OS X Menubar.
+ *
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2007 Imendio AB
+ *
+ * For further information, see:
+ * http://developer.imendio.com/projects/gtk-macosx/menubar
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __IGE_MAC_MENU_H__
+#define __IGE_MAC_MENU_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _IgeMacMenuGroup IgeMacMenuGroup;
+
+void              ige_mac_menu_set_menu_bar       (GtkMenuShell    *menu_shell);
+void              ige_mac_menu_set_quit_menu_item (GtkMenuItem     *menu_item);
+
+IgeMacMenuGroup * ige_mac_menu_add_app_menu_group (void);
+void              ige_mac_menu_add_app_menu_item  (IgeMacMenuGroup *group,
+                                                  GtkMenuItem     *menu_item,
+                                                  const gchar     *label);
+
+G_END_DECLS
+
+#endif /* __IGE_MAC_MENU_H__ */
index f3a40ffc69eaaa0f6ee82da8296b11017b51bcee..fe464d0fac62e00ee7d4ffa76a089fabac74952b 100644 (file)
@@ -27,21 +27,36 @@ using namespace Gtk;
 using namespace Gdk;
 using namespace std;
 
-PixFader::PixFader (Glib::RefPtr<Pixbuf> belt, Gtk::Adjustment& adj)
+#ifdef GTKOSX
+int PixFader::fine_scale_modifier = GDK_META_MASK;
+#else
+int PixFader::fine_scale_modifier = GDK_CONTROL_MASK;
+#endif
+
+int PixFader::extra_fine_scale_modifier = GDK_MOD1_MASK;
+
+PixFader::PixFader (Glib::RefPtr<Pixbuf> belt, Gtk::Adjustment& adj, int orientation)
+
        : adjustment (adj),
-         pixbuf (belt)
+         pixbuf (belt),
+         _orien(orientation)
 {
        dragging = false;
        default_value = adjustment.get_value();
        last_drawn = -1;
-       pixheight = pixbuf->get_height();
 
        view.x = 0;
        view.y = 0;
-       view.width = pixbuf->get_width();
-       view.height = pixheight / 2;
 
-       unity_y = (int) rint (view.height - (default_value * view.height)) - 1;
+       if (orientation == VERT) {
+               view.width = girth = pixbuf->get_width();
+               view.height = span = pixbuf->get_height() / 2;
+               unity_loc = (int) rint (view.height - (default_value * view.height)) - 1;
+       } else {
+               view.width = span = pixbuf->get_width () / 2;
+               view.height = girth = pixbuf->get_height();
+               unity_loc = (int) rint (default_value * view.width) - 1;
+       }       
 
        add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
 
@@ -57,13 +72,20 @@ bool
 PixFader::on_expose_event (GdkEventExpose* ev)
 {
        GdkRectangle intersection;
-       int dh = display_height ();
-       int offset_into_pixbuf = (int) floor (view.height / ((float) view.height / dh));
+       int srcx, srcy, ds = display_span ();
+       int offset_into_pixbuf = (int) floor (span / ((float) span / ds));
        Glib::RefPtr<Gdk::GC> fg_gc (get_style()->get_fg_gc(get_state()));
 
        if (gdk_rectangle_intersect (&view, &ev->area, &intersection)) {
+               if (_orien == VERT) {
+                       srcx = intersection.x;
+                       srcy = offset_into_pixbuf + intersection.y;
+               } else {
+                       srcx = offset_into_pixbuf + intersection.x;
+                       srcy = intersection.y;
+               }
                get_window()->draw_pixbuf (fg_gc, pixbuf, 
-                                          intersection.x, offset_into_pixbuf + intersection.y,
+                                          srcx, srcy,
                                           intersection.x, intersection.y,
                                           intersection.width, intersection.height,
                                           Gdk::RGB_DITHER_NONE, 0, 0);
@@ -75,10 +97,12 @@ PixFader::on_expose_event (GdkEventExpose* ev)
        }
 
        /* always draw the line */
-
-       get_window()->draw_line (fg_gc, 1, unity_y, view.width - 2, unity_y);
-
-       last_drawn = dh;
+       if (_orien == VERT) {
+               get_window()->draw_line (fg_gc, 1, unity_loc, girth - 2, unity_loc);
+       } else {
+               get_window()->draw_line (fg_gc, unity_loc, 1, unity_loc, girth - 2);
+       }
+       last_drawn = ds;
        return true;
 }
 
@@ -96,8 +120,8 @@ PixFader::on_button_press_event (GdkEventButton* ev)
        case 1:
        case 2:
                add_modal_grab();
-               grab_y = ev->y;
-               grab_start = ev->y;
+               grab_loc = (_orien == VERT) ? ev->y : ev->x;
+               grab_start = (_orien == VERT) ? ev->y : ev->x;
                grab_window = ev->window;
                dragging = true;
                break;
@@ -112,7 +136,9 @@ PixFader::on_button_press_event (GdkEventButton* ev)
 bool
 PixFader::on_button_release_event (GdkEventButton* ev)
 {
-       double fract;
+       double fract, ev_pos;
+
+       ev_pos = (_orien == VERT) ? ev->y : 0; // Don't step if we are horizontal
        
        switch (ev->button) {
        case 1:
@@ -120,15 +146,15 @@ PixFader::on_button_release_event (GdkEventButton* ev)
                        remove_modal_grab();
                        dragging = false;
 
-                       if (ev->y == grab_start) {
+                       if (ev_pos == grab_start) {
 
                                /* no motion - just a click */
 
                                if (ev->state & Gdk::SHIFT_MASK) {
                                        adjustment.set_value (default_value);
-                               } else if (ev->state & GDK_CONTROL_MASK) {
+                               } else if (ev->state & fine_scale_modifier) {
                                        adjustment.set_value (adjustment.get_lower());
-                               } else if (ev->y < view.height - display_height()) {
+                               } else if (ev_pos < span - display_span()) {
                                        /* above the current display height, remember X Window coords */
                                        adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment());
                                } else {
@@ -144,7 +170,7 @@ PixFader::on_button_release_event (GdkEventButton* ev)
                        remove_modal_grab();
                        dragging = false;
                        
-                       fract = 1.0 - (ev->y / view.height); // inverted X Window coordinates, grrr
+                       fract = 1.0 - (ev_pos / span); // inverted X Window coordinates, grrr
                        
                        fract = min (1.0, fract);
                        fract = max (0.0, fract);
@@ -164,29 +190,45 @@ bool
 PixFader::on_scroll_event (GdkEventScroll* ev)
 {
        double scale;
-       
-       if (ev->state & GDK_CONTROL_MASK) {
-               if (ev->state & GDK_MOD1_MASK) {
-                       scale = 0.05;
+
+       if (ev->state & fine_scale_modifier) {
+               if (ev->state & extra_fine_scale_modifier) {
+                       scale = 0.01;
                } else {
-                       scale = 0.1;
+                       scale = 0.05;
                }
        } else {
-               scale = 0.5;
+               scale = 0.25;
        }
 
-       switch (ev->direction) {
-
-       case GDK_SCROLL_UP:
-               /* wheel up */
-               adjustment.set_value (adjustment.get_value() + (adjustment.get_page_increment() * scale));
-               break;
-       case GDK_SCROLL_DOWN:
-               /* wheel down */
-               adjustment.set_value (adjustment.get_value() - (adjustment.get_page_increment() * scale));
-               break;
-       default:
-               break;
+       if (_orien == VERT) {
+               switch (ev->direction) {
+
+               case GDK_SCROLL_UP:
+                       /* wheel up */
+                       adjustment.set_value (adjustment.get_value() + (adjustment.get_page_increment() * scale));
+                       break;
+               case GDK_SCROLL_DOWN:
+                       /* wheel down */
+                       adjustment.set_value (adjustment.get_value() - (adjustment.get_page_increment() * scale));
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               switch (ev->direction) {
+
+               case GDK_SCROLL_RIGHT:
+                       /* wheel right */
+                       adjustment.set_value (adjustment.get_value() + (adjustment.get_page_increment() * scale));
+                       break;
+               case GDK_SCROLL_LEFT:
+                       /* wheel left */
+                       adjustment.set_value (adjustment.get_value() - (adjustment.get_page_increment() * scale));
+                       break;
+               default:
+                       break;
+               }
        }
        return false;
 }
@@ -195,18 +237,17 @@ bool
 PixFader::on_motion_notify_event (GdkEventMotion* ev)
 {
        if (dragging) {
-               double fract;
-               double delta;
-               double scale;
-
+               double fract, delta, scale, ev_pos;
+                ev_pos = (_orien == VERT) ? ev->y : ev->x;
+               //cerr << "PixFader::on_motion_notify_event() called x:y = " << ev->x << ":" << ev->y;
                if (ev->window != grab_window) {
-                       grab_y = ev->y;
+                       grab_loc = ev_pos;
                        grab_window = ev->window;
                        return true;
                }
                
-               if (ev->state & GDK_CONTROL_MASK) {
-                       if (ev->state & GDK_MOD1_MASK) {
+               if (ev->state & fine_scale_modifier) {
+                       if (ev->state & extra_fine_scale_modifier) {
                                scale = 0.05;
                        } else {
                                scale = 0.1;
@@ -214,20 +255,23 @@ PixFader::on_motion_notify_event (GdkEventMotion* ev)
                } else {
                        scale = 1.0;
                }
+               //cerr << " ev_pos=" << ev_pos << " grab_loc=" << grab_loc;
+               delta = ev_pos - grab_loc;
+               grab_loc = ev_pos;
 
-               delta = ev->y - grab_y;
-               grab_y = ev->y;
-
-               fract = (delta / view.height);
+               fract = (delta / span);
 
                fract = min (1.0, fract);
                fract = max (-1.0, fract);
 
                // X Window is top->bottom for 0..Y
                
-               fract = -fract;
+               if (_orien == VERT) {
+                       fract = -fract;
+               }
 
                adjustment.set_value (adjustment.get_value() + scale * fract * (adjustment.get_upper() - adjustment.get_lower()));
+               //cerr << " adj=" << adjustment.get_value() << " fract=" << fract << " delta=" << delta << " scale=" << scale << endl;
        }
 
        return true;
@@ -236,14 +280,15 @@ PixFader::on_motion_notify_event (GdkEventMotion* ev)
 void
 PixFader::adjustment_changed ()
 {
-       if (display_height() != last_drawn) {
+       if (display_span() != last_drawn) {
                queue_draw ();
        }
 }
 
 int
-PixFader::display_height ()
+PixFader::display_span ()
 {
        float fract = (adjustment.get_upper() - adjustment.get_value ()) / ((adjustment.get_upper() - adjustment.get_lower()));
-       return (int) floor (view.height * (1.0 - fract));
+       return (_orien == VERT) ? (int)floor (span * (1.0 - fract)) : (int)floor (span * fract);
 }
+
index 3e2b42f409361011e3e275729b323dc335cf4e25..93dfb27ae2568baa2a1847e512b4498ff05aa052 100644 (file)
@@ -29,11 +29,11 @@ using namespace Gtkmm2ext;
 using namespace PBD;
 
 SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
-                                   Gtk::Adjustment *adj,
+                                   Gtk::Adjustment *adj,  int orientation,
                                    Controllable& c,
                                    bool with_numeric)
 
-       : PixFader (image, *adj),
+       : PixFader (image, *adj, orientation),
          binding_proxy (c),
          spin (*adj, 0, 2)
 {                        
@@ -63,7 +63,7 @@ VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
                                      Controllable& control,
                                      bool with_numeric)
 
-       : SliderController (image, adj, control, with_numeric)
+       : SliderController (image, adj, VERT, control, with_numeric)
 {
        if (with_numeric) {
                spin_frame.add (spin);
@@ -79,7 +79,7 @@ HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
                                      Controllable& control,
                                      bool with_numeric)
        
-       : SliderController (image, adj, control, with_numeric)
+       : SliderController (image, adj, HORIZ, control, with_numeric)
 {
        if (with_numeric) {
                spin_frame.add (spin);
diff --git a/libs/gtkmm2ext/sync-menu.c b/libs/gtkmm2ext/sync-menu.c
new file mode 100644 (file)
index 0000000..894446c
--- /dev/null
@@ -0,0 +1,977 @@
+/* GTK+ Integration for the Mac OS X Menubar.
+ *
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2007 Imendio AB
+ *
+ * For further information, see:
+ * http://developer.imendio.com/projects/gtk-macosx/menubar
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <Carbon/Carbon.h>
+
+#include <gtkmm2ext/sync-menu.h>
+
+
+/* TODO
+ *
+ * - Sync adding/removing/reordering items
+ * - Create on demand? (can this be done with gtk+? ie fill in menu
+     items when the menu is opened)
+ * - Figure out what to do per app/window...
+ *
+ */
+
+#define IGE_QUARTZ_MENU_CREATOR 'IGEC'
+#define IGE_QUARTZ_ITEM_WIDGET  'IWID'
+
+
+static void   sync_menu_shell (GtkMenuShell *menu_shell,
+                              MenuRef       carbon_menu,
+                              gboolean      toplevel,
+                              gboolean      debug);
+
+
+/*
+ * utility functions
+ */
+
+static GtkWidget *
+find_menu_label (GtkWidget *widget)
+{
+  GtkWidget *label = NULL;
+
+  if (GTK_IS_LABEL (widget))
+    return widget;
+
+  if (GTK_IS_CONTAINER (widget))
+    {
+      GList *children;
+      GList *l;
+
+      children = gtk_container_get_children (GTK_CONTAINER (widget));
+
+      for (l = children; l; l = l->next)
+       {
+         label = find_menu_label (l->data);
+         if (label)
+           break;
+       }
+
+      g_list_free (children);
+    }
+
+  return label;
+}
+
+static const gchar *
+get_menu_label_text (GtkWidget  *menu_item,
+                    GtkWidget **label)
+{
+  GtkWidget *my_label;
+
+  my_label = find_menu_label (menu_item);
+  if (label)
+    *label = my_label;
+
+  if (my_label)
+    return gtk_label_get_text (GTK_LABEL (my_label));
+
+  return NULL;
+}
+
+static gboolean
+accel_find_func (GtkAccelKey *key,
+                GClosure    *closure,
+                gpointer     data)
+{
+  return (GClosure *) data == closure;
+}
+
+
+/*
+ * CarbonMenu functions
+ */
+
+typedef struct
+{
+  MenuRef menu;
+} CarbonMenu;
+
+static GQuark carbon_menu_quark = 0;
+
+static CarbonMenu *
+carbon_menu_new (void)
+{
+  return g_slice_new0 (CarbonMenu);
+}
+
+static void
+carbon_menu_free (CarbonMenu *menu)
+{
+  g_slice_free (CarbonMenu, menu);
+}
+
+static CarbonMenu *
+carbon_menu_get (GtkWidget *widget)
+{
+  return g_object_get_qdata (G_OBJECT (widget), carbon_menu_quark);
+}
+
+static void
+carbon_menu_connect (GtkWidget *menu,
+                    MenuRef    menuRef)
+{
+  CarbonMenu *carbon_menu = carbon_menu_get (menu);
+
+  if (!carbon_menu)
+    {
+      carbon_menu = carbon_menu_new ();
+
+      g_object_set_qdata_full (G_OBJECT (menu), carbon_menu_quark,
+                              carbon_menu,
+                              (GDestroyNotify) carbon_menu_free);
+    }
+
+  carbon_menu->menu = menuRef;
+}
+
+
+/*
+ * CarbonMenuItem functions
+ */
+
+typedef struct
+{
+  MenuRef        menu;
+  MenuItemIndex  index;
+  MenuRef        submenu;
+  GClosure      *accel_closure;
+} CarbonMenuItem;
+
+static GQuark carbon_menu_item_quark = 0;
+
+static CarbonMenuItem *
+carbon_menu_item_new (void)
+{
+  return g_slice_new0 (CarbonMenuItem);
+}
+
+static void
+carbon_menu_item_free (CarbonMenuItem *menu_item)
+{
+  if (menu_item->accel_closure)
+    g_closure_unref (menu_item->accel_closure);
+
+  g_slice_free (CarbonMenuItem, menu_item);
+}
+
+static CarbonMenuItem *
+carbon_menu_item_get (GtkWidget *widget)
+{
+  return g_object_get_qdata (G_OBJECT (widget), carbon_menu_item_quark);
+}
+
+static void
+carbon_menu_item_update_state (CarbonMenuItem *carbon_item,
+                              GtkWidget      *widget)
+{
+  gboolean sensitive;
+  gboolean visible;
+  UInt32   set_attrs = 0;
+  UInt32   clear_attrs = 0;
+
+  g_object_get (widget,
+                "sensitive", &sensitive,
+                "visible",   &visible,
+                NULL);
+
+  if (!sensitive)
+    set_attrs |= kMenuItemAttrDisabled;
+  else
+    clear_attrs |= kMenuItemAttrDisabled;
+
+  if (!visible)
+    set_attrs |= kMenuItemAttrHidden;
+  else
+    clear_attrs |= kMenuItemAttrHidden;
+
+  ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
+                            set_attrs, clear_attrs);
+}
+
+static void
+carbon_menu_item_update_active (CarbonMenuItem *carbon_item,
+                               GtkWidget      *widget)
+{
+  gboolean active;
+
+  g_object_get (widget,
+                "active", &active,
+                NULL);
+
+  CheckMenuItem (carbon_item->menu, carbon_item->index,
+                active);
+}
+
+static void
+carbon_menu_item_update_submenu (CarbonMenuItem *carbon_item,
+                                GtkWidget      *widget)
+{
+  GtkWidget *submenu;
+
+  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+
+  if (submenu)
+    {
+      const gchar *label_text;
+      CFStringRef  cfstr = NULL;
+
+      label_text = get_menu_label_text (widget, NULL);
+      if (label_text)
+        cfstr = CFStringCreateWithCString (NULL, label_text,
+                                          kCFStringEncodingUTF8);
+
+      CreateNewMenu (0, 0, &carbon_item->submenu);
+      SetMenuTitleWithCFString (carbon_item->submenu, cfstr);
+      SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
+                                  carbon_item->submenu);
+
+      sync_menu_shell (GTK_MENU_SHELL (submenu), carbon_item->submenu, FALSE, FALSE);
+
+      if (cfstr)
+       CFRelease (cfstr);
+    }
+  else
+    {
+      SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
+                                  NULL);
+      carbon_item->submenu = NULL;
+    }
+}
+
+static void
+carbon_menu_item_update_label (CarbonMenuItem *carbon_item,
+                              GtkWidget      *widget)
+{
+  const gchar *label_text;
+  CFStringRef  cfstr = NULL;
+
+  label_text = get_menu_label_text (widget, NULL);
+  if (label_text)
+    cfstr = CFStringCreateWithCString (NULL, label_text,
+                                      kCFStringEncodingUTF8);
+
+  SetMenuItemTextWithCFString (carbon_item->menu, carbon_item->index,
+                              cfstr);
+
+  if (cfstr)
+    CFRelease (cfstr);
+}
+
+static void
+carbon_menu_item_update_accelerator (CarbonMenuItem *carbon_item,
+                                    GtkWidget      *widget)
+{
+  GtkWidget *label;
+
+  get_menu_label_text (widget, &label);
+
+  if (GTK_IS_ACCEL_LABEL (label) &&
+      GTK_ACCEL_LABEL (label)->accel_closure)
+    {
+      GtkAccelKey *key;
+
+      key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group,
+                                 accel_find_func,
+                                 GTK_ACCEL_LABEL (label)->accel_closure);
+
+      if (key            &&
+         key->accel_key &&
+         key->accel_flags & GTK_ACCEL_VISIBLE)
+       {
+         GdkDisplay      *display = gtk_widget_get_display (widget);
+         GdkKeymap       *keymap  = gdk_keymap_get_for_display (display);
+         GdkKeymapKey    *keys;
+         gint             n_keys;
+         gint             use_command;
+         gboolean         add_modifiers = FALSE;
+
+         if (gdk_keymap_get_entries_for_keyval (keymap, key->accel_key,
+                                                &keys, &n_keys) == 0)
+            {
+                 gint realkey = -1;
+
+                 switch (key->accel_key) {
+                 case GDK_rightarrow:
+                 case GDK_Right:
+                         realkey = kRightArrowCharCode;
+                         break;
+                 case GDK_leftarrow:
+                 case GDK_Left:
+                         realkey = kLeftArrowCharCode;
+                         break;
+                 case GDK_uparrow:
+                 case GDK_Up:
+                         realkey = kUpArrowCharCode;
+                         break;
+                 case GDK_downarrow:
+                 case GDK_Down:
+                         realkey = kDownArrowCharCode;
+                         break;
+                 default:
+                         break;
+                 }
+         
+                 if (realkey != -1) {
+                         SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
+                                                false, realkey);
+                         add_modifiers = TRUE;
+                 }
+
+           } else {
+                 SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
+                                        true, keys[0].keycode);
+                 g_free (keys);
+                 add_modifiers = TRUE;
+           }
+
+         if (add_modifiers)
+           {
+            UInt8 modifiers = 0; /* implies Command key */
+
+             use_command = 0;
+
+             if (key->accel_mods)
+               {
+                 if (key->accel_mods & GDK_SHIFT_MASK) {
+                   modifiers |= kMenuShiftModifier;
+                 }
+
+                 /* gdk/quartz maps Alt/Option to Mod1 */
+
+                 if (key->accel_mods & (GDK_MOD1_MASK)) {
+                   modifiers |= kMenuOptionModifier;
+                 }
+
+                 if (key->accel_mods & GDK_CONTROL_MASK) {
+                   modifiers |= kMenuControlModifier;
+                 }
+
+                 /* gdk/quartz maps Command to Meta */
+                 
+                 if (key->accel_mods & GDK_META_MASK) {
+                         use_command = 1;
+                 }
+               }  
+
+             if (!use_command)
+               modifiers |= kMenuNoCommandModifier;
+
+             SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
+                                   modifiers);
+
+             return;
+           }
+       }
+    }
+
+  /*  otherwise, clear the menu shortcut  */
+  SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
+                       kMenuNoModifiers | kMenuNoCommandModifier);
+  ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
+                           0, kMenuItemAttrUseVirtualKey);
+  SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
+                        false, 0);
+}
+
+static void
+carbon_menu_item_accel_changed (GtkAccelGroup   *accel_group,
+                               guint            keyval,
+                               GdkModifierType  modifier,
+                               GClosure        *accel_closure,
+                               GtkWidget       *widget)
+{
+  CarbonMenuItem *carbon_item = carbon_menu_item_get (widget);
+  GtkWidget      *label;
+
+  get_menu_label_text (widget, &label);
+
+  if (GTK_IS_ACCEL_LABEL (label) &&
+      GTK_ACCEL_LABEL (label)->accel_closure == accel_closure)
+    carbon_menu_item_update_accelerator (carbon_item, widget);
+}
+
+static void
+carbon_menu_item_update_accel_closure (CarbonMenuItem *carbon_item,
+                                      GtkWidget      *widget)
+{
+  GtkAccelGroup *group;
+  GtkWidget     *label;
+
+  get_menu_label_text (widget, &label);
+
+  if (carbon_item->accel_closure)
+    {
+      group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
+
+      g_signal_handlers_disconnect_by_func (group,
+                                           carbon_menu_item_accel_changed,
+                                           widget);
+
+      g_closure_unref (carbon_item->accel_closure);
+      carbon_item->accel_closure = NULL;
+    }
+
+  if (GTK_IS_ACCEL_LABEL (label))
+    carbon_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure;
+
+  if (carbon_item->accel_closure)
+    {
+      g_closure_ref (carbon_item->accel_closure);
+
+      group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
+
+      g_signal_connect_object (group, "accel-changed",
+                              G_CALLBACK (carbon_menu_item_accel_changed),
+                              widget, 0);
+    }
+
+  carbon_menu_item_update_accelerator (carbon_item, widget);
+}
+
+static void
+carbon_menu_item_notify (GObject        *object,
+                        GParamSpec     *pspec,
+                        CarbonMenuItem *carbon_item)
+{
+  if (!strcmp (pspec->name, "sensitive") ||
+      !strcmp (pspec->name, "visible"))
+    {
+      carbon_menu_item_update_state (carbon_item, GTK_WIDGET (object));
+    }
+  else if (!strcmp (pspec->name, "active"))
+    {
+      carbon_menu_item_update_active (carbon_item, GTK_WIDGET (object));
+    }
+  else if (!strcmp (pspec->name, "submenu"))
+    {
+      carbon_menu_item_update_submenu (carbon_item, GTK_WIDGET (object));
+    }
+}
+
+static void
+carbon_menu_item_notify_label (GObject    *object,
+                              GParamSpec *pspec,
+                              gpointer    data)
+{
+  CarbonMenuItem *carbon_item = carbon_menu_item_get (GTK_WIDGET (object));
+
+  if (!strcmp (pspec->name, "label"))
+    {
+      carbon_menu_item_update_label (carbon_item,
+                                    GTK_WIDGET (object));
+    }
+  else if (!strcmp (pspec->name, "accel-closure"))
+    {
+      carbon_menu_item_update_accel_closure (carbon_item,
+                                            GTK_WIDGET (object));
+    }
+}
+
+static CarbonMenuItem *
+carbon_menu_item_connect (GtkWidget     *menu_item,
+                         GtkWidget     *label,
+                         MenuRef        menu,
+                         MenuItemIndex  index)
+{
+  CarbonMenuItem *carbon_item = carbon_menu_item_get (menu_item);
+
+  if (!carbon_item)
+    {
+      carbon_item = carbon_menu_item_new ();
+
+      g_object_set_qdata_full (G_OBJECT (menu_item), carbon_menu_item_quark,
+                              carbon_item,
+                              (GDestroyNotify) carbon_menu_item_free);
+
+      g_signal_connect (menu_item, "notify",
+                        G_CALLBACK (carbon_menu_item_notify),
+                        carbon_item);
+
+      if (label)
+       g_signal_connect_swapped (label, "notify::label",
+                                 G_CALLBACK (carbon_menu_item_notify_label),
+                                 menu_item);
+    }
+
+  carbon_item->menu  = menu;
+  carbon_item->index = index;
+
+  return carbon_item;
+}
+
+
+/*
+ * carbon event handler
+ */
+
+static int _in_carbon_menu_event_handler = 0;
+
+int 
+gdk_quartz_in_carbon_menu_event_handler ()
+{
+       return _in_carbon_menu_event_handler;
+}
+
+static gboolean
+dummy_gtk_menu_item_activate (gpointer *arg)
+{
+       gtk_menu_item_activate (GTK_MENU_ITEM(arg));
+       return FALSE;
+}
+
+static OSStatus
+menu_event_handler_func (EventHandlerCallRef  event_handler_call_ref,
+                        EventRef             event_ref,
+                        void                *data)
+{
+  UInt32  event_class = GetEventClass (event_ref);
+  UInt32  event_kind = GetEventKind (event_ref);
+  MenuRef menu_ref;
+  OSStatus ret;
+
+  _in_carbon_menu_event_handler = 1;
+
+  switch (event_class)
+    {
+    case kEventClassCommand:
+      /* This is called when activating (is that the right GTK+ term?)
+       * a menu item.
+       */
+      if (event_kind == kEventCommandProcess)
+       {
+         HICommand command;
+         OSStatus  err;
+
+         /*g_printerr ("Menu: kEventClassCommand/kEventCommandProcess\n");*/
+
+         err = GetEventParameter (event_ref, kEventParamDirectObject,
+                                  typeHICommand, 0,
+                                  sizeof (command), 0, &command);
+
+         if (err == noErr)
+           {
+             GtkWidget *widget = NULL;
+
+             /* Get any GtkWidget associated with the item. */
+             err = GetMenuItemProperty (command.menu.menuRef,
+                                        command.menu.menuItemIndex,
+                                        IGE_QUARTZ_MENU_CREATOR,
+                                        IGE_QUARTZ_ITEM_WIDGET,
+                                        sizeof (widget), 0, &widget);
+             if (err == noErr && GTK_IS_WIDGET (widget))
+               {
+                 g_idle_add (dummy_gtk_menu_item_activate, widget);
+                 // gtk_menu_item_activate (GTK_MENU_ITEM (widget));
+                 _in_carbon_menu_event_handler = 0;
+                 return noErr;
+               }
+           }
+       }
+      break;
+
+    case kEventClassMenu:
+      GetEventParameter (event_ref,
+                        kEventParamDirectObject,
+                        typeMenuRef,
+                        NULL,
+                        sizeof (menu_ref),
+                        NULL,
+                        &menu_ref);
+
+      switch (event_kind)
+       {
+       case kEventMenuTargetItem:
+         /* This is called when an item is selected (what is the
+          * GTK+ term? prelight?)
+          */
+         /*g_printerr ("kEventClassMenu/kEventMenuTargetItem\n");*/
+         break;
+
+       case kEventMenuOpening:
+         /* Is it possible to dynamically build the menu here? We
+          * can at least set visibility/sensitivity.
+          */
+         /*g_printerr ("kEventClassMenu/kEventMenuOpening\n");*/
+         break;
+
+       case kEventMenuClosed:
+         /*g_printerr ("kEventClassMenu/kEventMenuClosed\n");*/
+         break;
+
+       default:
+         break;
+       }
+
+      break;
+
+    default:
+      break;
+    }
+
+  ret = CallNextEventHandler (event_handler_call_ref, event_ref);
+  _in_carbon_menu_event_handler = 0;
+  return ret;
+}
+
+static void
+setup_menu_event_handler (void)
+{
+  EventHandlerUPP menu_event_handler_upp;
+  EventHandlerRef menu_event_handler_ref;
+  const EventTypeSpec menu_events[] = {
+    { kEventClassCommand, kEventCommandProcess },
+    { kEventClassMenu, kEventMenuTargetItem },
+    { kEventClassMenu, kEventMenuOpening },
+    { kEventClassMenu, kEventMenuClosed }
+  };
+
+  /* FIXME: We might have to install one per window? */
+
+  menu_event_handler_upp = NewEventHandlerUPP (menu_event_handler_func);
+  InstallEventHandler (GetApplicationEventTarget (), menu_event_handler_upp,
+                      GetEventTypeCount (menu_events), menu_events, 0,
+                      &menu_event_handler_ref);
+
+#if 0
+  /* FIXME: Remove the handler with: */
+  RemoveEventHandler(menu_event_handler_ref);
+  DisposeEventHandlerUPP(menu_event_handler_upp);
+#endif
+}
+
+static void
+sync_menu_shell (GtkMenuShell *menu_shell,
+                 MenuRef       carbon_menu,
+                gboolean      toplevel,
+                gboolean      debug)
+{
+  GList         *children;
+  GList         *l;
+  MenuItemIndex  carbon_index = 1;
+
+  if (debug)
+    g_printerr ("%s: syncing shell %p\n", G_STRFUNC, menu_shell);
+
+  carbon_menu_connect (GTK_WIDGET (menu_shell), carbon_menu);
+
+  children = gtk_container_get_children (GTK_CONTAINER (menu_shell));
+
+  for (l = children; l; l = l->next)
+    {
+      GtkWidget      *menu_item = l->data;
+      CarbonMenuItem *carbon_item;
+
+      if (GTK_IS_TEAROFF_MENU_ITEM (menu_item))
+       continue;
+
+      if (toplevel && g_object_get_data (G_OBJECT (menu_item),
+                                        "gtk-empty-menu-item"))
+       continue;
+
+      carbon_item = carbon_menu_item_get (menu_item);
+
+      if (debug)
+       g_printerr ("%s: carbon_item %d for menu_item %d (%s, %s)\n",
+                   G_STRFUNC, carbon_item ? carbon_item->index : -1,
+                   carbon_index, get_menu_label_text (menu_item, NULL),
+                   g_type_name (G_TYPE_FROM_INSTANCE (menu_item)));
+
+      if (carbon_item && carbon_item->index != carbon_index)
+       {
+         if (debug)
+           g_printerr ("%s:   -> not matching, deleting\n", G_STRFUNC);
+
+         DeleteMenuItem (carbon_item->menu, carbon_index);
+         carbon_item = NULL;
+       }
+
+      if (!carbon_item)
+       {
+         GtkWidget          *label      = NULL;
+         const gchar        *label_text;
+         CFStringRef         cfstr      = NULL;
+         MenuItemAttributes  attributes = 0;
+
+         if (debug)
+           g_printerr ("%s:   -> creating new\n", G_STRFUNC);
+
+         label_text = get_menu_label_text (menu_item, &label);
+         if (label_text)
+           cfstr = CFStringCreateWithCString (NULL, label_text,
+                                              kCFStringEncodingUTF8);
+
+         if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item))
+           attributes |= kMenuItemAttrSeparator;
+
+         if (!GTK_WIDGET_IS_SENSITIVE (menu_item))
+           attributes |= kMenuItemAttrDisabled;
+
+         if (!GTK_WIDGET_VISIBLE (menu_item))
+           attributes |= kMenuItemAttrHidden;
+
+         InsertMenuItemTextWithCFString (carbon_menu, cfstr,
+                                         carbon_index - 1,
+                                         attributes, 0);
+         SetMenuItemProperty (carbon_menu, carbon_index,
+                              IGE_QUARTZ_MENU_CREATOR,
+                              IGE_QUARTZ_ITEM_WIDGET,
+                              sizeof (menu_item), &menu_item);
+
+         if (cfstr)
+           CFRelease (cfstr);
+
+         carbon_item = carbon_menu_item_connect (menu_item, label,
+                                                 carbon_menu,
+                                                 carbon_index);
+
+         if (GTK_IS_CHECK_MENU_ITEM (menu_item))
+           carbon_menu_item_update_active (carbon_item, menu_item);
+
+         carbon_menu_item_update_accel_closure (carbon_item, menu_item);
+
+         if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item)))
+           carbon_menu_item_update_submenu (carbon_item, menu_item);
+       }
+
+      carbon_index++;
+    }
+
+  g_list_free (children);
+}
+
+
+static gulong emission_hook_id = 0;
+
+static gboolean
+parent_set_emission_hook (GSignalInvocationHint *ihint,
+                         guint                  n_param_values,
+                         const GValue          *param_values,
+                         gpointer               data)
+{
+  GtkWidget *instance = g_value_get_object (param_values);
+
+  if (GTK_IS_MENU_ITEM (instance))
+    {
+      GtkWidget *previous_parent = g_value_get_object (param_values + 1);
+      GtkWidget *menu_shell      = NULL;
+
+      if (GTK_IS_MENU_SHELL (previous_parent))
+       {
+         menu_shell = previous_parent;
+        }
+      else if (GTK_IS_MENU_SHELL (instance->parent))
+       {
+         menu_shell = instance->parent;
+       }
+
+      if (menu_shell)
+        {
+         CarbonMenu *carbon_menu = carbon_menu_get (menu_shell);
+
+         if (carbon_menu)
+           {
+#if 0
+             g_printerr ("%s: item %s %p (%s, %s)\n", G_STRFUNC,
+                         previous_parent ? "removed from" : "added to",
+                         menu_shell,
+                         get_menu_label_text (instance, NULL),
+                         g_type_name (G_TYPE_FROM_INSTANCE (instance)));
+#endif
+
+             sync_menu_shell (GTK_MENU_SHELL (menu_shell),
+                              carbon_menu->menu,
+                              carbon_menu->menu == (MenuRef) data,
+                              FALSE);
+           }
+        }
+    }
+
+  return TRUE;
+}
+
+static void
+parent_set_emission_hook_remove (GtkWidget *widget,
+                                gpointer   data)
+{
+  g_signal_remove_emission_hook (g_signal_lookup ("parent-set",
+                                                 GTK_TYPE_WIDGET),
+                                emission_hook_id);
+}
+
+
+/*
+ * public functions
+ */
+
+void
+ige_mac_menu_set_menu_bar (GtkMenuShell *menu_shell)
+{
+  MenuRef carbon_menubar;
+
+  g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+
+  if (carbon_menu_quark == 0)
+    carbon_menu_quark = g_quark_from_static_string ("CarbonMenu");
+
+  if (carbon_menu_item_quark == 0)
+    carbon_menu_item_quark = g_quark_from_static_string ("CarbonMenuItem");
+
+  CreateNewMenu (0 /*id*/, 0 /*options*/, &carbon_menubar);
+  SetRootMenu (carbon_menubar);
+
+  setup_menu_event_handler ();
+
+  emission_hook_id =
+    g_signal_add_emission_hook (g_signal_lookup ("parent-set",
+                                                GTK_TYPE_WIDGET),
+                               0,
+                               parent_set_emission_hook,
+                               carbon_menubar, NULL);
+
+  g_signal_connect (menu_shell, "destroy",
+                   G_CALLBACK (parent_set_emission_hook_remove),
+                   NULL);
+
+  sync_menu_shell (menu_shell, carbon_menubar, TRUE, FALSE);
+}
+
+void
+ige_mac_menu_set_quit_menu_item (GtkMenuItem *menu_item)
+{
+  MenuRef       appmenu;
+  MenuItemIndex index;
+
+  g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
+
+  if (GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
+                                   &appmenu, &index) == noErr)
+    {
+      SetMenuItemCommandID (appmenu, index, 0);
+      SetMenuItemProperty (appmenu, index,
+                           IGE_QUARTZ_MENU_CREATOR,
+                           IGE_QUARTZ_ITEM_WIDGET,
+                           sizeof (menu_item), &menu_item);
+
+      gtk_widget_hide (GTK_WIDGET (menu_item));
+    }
+}
+
+
+struct _IgeMacMenuGroup
+{
+  GList *items;
+};
+
+static GList *app_menu_groups = NULL;
+
+IgeMacMenuGroup *
+ige_mac_menu_add_app_menu_group (void)
+{
+  IgeMacMenuGroup *group = g_slice_new0 (IgeMacMenuGroup);
+
+  app_menu_groups = g_list_append (app_menu_groups, group);
+
+  return group;
+}
+
+void
+ige_mac_menu_add_app_menu_item (IgeMacMenuGroup *group,
+                               GtkMenuItem     *menu_item,
+                               const gchar     *label)
+{
+  MenuRef  appmenu;
+  GList   *list;
+  gint     index = 0;
+
+  g_return_if_fail (group != NULL);
+  g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
+
+  if (GetIndMenuItemWithCommandID (NULL, kHICommandHide, 1,
+                                   &appmenu, NULL) != noErr)
+    {
+      g_warning ("%s: retrieving app menu failed",
+                G_STRFUNC);
+      return;
+    }
+
+  for (list = app_menu_groups; list; list = g_list_next (list))
+    {
+      IgeMacMenuGroup *list_group = list->data;
+
+      index += g_list_length (list_group->items);
+
+      /*  adjust index for the separator between groups, but not
+       *  before the first group
+       */
+      if (list_group->items && list->prev)
+       index++;
+
+      if (group == list_group)
+       {
+         CFStringRef cfstr;
+
+         /*  add a separator before adding the first item, but not
+          *  for the first group
+          */
+         if (!group->items && list->prev)
+           {
+             InsertMenuItemTextWithCFString (appmenu, NULL, index,
+                                             kMenuItemAttrSeparator, 0);
+             index++;
+           }
+
+         if (!label)
+           label = get_menu_label_text (GTK_WIDGET (menu_item), NULL);
+
+         cfstr = CFStringCreateWithCString (NULL, label,
+                                            kCFStringEncodingUTF8);
+
+         InsertMenuItemTextWithCFString (appmenu, cfstr, index, 0, 0);
+         SetMenuItemProperty (appmenu, index + 1,
+                              IGE_QUARTZ_MENU_CREATOR,
+                              IGE_QUARTZ_ITEM_WIDGET,
+                              sizeof (menu_item), &menu_item);
+
+         CFRelease (cfstr);
+
+         gtk_widget_hide (GTK_WIDGET (menu_item));
+
+         group->items = g_list_append (group->items, menu_item);
+
+         return;
+       }
+    }
+
+  if (!list)
+    g_warning ("%s: app menu group %p does not exist",
+              G_STRFUNC, group);
+}
index 797be5de452b6a0c054c892bdbd6955058aaa39d..34e58886875e2e0553d476ea9f230a5991b27249 100644 (file)
@@ -8,7 +8,7 @@ void
 disable_screen_updates ()
 {
 #ifdef GTKOSX
-       NSDisableScreenUpdates ();
+       // NSDisableScreenUpdates ();
 #endif
 }
 
@@ -16,6 +16,6 @@ void
 enable_screen_updates ()
 {
 #ifdef GTKOSX
-       NSEnableScreenUpdates();
+       // NSEnableScreenUpdates();
 #endif
 }
index 592fca37689aa35d83ab1094d023379170427dc2..a35b789ef305b217a5a24ee0e7e97ee386a39ca9 100644 (file)
@@ -21,6 +21,6 @@ Default(libvampplugins)
 env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'vamp'), libvampplugins))
 
 env.Alias('tarball', env.Distribute (env['DISTTREE'],
-                                     [ 'SConscript', 'COPYING', 'README' ] +
+                                     [ 'SConscript' ] +
                                      plugin_files +
                                      glob.glob('*.h')))
index 5000e5a2a4434aa565962f64e83ddc93f07cda59..592c4ae9a8583be03f72c90916a45e7aee09450c 100644 (file)
@@ -1,4 +1,4 @@
 #ifndef __ardour_svn_revision_h__
 #define __ardour_svn_revision_h__
-static const char* ardour_svn_revision = "2985";
+static const char* ardour_svn_revision = "3046";
 #endif
index 48d3837368089f6eff253f1a077466bf94469d29..18f6e6a65ead41a51cf1d417bbe17ab420546fa0 100755 (executable)
@@ -53,6 +53,10 @@ if not File.exist?(libdir+"/surfaces") then
    Dir.mkdir(libdir + "/surfaces")
 end
 
+if not File.exist?(libdir+"/vamp-plugins") then
+   Dir.mkdir(libdir + "/vamp-plugins")
+end
+
 
 odir = Dir.getwd
 Dir.chdir("../..")
@@ -67,6 +71,9 @@ results = results + result.split("\n").slice(1,result.size-1)
 result =  `otool -L libs/surfaces/*/*.dylib`
 results = results + result.split("\n").slice(1,result.size-1)
 
+result =  `otool -L libs/vamp-plugins/*.dylib`
+results = results + result.split("\n").slice(1,result.size-1)
+
 results.uniq!
 
 $stdout.print("Copying libs to #{libdir} ...\n");
@@ -117,6 +124,9 @@ begin
 rescue
 end
 
+# vamp plugins
+`cp ../../libs/vamp-plugins/*.dylib #{libdir}/vamp-plugins`
+
 
 # copy gtk and pango lib stuff
 `cp -R /opt/local/lib/pango #{libdir}/`
index 41a2904ff93cd06350270c7474d963671025416a..0ac0370c8200c20feb5250e7c93b14c73fea5110 100755 (executable)
@@ -24,10 +24,13 @@ export ARDOUR_MODULE_PATH="$TOP/lib/"
 export ARDOUR_DATA_PATH="$TOP/share"
 export ARDOUR_GLADE_PATH="$TOP/share/ardour2/glade"
 
-export LADSPA_RDF_PATH="$HOME/Library/Audio/Plug-Ins/LADSPA/rdf:/Library/Audio/Plug-Ins/LADSPA/rdf:$TOP/s
-hare/ladspa/rdf:/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf"
-export LADSPA_PATH="$HOME/Library/Audio/Plug-Ins/LADSPA:/Library/Audio/Plug-Ins/LADSPA:/usr/local/lib/lad
-spa:/usr/lib/ladspa"
+export ARDOUR_PATH="$TOP/share/ardour/icons:$TOP/share/ardour/pixmaps"
+
+
+export LADSPA_RDF_PATH="$HOME/Library/Audio/Plug-Ins/LADSPA/rdf:/Library/Audio/Plug-Ins/LADSPA/rdf:$TOP/share/ladspa/rdf:/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf"
+export LADSPA_PATH="$HOME/Library/Audio/Plug-Ins/LADSPA:/Library/Audio/Plug-Ins/LADSPA:/usr/local/lib/ladspa:/usr/lib/ladspa"
+
+export VAMP_PATH="$TOP/lib/vamp-plugins" 
 
 mkdir -p "$ETC"
 sed 's|${HOME}|'"$HOME|g" "$TOP/etc/pango/pangorc" > "$ETC/pangorc"
index eb4dd6683b0fa3d0dcf630be2732da47d4699ff8..4a130fed808e47fd859ff71b2d063132fe3153b0 100644 (file)
@@ -68,7 +68,7 @@ wine_executable = ardour_vst.SubstInFile ('ardourvst', 'ardourvst.in', SUBST_DIC
 
 if ardour_vst['VST']:
     ardour_vst.AddPostAction (wine_executable, ardour_vst.Action (Chmod ('vst/ardevst', 0755)))
-    ardour_vst.AddPostAction (wine_executable, ardour_vst.Action (Chmod (wine_executable, 0755)))
+    ardour_vst.AddPostAction (wine_executable, ardour_vst.Action (Chmod ("vst/" + str(wine_executable[0]), 0755)))
     Default([wine_generated_executable, wine_executable])
     
     # the wine script - into the bin dir