Merge with 2.0-ongoing R3071.

git-svn-id: svn://localhost/ardour2/branches/3.0@3074 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2008-02-16 22:55:47 +00:00
parent 8aa9508c82
commit 859e9106e7
57 changed files with 2551 additions and 249 deletions

View File

@ -31,6 +31,7 @@ opts.AddOptions(
BoolOption('COREAUDIO', 'Compile with Apple\'s CoreAudio library', 0),
BoolOption('GTKOSX', 'Compile for use with GTK-OSX, not GTK-X11', 0),
BoolOption('NATIVE_OSX_KEYS', 'Build key bindings file that matches OS X conventions', 0),
BoolOption('OLDFONTS', 'Old school font sizes', 0),
BoolOption('DEBUG', 'Set to build with debugging information and no optimizations', 0),
PathOption('DESTDIR', 'Set the intermediate install "prefix"', '/'),
EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'leopard', 'none' ), ignorecase=2),
@ -538,7 +539,7 @@ if env['LV2']:
else:
print 'Building Ardour with LV2 support requires SLV2 >= 0.6.0'
print 'WARNING: SLV2 not found, or too old. Ardour will be built without LV2 support.'
print 'Until the 2.3 release, Ardour requires SLV2 out of SVN.'
print 'Until the 2.4 release, Ardour requires SLV2 out of SVN.'
print 'Testing would be very much appreciated! svn co http://svn.drobilla.net/lad/slv2'
env['LV2'] = 0
conf.Finish()

View File

@ -21,6 +21,7 @@
<Option name="plugins-stop-with-transport" value="no"/>
<Option name="no-sw-monitoring" value="no"/>
<Option name="stop-recording-on-xrun" value="no"/>
<Option name="create-xrun-marker" value="yes"/>
<Option name="stop-at-session-end" value="no"/>
<Option name="auto-xfade" value="yes"/>
<Option name="crossfades-active" value="1"/>

View File

@ -809,6 +809,8 @@ AudioRegionView::create_waves ()
ChanCount nchans = atv.get_diskstream()->n_channels();
cerr << "creating waves for " << _region->name() << " with wfd = " << wait_for_data << " and channels = " << nchans << endl;
/* in tmp_waves, set up null pointers for each channel so the vector is allocated */
for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
tmp_waves.push_back (0);
@ -822,15 +824,20 @@ AudioRegionView::create_waves ()
wave_caches.push_back (WaveView::create_cache ());
cerr << "\tchannel " << n << endl;
if (wait_for_data) {
if (audio_region()->audio_source(n)->peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) {
cerr << "\tData is ready\n";
create_one_wave (n, true);
} else {
cerr << "\tdata is not ready\n";
// we'll get a PeaksReady signal from the source in the future
// and will call create_one_wave(n) then.
}
} else {
cerr << "\tdon't delay, display today!\n";
create_one_wave (n, true);
}

View File

@ -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;
}

View File

@ -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; }
};

View File

@ -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

View File

@ -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__

View File

@ -20,6 +20,9 @@ ardour.Append(CXXFLAGS=["-DLIBSIGC_DISABLE_DEPRECATED", "-DGLIBMM_EXCEPTIONS_ENA
ardour.Append(PACKAGE = domain)
ardour.Append(POTFILE = domain + '.pot')
if ardour['IS_OSX']:
ardour.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
#
# explicitly reference the control protocol LGPL library for includes
#
@ -312,7 +315,7 @@ ardour.Merge ([
libraries['sndfile-ardour'],
libraries['vamp'],
libraries['vamphost'],
libraries['xml'],
libraries['xml']
])
if ardour['RUBBERBAND']:
@ -380,5 +383,10 @@ env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'i18n.h', 'gettext.h' ] +
[ 'sse_functions_xmm.cc', 'sse_functions.s', 'sse_functions_64bit.s' ] +
[ 'rb_effect.cc', 'st_stretch.cc', 'st_pitch.cc' ] +
ardour_files + osc_files + vst_files + coreaudio_files + audiounit_files +
ardour_files +
osc_files +
vst_files +
coreaudio_files +
audiounit_files +
lv2_files +
glob.glob('po/*.po') + glob.glob('ardour/*.h')))

View File

@ -95,7 +95,7 @@ Analyser::work ()
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) {
if (afs && afs->length()) {
analyse_audio_file_source (afs);
}
}

View File

@ -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 ();

View File

@ -32,6 +32,7 @@
#include <ardour/plugin.h>
#include <AudioUnit/AudioUnit.h>
#include <appleutility/AUParamInfo.h>
#include <boost/shared_ptr.hpp>
@ -45,6 +46,16 @@ namespace ARDOUR {
class AudioEngine;
class Session;
struct AUParameterDescriptor : public Plugin::ParameterDescriptor {
// additional fields to make operations more efficient
AudioUnitParameterID id;
AudioUnitScope scope;
AudioUnitElement element;
float default_value;
bool automatable;
AudioUnitParameterUnit unit;
};
class AUPlugin : public ARDOUR::Plugin
{
public:
@ -105,7 +116,7 @@ class AUPlugin : public ARDOUR::Plugin
private:
boost::shared_ptr<CAComponent> comp;
boost::shared_ptr<CAAudioUnit> unit;
AudioStreamBasicDescription streamFormat;
bool initialized;
int format_set;
@ -119,6 +130,7 @@ class AUPlugin : public ARDOUR::Plugin
int set_input_format ();
int set_stream_format (int scope, uint32_t cnt);
int _set_block_size (nframes_t nframes);
void discover_parameters ();
std::vector<std::pair<uint32_t, uint32_t> > parameter_map;
uint32_t current_maxbuf;
@ -126,6 +138,8 @@ class AUPlugin : public ARDOUR::Plugin
nframes_t cb_offset;
vector<Sample*>* current_buffers;
nframes_t frames_processed;
std::vector<AUParameterDescriptor> descriptors;
};
typedef boost::shared_ptr<AUPlugin> AUPluginPtr;

View File

@ -116,7 +116,6 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
static bool _build_peakfiles;
bool _peaks_built;
bool _analysed;
mutable Glib::Mutex _lock;
mutable Glib::Mutex _peaks_ready_lock;
Glib::ustring peakpath;

View File

@ -57,7 +57,10 @@ public:
virtual void add_control(boost::shared_ptr<AutomationControl>);
virtual void automation_snapshot(nframes_t now);
virtual void automation_snapshot(nframes_t now, bool force);
bool should_snapshot (nframes_t now) {
return (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval);
}
virtual void transport_stopped(nframes_t now);
virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;

View File

@ -105,6 +105,7 @@ CONFIG_VARIABLE (bool, punch_out, "punch-out", false)
CONFIG_VARIABLE (bool, plugins_stop_with_transport, "plugins-stop-with-transport", false)
CONFIG_VARIABLE (bool, do_not_record_plugins, "do-not-record-plugins", false)
CONFIG_VARIABLE (bool, stop_recording_on_xrun, "stop-recording-on-xrun", false)
CONFIG_VARIABLE (bool, create_xrun_marker, "create-xrun-marker", true)
CONFIG_VARIABLE (bool, stop_at_session_end, "stop-at-session-end", true)
CONFIG_VARIABLE (bool, seamless_loop, "seamless-loop", false)
CONFIG_VARIABLE (nframes_t, preroll, "preroll", 0)

View File

@ -251,8 +251,8 @@ class IO : public Automatable, public Latent
void set_parameter_automation_state (Parameter, AutoState);
virtual void transport_stopped (nframes_t now); // interface: matches Insert
void automation_snapshot (nframes_t now); // interface: matches Automatable
virtual void transport_stopped (nframes_t now);
virtual void automation_snapshot (nframes_t now, bool force);
void start_pan_touch (uint32_t which);
void end_pan_touch (uint32_t which);

View File

@ -65,7 +65,7 @@ class IOProcessor : public Processor
boost::shared_ptr<IO> io() { return _io; }
boost::shared_ptr<const IO> io() const { return _io; }
virtual void automation_snapshot (nframes_t now) { _io->automation_snapshot(now); }
virtual void automation_snapshot (nframes_t now, bool force) { _io->automation_snapshot(now, force); }
virtual void run_in_place (BufferSet& in, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset) = 0;

View File

@ -126,7 +126,6 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
sigc::signal<void> LengthChanged;
static string bump_name (string old_name, Session&);
static string bump_name_once (string old_name);
void freeze ();
void thaw ();

View File

@ -75,6 +75,8 @@ class Route : public IO
Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
virtual ~Route();
static std::string ensure_track_or_route_name(std::string, Session &);
std::string comment() { return _comment; }
void set_comment (std::string str, void *src);
@ -247,7 +249,7 @@ class Route : public IO
return _mute_control;
}
void automation_snapshot (nframes_t now);
void automation_snapshot (nframes_t now, bool force=false);
void protect_automation ();
void set_remote_control_id (uint32_t id);

