summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-02-16 22:55:47 +0000
committerDavid Robillard <d@drobilla.net>2008-02-16 22:55:47 +0000
commit859e9106e72a7908fa093d946111d148223225a0 (patch)
treeec47825b5f5746bcbc5d321d40da7fc798f5c380 /libs
parent8aa9508c82f32efcf9c7c00e2c9e76268d4dddce (diff)
Merge with 2.0-ongoing R3071.
git-svn-id: svn://localhost/ardour2/branches/3.0@3074 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/appleutility/AUParamInfo.cpp134
-rw-r--r--libs/appleutility/AUParamInfo.h107
-rw-r--r--libs/appleutility/CAAUParameter.cpp316
-rw-r--r--libs/appleutility/CAAUParameter.h187
-rw-r--r--libs/ardour/SConscript12
-rw-r--r--libs/ardour/analyser.cc2
-rw-r--r--libs/ardour/ardour/ardour.h7
-rw-r--r--libs/ardour/ardour/audio_unit.h16
-rw-r--r--libs/ardour/ardour/audiosource.h1
-rw-r--r--libs/ardour/ardour/automatable.h5
-rw-r--r--libs/ardour/ardour/configuration_vars.h1
-rw-r--r--libs/ardour/ardour/io.h4
-rw-r--r--libs/ardour/ardour/io_processor.h2
-rw-r--r--libs/ardour/ardour/playlist.h1
-rw-r--r--libs/ardour/ardour/route.h4
-rw-r--r--libs/ardour/ardour/session.h17
-rw-r--r--libs/ardour/ardour/types.h3
-rw-r--r--libs/ardour/ardour/utils.h2
-rw-r--r--libs/ardour/audio_track.cc2
-rw-r--r--libs/ardour/audio_unit.cc178
-rw-r--r--libs/ardour/audioengine.cc2
-rw-r--r--libs/ardour/audiofilesource.cc26
-rw-r--r--libs/ardour/audioregion.cc11
-rw-r--r--libs/ardour/audiosource.cc19
-rw-r--r--libs/ardour/automatable.cc4
-rw-r--r--libs/ardour/filter.cc5
-rw-r--r--libs/ardour/globals.cc73
-rw-r--r--libs/ardour/import.cc51
-rw-r--r--libs/ardour/io.cc22
-rw-r--r--libs/ardour/playlist.cc40
-rw-r--r--libs/ardour/plugin.cc13
-rw-r--r--libs/ardour/region.cc8
-rw-r--r--libs/ardour/route.cc32
-rw-r--r--libs/ardour/session.cc135
-rw-r--r--libs/ardour/session_state.cc9
-rw-r--r--libs/ardour/session_transport.cc4
-rw-r--r--libs/ardour/source.cc2
-rw-r--r--libs/ardour/transient_detector.cc16
-rw-r--r--libs/ardour/utils.cc44
-rw-r--r--libs/gtkmm2/pango/SConscript3
-rw-r--r--libs/gtkmm2ext/SConscript14
-rw-r--r--libs/gtkmm2ext/gtk_ui.cc21
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/pixfader.h21
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/slider_controller.h2
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/sync-menu.h44
-rw-r--r--libs/gtkmm2ext/pixfader.cc151
-rw-r--r--libs/gtkmm2ext/slider_controller.cc8
-rw-r--r--libs/gtkmm2ext/sync-menu.c977
-rw-r--r--libs/pbd/misc.c4
-rw-r--r--libs/vamp-plugins/SConscript2
50 files changed, 2522 insertions, 242 deletions
diff --git a/libs/appleutility/AUParamInfo.cpp b/libs/appleutility/AUParamInfo.cpp
new file mode 100644
index 0000000000..9b0046166f
--- /dev/null
+++ b/libs/appleutility/AUParamInfo.cpp
@@ -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
index 0000000000..9d342080b1
--- /dev/null
+++ b/libs/appleutility/AUParamInfo.h
@@ -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
index 0000000000..b99b6ab749
--- /dev/null
+++ b/libs/appleutility/CAAUParameter.cpp
@@ -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
index 0000000000..4f35b26353
--- /dev/null
+++ b/libs/appleutility/CAAUParameter.h
@@ -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__
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 529a778942..7521bd728a 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -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')))
diff --git a/libs/ardour/analyser.cc b/libs/ardour/analyser.cc
index 7ddb5428e9..2e14c74b86 100644
--- a/libs/ardour/analyser.cc
+++ b/libs/ardour/analyser.cc
@@ -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);
}
}
diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h
index fcec83394f..6f653f10bf 100644
--- a/libs/ardour/ardour/ardour.h
+++ b/libs/ardour/ardour/ardour.h
@@ -20,8 +20,10 @@
#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 ();
diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h
index c781e8200d..bdeac0477b 100644
--- a/libs/ardour/ardour/audio_unit.h
+++ b/libs/ardour/ardour/audio_unit.h
@@ -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;
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 1589841baa..d11b829694 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -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;
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index f96ecc0bd1..a2c1d98ae7 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -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;
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 134557daeb..015c617425 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -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)
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index 0b82844f61..83b6378dae 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -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);
diff --git a/libs/ardour/ardour/io_processor.h b/libs/ardour/ardour/io_processor.h
index 409ad91b15..a535ce3bb4 100644
--- a/libs/ardour/ardour/io_processor.h
+++ b/libs/ardour/ardour/io_processor.h
@@ -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;
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index d8a38841f8..4640a8e32f 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -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 ();
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 2466f37996..c7c0b77102 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -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);
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index c0c178eb02..10167ae5b3 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -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 ();
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index fdf8d0b439..efc2e35ecc 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -257,7 +257,8 @@ namespace ARDOUR {
enum EditMode {
Slide,
- Splice
+ Splice,
+ Lock
};
enum RegionPoint {
diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h
index e52274eb1f..eecde2e85f 100644
--- a/libs/ardour/ardour/utils.h
+++ b/libs/ardour/ardour/utils.h
@@ -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);
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index bc2f0d9feb..7d55cc343a 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -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);
}
}
diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc
index 387c7f1238..9132957743 100644
--- a/libs/ardour/audio_unit.cc
+++ b/libs/ardour/audio_unit.cc
@@ -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
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index da4f8a642c..8d2589db0e 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -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));
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 81ad45e08a..00e0f925df 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -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
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 20115ff944..7e2b709abd 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -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;
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index cd71dd21e4..01dea08d3e 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -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;
+ }
}
}
}
diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc
index 45b19d1997..8b8b843384 100644
--- a/libs/ardour/automatable.cc
+++ b/libs/ardour/automatable.cc
@@ -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()) {
diff --git a/libs/ardour/filter.cc b/libs/ardour/filter.cc
index dc8185db95..be382f72da 100644
--- a/libs/ardour/filter.cc
+++ b/libs/ardour/filter.cc
@@ -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 */
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 6aba688cae..02c4a5ced6 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -19,9 +19,12 @@
#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>
@@ -31,12 +34,16 @@
#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));
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index 91e5b9850c..2bc3a00a7a 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -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);
}
@@ -124,6 +127,25 @@ get_paths_for_new_sources (const string& import_file_path, const string& session
}
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 */
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index babf1e451f..f57d5b39de 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -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
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index da3a812123..65279499ec 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -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
diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc
index 95629f2561..3d218448dd 100644
--- a/libs/ardour/plugin.cc
+++ b/libs/ardour/plugin.cc
@@ -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);
}
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 2193a69908..508f09a480 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -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;
}
}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index fd0d99e87a..560946d9da 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -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);
}
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 5a3144b828..4cfcda992e 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -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
@@ -2546,41 +2561,54 @@ 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;
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index af4be07dc4..c4448640fd 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -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);
}
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index d422698f30..e6318f5503 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -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.
diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc
index 7941eb693b..f08d08b86e 100644
--- a/libs/ardour/source.cc
+++ b/libs/ardour/source.cc
@@ -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;
}
+
diff --git a/libs/ardour/transient_detector.cc b/libs/ardour/transient_detector.cc
index b92bf5fb2d..d24c4c9442 100644
--- a/libs/ardour/transient_detector.cc
+++ b/libs/ardour/transient_detector.cc
@@ -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()
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index cfd38c5099..99a6dbbc88 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -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");
diff --git a/libs/gtkmm2/pango/SConscript b/libs/gtkmm2/pango/SConscript
index 1caa21376c..b08b8b2145 100644
--- a/libs/gtkmm2/pango/SConscript
+++ b/libs/gtkmm2/pango/SConscript
@@ -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)
diff --git a/libs/gtkmm2ext/SConscript b/libs/gtkmm2ext/SConscript
index 829182c71e..fad538a40e 100644
--- a/libs/gtkmm2ext/SConscript
+++ b/libs/gtkmm2ext/SConscript
@@ -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')))
diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc
index 660ea32ad1..f00c6cd1e1 100644
--- a/libs/gtkmm2ext/gtk_ui.cc
+++ b/libs/gtkmm2ext/gtk_ui.cc
@@ -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;
diff --git a/libs/gtkmm2ext/gtkmm2ext/pixfader.h b/libs/gtkmm2ext/gtkmm2ext/pixfader.h
index d974f5d5bc..519e1c9e1e 100644
--- a/libs/gtkmm2ext/gtkmm2ext/pixfader.h
+++ b/libs/gtkmm2ext/gtkmm2ext/pixfader.h
@@ -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;
};
diff --git a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
index 74ff36816b..60c8eef660 100644
--- a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
+++ b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
@@ -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
index 0000000000..2be5e71d02
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/sync-menu.h
@@ -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__ */
diff --git a/libs/gtkmm2ext/pixfader.cc b/libs/gtkmm2ext/pixfader.cc
index f3a40ffc69..fe464d0fac 100644
--- a/libs/gtkmm2ext/pixfader.cc
+++ b/libs/gtkmm2ext/pixfader.cc
@@ -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);
}
+
diff --git a/libs/gtkmm2ext/slider_controller.cc b/libs/gtkmm2ext/slider_controller.cc
index 3e2b42f409..93dfb27ae2 100644
--- a/libs/gtkmm2ext/slider_controller.cc
+++ b/libs/gtkmm2ext/slider_controller.cc
@@ -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
index 0000000000..894446c424
--- /dev/null
+++ b/libs/gtkmm2ext/sync-menu.c
@@ -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);
+}
diff --git a/libs/pbd/misc.c b/libs/pbd/misc.c
index 797be5de45..34e5888687 100644
--- a/libs/pbd/misc.c
+++ b/libs/pbd/misc.c
@@ -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
}
diff --git a/libs/vamp-plugins/SConscript b/libs/vamp-plugins/SConscript
index 592fca3768..a35b789ef3 100644
--- a/libs/vamp-plugins/SConscript
+++ b/libs/vamp-plugins/SConscript
@@ -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')))