View File

@ -353,7 +353,7 @@ class Session : public PBD::StatefulDestructible
sigc::signal<void> TransportStateChange; /* generic */
sigc::signal<void,nframes_t> PositionChanged; /* sent after any non-sequential motion */
sigc::signal<void> DurationChanged;
sigc::signal<void> HaltOnXrun;
sigc::signal<void,nframes_t> Xrun;
sigc::signal<void> TransportLooped;
sigc::signal<void,RouteList&> RouteAdded;
@ -563,8 +563,11 @@ class Session : public PBD::StatefulDestructible
/* region info */
sigc::signal<void,boost::shared_ptr<Region> > RegionAdded;
sigc::signal<void,boost::shared_ptr<Region> > RegionRemoved;
void add_regions (std::vector<boost::shared_ptr<Region> >&);
sigc::signal<void,boost::weak_ptr<Region> > RegionAdded;
sigc::signal<void,std::vector<boost::weak_ptr<Region> >& > RegionsAdded;
sigc::signal<void,boost::weak_ptr<Region> > RegionRemoved;
int region_name (string& result, string base = string(""), bool newlevel = false) const;
string new_region_name (string);
@ -586,10 +589,10 @@ class Session : public PBD::StatefulDestructible
string doing_what;
/* control info */
bool sample_convert;
SrcQuality quality;
volatile bool freeze;
std::vector<Glib::ustring> paths;
bool replace_existing_source;
/* result */
SourceList sources;
@ -1480,6 +1483,12 @@ class Session : public PBD::StatefulDestructible
SourceMap sources;
public:
SourceMap get_sources() { return sources; }
private:
int load_sources (const XMLNode& node);
XMLNode& get_sources_as_xml ();

View File

@ -257,7 +257,8 @@ namespace ARDOUR {
enum EditMode {
Slide,
Splice
Splice,
Lock
};
enum RegionPoint {

View File

@ -45,6 +45,8 @@ static inline float f_max(float x, float a) {
return (x);
}
std::string bump_name_once(std::string s);
int cmp_nocase (const std::string& s, const std::string& s2);
int touch_file(Glib::ustring path);

View File

@ -519,7 +519,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
if (lm.locked()) {
// automation snapshot can also be called from the non-rt context
// and it uses the redirect list, so we take the lock out here
automation_snapshot (start_frame);
automation_snapshot (start_frame, false);
}
}

View File

@ -32,6 +32,7 @@
#include <ardour/utils.h>
#include <appleutility/CAAudioUnit.h>
#include <appleutility/CAAUParameter.h>
#include <CoreServices/CoreServices.h>
#include <AudioUnit/AudioUnit.h>
@ -83,6 +84,7 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAC
throw failed_constructor();
}
unit->GetElementCount (kAudioUnitScope_Global, global_elements);
unit->GetElementCount (kAudioUnitScope_Input, input_elements);
unit->GetElementCount (kAudioUnitScope_Output, output_elements);
@ -106,6 +108,10 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAC
error << _("AUPlugin: cannot set processing block size") << endmsg;
throw failed_constructor();
}
discover_parameters ();
Plugin::setup_controls ();
}
AUPlugin::~AUPlugin ()
@ -119,6 +125,124 @@ AUPlugin::~AUPlugin ()
}
}
void
AUPlugin::discover_parameters ()
{
/* discover writable parameters */
cerr << "get param info, there are " << global_elements << " global elements\n";
AudioUnitScope scopes[] = {
kAudioUnitScope_Global,
kAudioUnitScope_Output,
kAudioUnitScope_Input
};
descriptors.clear ();
for (uint32_t i = 0; i < sizeof (scopes) / sizeof (scopes[0]); ++i) {
AUParamInfo param_info (unit->AU(), false, false, scopes[i]);
cerr << "discovered " << param_info.NumParams() << " parameters in scope " << i << endl;
for (uint32_t i = 0; i < param_info.NumParams(); ++i) {
AUParameterDescriptor d;
d.id = param_info.ParamID (i);
const CAAUParameter* param = param_info.GetParamInfo (d.id);
const AudioUnitParameterInfo& info (param->ParamInfo());
const int len = CFStringGetLength (param->GetName());;
char local_buffer[len*2];
Boolean good = CFStringGetCString(param->GetName(),local_buffer,len*2,kCFStringEncodingMacRoman);
if (!good) {
d.label = "???";
} else {
d.label = local_buffer;
}
d.scope = param_info.GetScope ();
d.element = param_info.GetElement ();
/* info.units to consider */
/*
kAudioUnitParameterUnit_Generic = 0
kAudioUnitParameterUnit_Indexed = 1
kAudioUnitParameterUnit_Boolean = 2
kAudioUnitParameterUnit_Percent = 3
kAudioUnitParameterUnit_Seconds = 4
kAudioUnitParameterUnit_SampleFrames = 5
kAudioUnitParameterUnit_Phase = 6
kAudioUnitParameterUnit_Rate = 7
kAudioUnitParameterUnit_Hertz = 8
kAudioUnitParameterUnit_Cents = 9
kAudioUnitParameterUnit_RelativeSemiTones = 10
kAudioUnitParameterUnit_MIDINoteNumber = 11
kAudioUnitParameterUnit_MIDIController = 12
kAudioUnitParameterUnit_Decibels = 13
kAudioUnitParameterUnit_LinearGain = 14
kAudioUnitParameterUnit_Degrees = 15
kAudioUnitParameterUnit_EqualPowerCrossfade = 16
kAudioUnitParameterUnit_MixerFaderCurve1 = 17
kAudioUnitParameterUnit_Pan = 18
kAudioUnitParameterUnit_Meters = 19
kAudioUnitParameterUnit_AbsoluteCents = 20
kAudioUnitParameterUnit_Octaves = 21
kAudioUnitParameterUnit_BPM = 22
kAudioUnitParameterUnit_Beats = 23
kAudioUnitParameterUnit_Milliseconds = 24
kAudioUnitParameterUnit_Ratio = 25
*/
/* info.flags to consider */
/*
kAudioUnitParameterFlag_CFNameRelease = (1L << 4)
kAudioUnitParameterFlag_HasClump = (1L << 20)
kAudioUnitParameterFlag_HasName = (1L << 21)
kAudioUnitParameterFlag_DisplayLogarithmic = (1L << 22)
kAudioUnitParameterFlag_IsHighResolution = (1L << 23)
kAudioUnitParameterFlag_NonRealTime = (1L << 24)
kAudioUnitParameterFlag_CanRamp = (1L << 25)
kAudioUnitParameterFlag_ExpertMode = (1L << 26)
kAudioUnitParameterFlag_HasCFNameString = (1L << 27)
kAudioUnitParameterFlag_IsGlobalMeta = (1L << 28)
kAudioUnitParameterFlag_IsElementMeta = (1L << 29)
kAudioUnitParameterFlag_IsReadable = (1L << 30)
kAudioUnitParameterFlag_IsWritable = (1L << 31)
*/
d.lower = info.minValue;
d.upper = info.maxValue;
d.default_value = info.defaultValue;
d.integer_step = (info.unit & kAudioUnitParameterUnit_Indexed);
d.toggled = (info.unit & kAudioUnitParameterUnit_Boolean) ||
(d.integer_step && ((d.upper - d.lower) == 1.0));
d.sr_dependent = (info.unit & kAudioUnitParameterUnit_SampleFrames);
d.automatable = !d.toggled &&
!(info.flags & kAudioUnitParameterFlag_NonRealTime) &&
(info.flags & kAudioUnitParameterFlag_IsWritable);
d.logarithmic = (info.flags & kAudioUnitParameterFlag_DisplayLogarithmic);
d.unit = info.unit;
d.step = 1.0;
d.smallstep = 0.1;
d.largestep = 10.0;
d.min_unbound = 0; // lower is bound
d.max_unbound = 0; // upper is bound
descriptors.push_back (d);
}
}
}
string
AUPlugin::unique_id () const
{
@ -134,13 +258,16 @@ AUPlugin::label () const
uint32_t
AUPlugin::parameter_count () const
{
return 0;
return descriptors.size();
}
float
AUPlugin::default_value (uint32_t port)
{
// AudioUnits don't have default values. Maybe presets though?
if (port < descriptors.size()) {
return descriptors[port].default_value;
}
return 0;
}
@ -157,28 +284,41 @@ AUPlugin::signal_latency () const
void
AUPlugin::set_parameter (uint32_t which, float val)
{
// unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val);
if (which < descriptors.size()) {
const AUParameterDescriptor& d (descriptors[which]);
unit->SetParameter (d.id, d.scope, d.element, val);
}
}
float
AUPlugin::get_parameter (uint32_t which) const
{
float outValue = 0.0;
// unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue);
return outValue;
float val = 0.0;
if (which < descriptors.size()) {
const AUParameterDescriptor& d (descriptors[which]);
unit->GetParameter(d.id, d.scope, d.element, val);
}
return val;
}
int
AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const
AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& pd) const
{
return 0;
if (which < descriptors.size()) {
pd = descriptors[which];
return 0;
}
return -1;
}
uint32_t
AUPlugin::nth_parameter (uint32_t which, bool& ok) const
{
if (which < descriptors.size()) {
ok = true;
return which;
}
ok = false;
return 0;
}
@ -397,20 +537,26 @@ set<uint32_t>
AUPlugin::automatable() const
{
set<uint32_t> automates;
for (uint32_t i = 0; i < descriptors.size(); ++i) {
if (descriptors[i].automatable) {
automates.insert (i);
}
}
return automates;
}
string
AUPlugin::describe_parameter (uint32_t)
AUPlugin::describe_parameter (uint32_t param)
{
return "";
return descriptors[param].label;
}
void
AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const
AUPlugin::print_parameter (uint32_t param, char* buf, uint32_t len) const
{
// NameValue stuff here
}
bool
@ -422,7 +568,7 @@ AUPlugin::parameter_is_audio (uint32_t) const
bool
AUPlugin::parameter_is_control (uint32_t) const
{
return false;
return true;
}
bool

View File

@ -126,6 +126,8 @@ AudioEngine::start ()
if (session) {
nframes_t blocksize = jack_get_buffer_size (_jack);
BootMessage (_("Connect session to engine"));
session->set_block_size (blocksize);
session->set_frame_rate (jack_get_sample_rate (_jack));

View File

@ -677,20 +677,18 @@ bool
AudioFileSource::safe_file_extension(ustring file)
{
return !(file.rfind(".wav") == ustring::npos &&
file.rfind(".aiff")== ustring::npos &&
file.rfind(".aif") == ustring::npos &&
file.rfind(".snd") == ustring::npos &&
file.rfind(".au") == ustring::npos &&
file.rfind(".raw") == ustring::npos &&
file.rfind(".sf") == ustring::npos &&
file.rfind(".cdr") == ustring::npos &&
file.rfind(".smp") == ustring::npos &&
file.rfind(".maud")== ustring::npos &&
file.rfind(".vwe") == ustring::npos &&
file.rfind(".paf") == ustring::npos &&
/* protools convention */
file.rfind(".L") == ustring::npos &&
file.rfind(".R") == ustring::npos &&
file.rfind(".aiff")== ustring::npos &&
file.rfind(".aif") == ustring::npos &&
file.rfind(".amb") == ustring::npos &&
file.rfind(".snd") == ustring::npos &&
file.rfind(".au") == ustring::npos &&
file.rfind(".raw") == ustring::npos &&
file.rfind(".sf") == ustring::npos &&
file.rfind(".cdr") == ustring::npos &&
file.rfind(".smp") == ustring::npos &&
file.rfind(".maud")== ustring::npos &&
file.rfind(".vwe") == ustring::npos &&
file.rfind(".paf") == ustring::npos &&
#ifdef HAVE_FLAC
file.rfind(".flac")== ustring::npos &&
#endif // HAVE_FLAC

View File

@ -1316,6 +1316,8 @@ AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
return 0;
}
cerr << "startup analysis of " << _name << endl;
TransientDetector t (pl->session().frame_rate());
bool existing_results = !results.empty();
@ -1328,10 +1330,14 @@ AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
t.reset ();
cerr << "working on channel " << i << endl;
if (t.run ("", this, i, these_results)) {
return -1;
}
cerr << "done\n";
/* translate all transients to give absolute position */
for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
@ -1357,6 +1363,11 @@ AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
/* make sure ours are clean too */
TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
} else {
TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
results = _transients;
}
_valid_transients = true;

View File

@ -70,6 +70,7 @@ AudioSource::AudioSource (Session& s, ustring name)
AudioSource::AudioSource (Session& s, const XMLNode& node)
: Source (s, node)
{
_peaks_built = false;
_peak_byte_max = 0;
peakfile = -1;
@ -213,7 +214,7 @@ AudioSource::initialize_peakfile (bool newfile, ustring audio_path)
/* we found it in the peaks dir, so check it out */
if (statbuf.st_size == 0) {
if (statbuf.st_size == 0 || (statbuf.st_size < ((length() / _FPP) * sizeof (PeakData)))) {
// empty
_peaks_built = false;
} else {
@ -221,12 +222,22 @@ AudioSource::initialize_peakfile (bool newfile, ustring audio_path)
struct stat stat_file;
int err = stat (audio_path.c_str(), &stat_file);
if (!err && stat_file.st_mtime > statbuf.st_mtime){
if (err) {
_peaks_built = false;
_peak_byte_max = 0;
} else {
_peaks_built = true;
_peak_byte_max = statbuf.st_size;
/* allow 6 seconds slop on checking peak vs. file times because of various
disk action "races"
*/
if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
_peaks_built = false;
_peak_byte_max = 0;
} else {
_peaks_built = true;
_peak_byte_max = statbuf.st_size;
}
}
}
}

View File

@ -422,9 +422,9 @@ Automatable::protect_automation ()
}
void
Automatable::automation_snapshot (nframes_t now)
Automatable::automation_snapshot (nframes_t now, bool force)
{
if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
if (force || _last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) {
if (i->second->list()->automation_write()) {

View File

@ -28,6 +28,7 @@
#include <ardour/filter.h>
#include <ardour/region_factory.h>
#include <ardour/source_factory.h>
#include <ardour/analyser.h>
#include "i18n.h"
@ -101,6 +102,10 @@ Filter::finish (boost::shared_ptr<Region> region, SourceList& nsrcs, string regi
smfs->set_timeline_position (region->position());
smfs->flush_footer ();
}
/* now that there is data there, requeue the file for analysis */
Analyser::queue_source_for_analysis (*si, false);
}
/* create a new region */

View File

@ -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));

View File

@ -46,6 +46,7 @@
#include <ardour/region_factory.h>
#include <ardour/source_factory.h>
#include <ardour/resampled_source.h>
#include <ardour/analyser.h>
#include "i18n.h"
@ -65,7 +66,7 @@ open_importable_source (const string& path, nframes_t samplerate, ARDOUR::SrcQua
}
static std::string
get_non_existent_filename (const std::string& basename, uint channel, uint channels)
get_non_existent_filename (const bool allow_replacing, const std::string destdir, const std::string& basename, uint channel, uint channels)
{
char buf[PATH_MAX+1];
bool goodfile = false;
@ -84,7 +85,9 @@ get_non_existent_filename (const std::string& basename, uint channel, uint chann
snprintf (buf, sizeof(buf), "%s.wav", base.c_str());
}
if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
string tempname = destdir + "/" + buf;
if (!allow_replacing && Glib::file_test (tempname, Glib::FILE_TEST_EXISTS)) {
/* if the file already exists, we must come up with
* a new name for it. for now we just keep appending
@ -104,7 +107,7 @@ get_non_existent_filename (const std::string& basename, uint channel, uint chann
}
static vector<string>
get_paths_for_new_sources (const string& import_file_path, const string& session_dir, uint channels)
get_paths_for_new_sources (const bool allow_replacing, const string& import_file_path, const string& session_dir, uint channels)
{
vector<string> new_paths;
const string basename = basename_nosuffix (import_file_path);
@ -115,7 +118,7 @@ get_paths_for_new_sources (const string& import_file_path, const string& session
filepath = session_dir;
filepath += '/';
filepath += get_non_existent_filename (basename, n, channels);
filepath += get_non_existent_filename (allow_replacing, session_dir, basename, n, channels);
new_paths.push_back (filepath);
}
@ -123,6 +126,25 @@ get_paths_for_new_sources (const string& import_file_path, const string& session
return new_paths;
}
static bool
map_existing_mono_sources (const vector<string>& new_paths, Session& sess,
uint samplerate, vector<boost::shared_ptr<AudioFileSource> >& newfiles, Session *session)
{
for (vector<string>::const_iterator i = new_paths.begin();
i != new_paths.end(); ++i)
{
boost::shared_ptr<Source> source = session->source_by_path_and_channel(*i, 0);
if (source == 0) {
error << string_compose(_("Could not find a source for %1 even though we are updating this file!"), (*i)) << endl;
return false;
}
newfiles.push_back(boost::dynamic_pointer_cast<AudioFileSource>(source));
}
return true;
}
static bool
create_mono_sources_for_writing (const vector<string>& new_paths, Session& sess,
uint samplerate, vector<boost::shared_ptr<AudioFileSource> >& newfiles)
@ -228,6 +250,10 @@ remove_file_source (boost::shared_ptr<AudioFileSource> file_source)
::unlink (file_source->path().c_str());
}
// This function is still unable to cleanly update an existing source, even though
// it is possible to set the import_status flag accordingly. The functinality
// is disabled at the GUI until the Source implementations are able to provide
// the necessary API.
void
Session::import_audiofiles (import_status& status)
{
@ -254,13 +280,19 @@ Session::import_audiofiles (import_status& status)
return;
}
vector<string> new_paths = get_paths_for_new_sources (*p,
vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source,
*p,
get_best_session_directory_for_new_source (),
source->channels());
AudioSources newfiles;
status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles);
if (status.replace_existing_source) {
fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endl;
status.cancel = !map_existing_mono_sources (new_paths, *this, frame_rate(), newfiles, this);
} else {
status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles);
}
// copy on cancel/failure so that any files that were created will be removed below
std::copy (newfiles.begin(), newfiles.end(), std::back_inserter(all_new_sources));
@ -286,11 +318,14 @@ Session::import_audiofiles (import_status& status)
/* flush the final length(s) to the header(s) */
for (AudioSources::iterator x = all_new_sources.begin();
x != all_new_sources.end(); ++x)
for (AudioSources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ++x)
{
(*x)->update_header(0, *now, xnow);
(*x)->done_with_peakfile_writes ();
/* now that there is data there, requeue the file for analysis */
Analyser::queue_source_for_analysis (boost::static_pointer_cast<Source>(*x), false);
}
/* save state so that we don't lose these new Sources */

View File

@ -32,6 +32,7 @@
#include <ardour/audioengine.h>
#include <ardour/io.h>
#include <ardour/route.h>
#include <ardour/port.h>
#include <ardour/audio_port.h>
#include <ardour/midi_port.h>
@ -1800,14 +1801,22 @@ IO::parse_gain_string (const string& str, vector<string>& ports)
}
bool
IO::set_name (const string& str)
IO::set_name (const string& requested_name)
{
if (str == _name) {
if (requested_name == _name) {
return true;
}
string name;
Route *rt;
if ( (rt = dynamic_cast<Route *>(this))) {
name = Route::ensure_track_or_route_name(requested_name, _session);
} else {
name = requested_name;
}
/* replace all colons in the name. i wish we didn't have to do this */
string name = str;
if (replace_all (name, ":", "-")) {
warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
@ -2224,13 +2233,16 @@ IO::end_pan_touch (uint32_t which)
}
void
IO::automation_snapshot (nframes_t now)
IO::automation_snapshot (nframes_t now, bool force)
{
Automatable::automation_snapshot (now);
Automatable::automation_snapshot (now, force);
if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
_panner->snapshot (now);
}
_panner->snapshot (now);
_last_automation_snapshot = now;
}
void

View File

@ -1814,50 +1814,12 @@ Playlist::bump_name (string name, Session &session)
string newname = name;
do {
newname = Playlist::bump_name_once (newname);
newname = bump_name_once (newname);
} while (session.playlist_by_name (newname)!=NULL);
return newname;
}
string
Playlist::bump_name_once (string name)
{
string::size_type period;
string newname;
if ((period = name.find_last_of ('.')) == string::npos) {
newname = name;
newname += ".1";
} else {
int isnumber = 1;
const char *last_element = name.c_str() + period + 1;
for (size_t i = 0; i < strlen(last_element); i++) {
if (!isdigit(last_element[i])) {
isnumber = 0;
break;
}
}
errno = 0;
long int version = strtol (name.c_str()+period+1, (char **)NULL, 10);
if (isnumber == 0 || errno != 0) {
// last_element is not a number, or is too large
newname = name;
newname += ".1";
} else {
char buf[32];
snprintf (buf, sizeof(buf), "%ld", version+1);
newname = name.substr (0, period+1);
newname += buf;
}
}
return newname;
}
layer_t
Playlist::top_layer() const

View File

@ -224,6 +224,19 @@ ARDOUR::find_plugin(Session& session, string identifier, PluginType type)
return (*i)->load (session);
}
}
#ifdef VST_SUPPORT
/* hmm, we didn't find it. could be because in older versions of Ardour.
we used to store the name of a VST plugin, not its unique ID. so try
again.
*/
for (i = plugs.begin(); i != plugs.end(); ++i) {
if (identifier == (*i)->name){
return (*i)->load (session);
}
}
#endif
return PluginPtr ((Plugin*) 0);
}

View File

@ -957,15 +957,15 @@ 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) {
pos -= offset;
}
} else {
if (pos > offset) {
pos += offset;
pos -= offset;
} else {
pos = 0;
}
} else {
if (max_frames - pos > offset) {
pos += offset;
}
}
return pos;

View File

@ -46,6 +46,9 @@
#include <ardour/amp.h>
#include <ardour/meter.h>
#include <ardour/buffer_set.h>
#include <ardour/mix.h>
#include <ardour/profile.h>
#include "i18n.h"
using namespace std;
@ -190,6 +193,20 @@ Route::sync_order_keys ()
}
}
string
Route::ensure_track_or_route_name(string name, Session &session)
{
string newname = name;
while (session.route_by_name (newname)!=NULL)
{
newname = bump_name_once (newname);
}
return newname;
}
void
Route::inc_gain (gain_t fraction, void *src)
{
@ -843,8 +860,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
reset_panner ();
}
processors_changed (); /* EMIT SIGNAL */
return 0;
}
@ -2291,7 +2308,7 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
Glib::RWLock::ReaderLock lm (_processor_lock);
if (!did_locate) {
automation_snapshot (now);
automation_snapshot (now, true);
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@ -2398,7 +2415,7 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nfra
if (lm.locked()) {
// automation snapshot can also be called from the non-rt context
// and it uses the processor list, so we take the lock out here
automation_snapshot (_session.transport_frame());
automation_snapshot (_session.transport_frame(), false);
}
}
@ -2569,12 +2586,15 @@ Route::set_latency_delay (nframes_t longest_session_latency)
}
void
Route::automation_snapshot (nframes_t now)
Route::automation_snapshot (nframes_t now, bool force)
{
IO::automation_snapshot (now);
if (!force && !should_snapshot(now)) {
return;
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->automation_snapshot (now);
// IO::automation_snapshot (now, force); ?
(*i)->automation_snapshot (now, force);
}
}

View File

@ -504,9 +504,13 @@ Session::when_engine_running ()
/* we don't want to run execute this again */
BootMessage (_("Set block size and sample rate"));
set_block_size (_engine.frames_per_cycle());
set_frame_rate (_engine.frame_rate());
BootMessage (_("Using configuration"));
Config->map_parameters (mem_fun (*this, &Session::config_changed));
/* every time we reconnect, recompute worst case output latencies */
@ -562,6 +566,8 @@ Session::when_engine_running ()
error << _("cannot setup Click I/O") << endmsg;
}
BootMessage (_("Compute I/O Latencies"));
set_worst_io_latencies ();
if (_clicking) {
@ -572,6 +578,8 @@ Session::when_engine_running ()
to the physical outputs currently available
*/
BootMessage (_("Set up standard connections"));
/* ONE: MONO */
for (uint32_t np = 0; np < n_physical_outputs; ++np) {
@ -672,11 +680,15 @@ Session::when_engine_running ()
}
add_bundle (c);
}
BootMessage (_("Connect ports"));
hookup_io ();
/* catch up on send+insert cnts */
BootMessage (_("Catch up with send/insert state"));
insert_cnt = 0;
for (list<PortInsert*>::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) {
@ -704,14 +716,17 @@ Session::when_engine_running ()
_state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
/* hook us up to the engine */
BootMessage (_("Connect to engine"));
_engine.set_session (this);
#ifdef HAVE_LIBLO
/* and to OSC */
BootMessage (_("OSC startup"));
osc->set_session (*this);
#endif
@ -2545,42 +2560,55 @@ Session::region_name (string& result, string base, bool newlevel) const
void
Session::add_region (boost::shared_ptr<Region> region)
{
vector<boost::shared_ptr<Region> > v;
v.push_back (region);
add_regions (v);
}
void
Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
{
bool added = false;
{
Glib::Mutex::Lock lm (region_lock);
if (region == 0) {
error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
} else {
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) {
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;
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 (region->playlist()) {
region->playlist()->destroy_region (region);
}
if (aregion->playlist()) {
aregion->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;

View File

@ -350,11 +350,15 @@ Session::second_stage_init (bool new_session)
return -1;
}
BootMessage (_("Reset Remote Controls"));
//send_full_time_code ();
_engine.transport_locate (0);
deliver_mmc (MIDI::MachineControl::cmdMmcReset, 0);
deliver_mmc (MIDI::MachineControl::cmdLocate, 0);
BootMessage (_("Reset Control Protocols"));
ControlProtocolManager::instance().set_session (*this);
if (new_session) {
@ -364,7 +368,6 @@ Session::second_stage_init (bool new_session)
}
_state_of_the_state = Clean;
DirtyChanged (); /* EMIT SIGNAL */
@ -374,6 +377,8 @@ Session::second_stage_init (bool new_session)
state_was_pending = false;
}
BootMessage (_("Session loading complete"));
return 0;
}
@ -1373,6 +1378,8 @@ Session::load_routes (const XMLNode& node)
return -1;
}
BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
new_routes.push_back (route);
}

View File

@ -1267,9 +1267,9 @@ Session::engine_halted ()
void
Session::xrun_recovery ()
{
if (Config->get_stop_recording_on_xrun() && actively_recording()) {
Xrun (transport_frame()); //EMIT SIGNAL
HaltOnXrun (); /* EMIT SIGNAL */
if (Config->get_stop_recording_on_xrun() && actively_recording()) {
/* it didn't actually halt, but we need
to handle things in the same way.

View File

@ -195,6 +195,7 @@ Source::set_been_analysed (bool yn)
}
if (yn) {
load_transients (get_transients_path());
AnalysisChanged(); // EMIT SIGNAL
}
}
@ -265,3 +266,4 @@ Source::check_for_analysis_data_on_disk ()
set_been_analysed (ok);
return ok;
}

View File

@ -6,18 +6,20 @@ using namespace Vamp;
using namespace ARDOUR;
using namespace std;
string TransientDetector::_op_id;
/* need a static initializer function for this */
string TransientDetector::_op_id = X_("libardourvampplugins:percussiononsets:2");
TransientDetector::TransientDetector (float sr)
: AudioAnalyser (sr, X_("libardourvampplugins:percussiononsets"))
{
if (_op_id.empty()) {
_op_id = X_("libardourvampplugins:percussiononsets");
/* update the op_id */
// XXX this should load the above-named plugin and get the current version
_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()

View File

@ -86,6 +86,45 @@ legalize_for_path (string str)
}
#endif
string bump_name_once(std::string name)
{
string::size_type period;
string newname;
if ((period = name.find_last_of ('.')) == string::npos) {
newname = name;
newname += ".1";
} else {
int isnumber = 1;
const char *last_element = name.c_str() + period + 1;
for (size_t i = 0; i < strlen(last_element); i++) {
if (!isdigit(last_element[i])) {
isnumber = 0;
break;
}
}
errno = 0;
long int version = strtol (name.c_str()+period+1, (char **)NULL, 10);
if (isnumber == 0 || errno != 0) {
// last_element is not a number, or is too large
newname = name;
newname += ".1";
} else {
char buf[32];
snprintf (buf, sizeof(buf), "%ld", version+1);
newname = name.substr (0, period+1);
newname += buf;
}
}
return newname;
}
ostream&
operator<< (ostream& o, const BBT_Time& bbt)
{
@ -289,6 +328,8 @@ string_to_edit_mode (string str)
return Splice;
} else if (str == _("Slide Edit")) {
return Slide;
} else if (str == _("Lock Edit")) {
return Lock;
}
fatal << string_compose (_("programming error: unknown edit mode string \"%1\""), str) << endmsg;
/*NOTREACHED*/
@ -302,6 +343,9 @@ edit_mode_to_string (EditMode mode)
case Slide:
return _("Slide Edit");
case Lock:
return _("Lock Edit");
default:
case Splice:
return _("Splice Edit");

View File

@ -10,6 +10,9 @@ Import('env libraries install_prefix')
pangomm = env.Copy()
pangomm.Merge([libraries['glibmm2'], libraries['pango'], libraries['sigc2'], libraries['cairomm'], libraries['cairo']])
if pangomm['IS_OSX']:
pangomm.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
libpangomm = pangomm.SharedLibrary('pangomm', pangomm_files)
Default(libpangomm)

View File

@ -32,6 +32,8 @@ gtkmm2ext.Append(CXXFLAGS=["-DLIBSIGC_DISABLE_DEPRECATED", "-DGLIBMM_DEFAULT_SIG
gtkmm2ext.Append(PACKAGE=domain)
gtkmm2ext.Append(POTFILE=domain + '.pot')
extra_sources = []
gtkmm2ext_files = Split("""
auto_spin.cc
barcontroller.cc
@ -61,12 +63,21 @@ version.cc
window_title.cc
""")
gtkosx_files=Split("""
sync-menu.c
""")
if gtkmm2ext['GTKOSX']:
extra_sources += gtkosx_files
gtkmm2ext.Append (CCFLAGS="-DTOP_MENUBAR -DGTKOSX")
gtkmm2ext.Append (LINKFLAGS="-framework Carbon")
gtkmm2ext.VersionBuild(['version.cc','gtkmm2ext/version.h'], [])
gtkmm2ext.Append(CCFLAGS="-D_REENTRANT")
gtkmm2ext.Append(CCFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
libgtkmm2ext = gtkmm2ext.SharedLibrary('gtkmm2ext', gtkmm2ext_files)
libgtkmm2ext = gtkmm2ext.SharedLibrary('gtkmm2ext', gtkmm2ext_files + extra_sources)
Default(libgtkmm2ext)
@ -78,5 +89,6 @@ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ar
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'i18n.h', 'gettext.h'] +
gtkmm2ext_files +
gtkosx_files +
glob.glob('po/*.po') +
glob.glob('gtkmm2ext/*.h')))

View File

@ -560,10 +560,31 @@ UI::popup_error (const char *text)
pup->touch ();
}
#ifdef GTKOSX
extern "C" {
int gdk_quartz_in_carbon_menu_event_handler ();
}
#endif
void
UI::flush_pending ()
{
#ifdef GTKOSX
/* as of february 11th 2008, gtk/osx has a problem in that mac menu events
are handled using Carbon with an "internal" event handling system that
doesn't pass things back to the glib/gtk main loop. this makes
gtk_main_iteration() block if we call it while in a menu event handler
because glib gets confused and thinks there are two threads running
g_main_poll_func().
this hack (relies on code in gtk2_ardour/sync-menu.c) works
around that.
*/
if (gdk_quartz_in_carbon_menu_event_handler()) {
return;
}
#endif
if (!caller_is_ui_thread()) {
error << "non-UI threads cannot call UI::flush_pending()"
<< endmsg;

View File

@ -30,7 +30,7 @@ namespace Gtkmm2ext {
class PixFader : public Gtk::DrawingArea {
public:
PixFader (Glib::RefPtr<Gdk::Pixbuf> belt_image, Gtk::Adjustment& adjustment);
PixFader (Glib::RefPtr<Gdk::Pixbuf> belt_image, Gtk::Adjustment& adjustment, int orientation);
virtual ~PixFader ();
protected:
@ -44,23 +44,32 @@ class PixFader : public Gtk::DrawingArea {
bool on_motion_notify_event (GdkEventMotion*);
bool on_scroll_event (GdkEventScroll* ev);
private:
enum Orientation {
VERT=1,
HORIZ=2,
};
private:
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
gint pixheight;
int span, girth;
int _orien;
GdkRectangle view;
GdkWindow* grab_window;
double grab_y;
double grab_loc;
double grab_start;
int last_drawn;
bool dragging;
float default_value;
int unity_y;
int unity_loc;
void adjustment_changed ();
int display_height ();
int display_span ();
static int fine_scale_modifier;
static int extra_fine_scale_modifier;
};

View File

@ -38,7 +38,7 @@ class SliderController : public Gtkmm2ext::PixFader
{
public:
SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment* adj,
Gtk::Adjustment* adj, int orientation,
PBD::Controllable&,
bool with_numeric = true);

View File

@ -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__ */

View File

@ -27,21 +27,36 @@ using namespace Gtk;
using namespace Gdk;
using namespace std;
PixFader::PixFader (Glib::RefPtr<Pixbuf> belt, Gtk::Adjustment& adj)
#ifdef GTKOSX
int PixFader::fine_scale_modifier = GDK_META_MASK;
#else
int PixFader::fine_scale_modifier = GDK_CONTROL_MASK;
#endif
int PixFader::extra_fine_scale_modifier = GDK_MOD1_MASK;
PixFader::PixFader (Glib::RefPtr<Pixbuf> belt, Gtk::Adjustment& adj, int orientation)
: adjustment (adj),
pixbuf (belt)
pixbuf (belt),
_orien(orientation)
{
dragging = false;
default_value = adjustment.get_value();
last_drawn = -1;
pixheight = pixbuf->get_height();
view.x = 0;
view.y = 0;
view.width = pixbuf->get_width();
view.height = pixheight / 2;
unity_y = (int) rint (view.height - (default_value * view.height)) - 1;
if (orientation == VERT) {
view.width = girth = pixbuf->get_width();
view.height = span = pixbuf->get_height() / 2;
unity_loc = (int) rint (view.height - (default_value * view.height)) - 1;
} else {
view.width = span = pixbuf->get_width () / 2;
view.height = girth = pixbuf->get_height();
unity_loc = (int) rint (default_value * view.width) - 1;
}
add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
@ -57,13 +72,20 @@ bool
PixFader::on_expose_event (GdkEventExpose* ev)
{
GdkRectangle intersection;
int dh = display_height ();
int offset_into_pixbuf = (int) floor (view.height / ((float) view.height / dh));
int srcx, srcy, ds = display_span ();
int offset_into_pixbuf = (int) floor (span / ((float) span / ds));
Glib::RefPtr<Gdk::GC> fg_gc (get_style()->get_fg_gc(get_state()));
if (gdk_rectangle_intersect (&view, &ev->area, &intersection)) {
if (_orien == VERT) {
srcx = intersection.x;
srcy = offset_into_pixbuf + intersection.y;
} else {
srcx = offset_into_pixbuf + intersection.x;
srcy = intersection.y;
}
get_window()->draw_pixbuf (fg_gc, pixbuf,
intersection.x, offset_into_pixbuf + intersection.y,
srcx, srcy,
intersection.x, intersection.y,
intersection.width, intersection.height,
Gdk::RGB_DITHER_NONE, 0, 0);
@ -75,10 +97,12 @@ PixFader::on_expose_event (GdkEventExpose* ev)
}
/* always draw the line */
get_window()->draw_line (fg_gc, 1, unity_y, view.width - 2, unity_y);
last_drawn = dh;
if (_orien == VERT) {
get_window()->draw_line (fg_gc, 1, unity_loc, girth - 2, unity_loc);
} else {
get_window()->draw_line (fg_gc, unity_loc, 1, unity_loc, girth - 2);
}
last_drawn = ds;
return true;
}
@ -96,8 +120,8 @@ PixFader::on_button_press_event (GdkEventButton* ev)
case 1:
case 2:
add_modal_grab();
grab_y = ev->y;
grab_start = ev->y;
grab_loc = (_orien == VERT) ? ev->y : ev->x;
grab_start = (_orien == VERT) ? ev->y : ev->x;
grab_window = ev->window;
dragging = true;
break;
@ -112,7 +136,9 @@ PixFader::on_button_press_event (GdkEventButton* ev)
bool
PixFader::on_button_release_event (GdkEventButton* ev)
{
double fract;
double fract, ev_pos;
ev_pos = (_orien == VERT) ? ev->y : 0; // Don't step if we are horizontal
switch (ev->button) {
case 1:
@ -120,15 +146,15 @@ PixFader::on_button_release_event (GdkEventButton* ev)
remove_modal_grab();
dragging = false;
if (ev->y == grab_start) {
if (ev_pos == grab_start) {
/* no motion - just a click */
if (ev->state & Gdk::SHIFT_MASK) {
adjustment.set_value (default_value);
} else if (ev->state & GDK_CONTROL_MASK) {
} else if (ev->state & fine_scale_modifier) {
adjustment.set_value (adjustment.get_lower());
} else if (ev->y < view.height - display_height()) {
} else if (ev_pos < span - display_span()) {
/* above the current display height, remember X Window coords */
adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment());
} else {
@ -144,7 +170,7 @@ PixFader::on_button_release_event (GdkEventButton* ev)
remove_modal_grab();
dragging = false;
fract = 1.0 - (ev->y / view.height); // inverted X Window coordinates, grrr
fract = 1.0 - (ev_pos / span); // inverted X Window coordinates, grrr
fract = min (1.0, fract);
fract = max (0.0, fract);
@ -164,29 +190,45 @@ bool
PixFader::on_scroll_event (GdkEventScroll* ev)
{
double scale;
if (ev->state & GDK_CONTROL_MASK) {
if (ev->state & GDK_MOD1_MASK) {
scale = 0.05;
if (ev->state & fine_scale_modifier) {
if (ev->state & extra_fine_scale_modifier) {
scale = 0.01;
} else {
scale = 0.1;
scale = 0.05;
}
} else {
scale = 0.5;
scale = 0.25;
}
switch (ev->direction) {
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;
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);
}

View File

@ -29,11 +29,11 @@ using namespace Gtkmm2ext;
using namespace PBD;
SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
Gtk::Adjustment *adj, int orientation,
Controllable& c,
bool with_numeric)
: PixFader (image, *adj),
: PixFader (image, *adj, orientation),
binding_proxy (c),
spin (*adj, 0, 2)
{
@ -63,7 +63,7 @@ VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Controllable& control,
bool with_numeric)
: SliderController (image, adj, control, with_numeric)
: SliderController (image, adj, VERT, control, with_numeric)
{
if (with_numeric) {
spin_frame.add (spin);
@ -79,7 +79,7 @@ HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Controllable& control,
bool with_numeric)
: SliderController (image, adj, control, with_numeric)
: SliderController (image, adj, HORIZ, control, with_numeric)
{
if (with_numeric) {
spin_frame.add (spin);

977
libs/gtkmm2ext/sync-menu.c Normal file
View File

@ -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);
}

View File

@ -8,7 +8,7 @@ void
disable_screen_updates ()
{
#ifdef GTKOSX
NSDisableScreenUpdates ();
// NSDisableScreenUpdates ();
#endif
}
@ -16,6 +16,6 @@ void
enable_screen_updates ()
{
#ifdef GTKOSX
NSEnableScreenUpdates();
// NSEnableScreenUpdates();
#endif
}

View File

@ -21,6 +21,6 @@ Default(libvampplugins)
env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'vamp'), libvampplugins))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'COPYING', 'README' ] +
[ 'SConscript' ] +
plugin_files +
glob.glob('*.h')))

View File

@ -1,4 +1,4 @@
#ifndef __ardour_svn_revision_h__
#define __ardour_svn_revision_h__
static const char* ardour_svn_revision = "2985";
static const char* ardour_svn_revision = "3046";
#endif

View File

@ -53,6 +53,10 @@ if not File.exist?(libdir+"/surfaces") then
Dir.mkdir(libdir + "/surfaces")
end
if not File.exist?(libdir+"/vamp-plugins") then
Dir.mkdir(libdir + "/vamp-plugins")
end
odir = Dir.getwd
Dir.chdir("../..")
@ -67,6 +71,9 @@ results = results + result.split("\n").slice(1,result.size-1)
result = `otool -L libs/surfaces/*/*.dylib`
results = results + result.split("\n").slice(1,result.size-1)
result = `otool -L libs/vamp-plugins/*.dylib`
results = results + result.split("\n").slice(1,result.size-1)
results.uniq!
$stdout.print("Copying libs to #{libdir} ...\n");
@ -117,6 +124,9 @@ begin
rescue
end
# vamp plugins
`cp ../../libs/vamp-plugins/*.dylib #{libdir}/vamp-plugins`
# copy gtk and pango lib stuff
`cp -R /opt/local/lib/pango #{libdir}/`

View File

@ -24,10 +24,13 @@ export ARDOUR_MODULE_PATH="$TOP/lib/"
export ARDOUR_DATA_PATH="$TOP/share"
export ARDOUR_GLADE_PATH="$TOP/share/ardour2/glade"
export LADSPA_RDF_PATH="$HOME/Library/Audio/Plug-Ins/LADSPA/rdf:/Library/Audio/Plug-Ins/LADSPA/rdf:$TOP/s
hare/ladspa/rdf:/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf"
export LADSPA_PATH="$HOME/Library/Audio/Plug-Ins/LADSPA:/Library/Audio/Plug-Ins/LADSPA:/usr/local/lib/lad
spa:/usr/lib/ladspa"
export ARDOUR_PATH="$TOP/share/ardour/icons:$TOP/share/ardour/pixmaps"
export LADSPA_RDF_PATH="$HOME/Library/Audio/Plug-Ins/LADSPA/rdf:/Library/Audio/Plug-Ins/LADSPA/rdf:$TOP/share/ladspa/rdf:/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf"
export LADSPA_PATH="$HOME/Library/Audio/Plug-Ins/LADSPA:/Library/Audio/Plug-Ins/LADSPA:/usr/local/lib/ladspa:/usr/lib/ladspa"
export VAMP_PATH="$TOP/lib/vamp-plugins"
mkdir -p "$ETC"
sed 's|${HOME}|'"$HOME|g" "$TOP/etc/pango/pangorc" > "$ETC/pangorc"

View File

@ -68,7 +68,7 @@ wine_executable = ardour_vst.SubstInFile ('ardourvst', 'ardourvst.in', SUBST_DIC
if ardour_vst['VST']:
ardour_vst.AddPostAction (wine_executable, ardour_vst.Action (Chmod ('vst/ardevst', 0755)))
ardour_vst.AddPostAction (wine_executable, ardour_vst.Action (Chmod (wine_executable, 0755)))
ardour_vst.AddPostAction (wine_executable, ardour_vst.Action (Chmod ("vst/" + str(wine_executable[0]), 0755)))
Default([wine_generated_executable, wine_executable])
# the wine script - into the bin dir