From f9f5ec85fbfd15d0008f70d4185a84eeadfd3891 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 28 Jan 2007 17:44:13 +0000 Subject: Merged with trunk R1393. git-svn-id: svn://localhost/ardour2/branches/midi@1395 d708f5d6-7413-0410-9779-e7cbd77b26cf --- tools/ARDOUR/SourceInfoLoader.pm | 75 ++ .../English.lproj/InfoPlist.strings | Bin 0 -> 482 bytes .../English.lproj/schema.strings | Bin 0 -> 1276 bytes tools/Spotlight Importer/GetMetadataForFile.c | 56 ++ tools/Spotlight Importer/Info.plist | 87 +++ .../Spotlight Importer.xcodeproj/project.pbxproj | 275 +++++++ tools/Spotlight Importer/main.c | 225 ++++++ tools/Spotlight Importer/schema.xml | 29 + tools/osx_packaging/app_build.rb | 10 +- tools/osx_packaging/ardour2_mac_ui.rc | 93 ++- tools/session_exchange.py | 856 +++++++++++++++++++++ tools/synthesize_sources.pl | 75 ++ 12 files changed, 1741 insertions(+), 40 deletions(-) create mode 100644 tools/ARDOUR/SourceInfoLoader.pm create mode 100644 tools/Spotlight Importer/English.lproj/InfoPlist.strings create mode 100644 tools/Spotlight Importer/English.lproj/schema.strings create mode 100644 tools/Spotlight Importer/GetMetadataForFile.c create mode 100644 tools/Spotlight Importer/Info.plist create mode 100644 tools/Spotlight Importer/Spotlight Importer.xcodeproj/project.pbxproj create mode 100644 tools/Spotlight Importer/main.c create mode 100644 tools/Spotlight Importer/schema.xml create mode 100755 tools/session_exchange.py create mode 100755 tools/synthesize_sources.pl (limited to 'tools') diff --git a/tools/ARDOUR/SourceInfoLoader.pm b/tools/ARDOUR/SourceInfoLoader.pm new file mode 100644 index 0000000000..ec327d91f6 --- /dev/null +++ b/tools/ARDOUR/SourceInfoLoader.pm @@ -0,0 +1,75 @@ +package ARDOUR::SourceInfoLoader; + + +use XML::Handler::Subs; + +@ISA = qw( XML::Handler::Subs ); + +$VERSION = 1.0; + + +sub new { + my ($type, $sessionName) = @_; + + my $self = $type->SUPER::new(); + + $self->{SessionName} = $sessionName; + $self->{InRegions} = 0; + %self->{Sources} = {}; + + + return $self; +} + +sub start_element { + my $self = shift; + my $element = shift; + + my $atts = $element->{Attributes}; + + if ( $element->{Name} eq "Source") { + if ( ! -f "interchange/".$sessionName."/audiofiles/".$atts->{name}) { + $atts->{calculated_length} = 1; + $self->{Sources}->{$atts->{id}} = $atts; + } + } + + + if ( $self->{InRegions} eq 1 && $element->{Name} eq "Region") { + #print "Looking at region ".$atts->{id}."\n"; + my $num = 0; + + my $region_length = $atts->{length}; + while ( $atts->{"source-".$num} ne "" ) { + + if ($region_length > $self->{Sources}->{$atts->{"source-".$num}}->{calculated_length} ) { + $self->{Sources}->{$atts->{"source-".$num}}->{calculated_length} = $region_length; + } + + $num++; + } + } + + if ( $element->{Name} eq "Regions") { + $self->{InRegions} = 1; + #print "In regions\n"; + } + + +} + +sub end_element { + my $self = shift; + my $element = shift; + + if ( $element->{Name} eq "Regions") { + $self->{InRegions} = 0; + #print "Out of regions\n"; + } + +} + +1; + + + diff --git a/tools/Spotlight Importer/English.lproj/InfoPlist.strings b/tools/Spotlight Importer/English.lproj/InfoPlist.strings new file mode 100644 index 0000000000..cafcc33a9e Binary files /dev/null and b/tools/Spotlight Importer/English.lproj/InfoPlist.strings differ diff --git a/tools/Spotlight Importer/English.lproj/schema.strings b/tools/Spotlight Importer/English.lproj/schema.strings new file mode 100644 index 0000000000..1577efdb95 Binary files /dev/null and b/tools/Spotlight Importer/English.lproj/schema.strings differ diff --git a/tools/Spotlight Importer/GetMetadataForFile.c b/tools/Spotlight Importer/GetMetadataForFile.c new file mode 100644 index 0000000000..6b12614172 --- /dev/null +++ b/tools/Spotlight Importer/GetMetadataForFile.c @@ -0,0 +1,56 @@ +#include +#include + +/* ----------------------------------------------------------------------------- + Step 1 + Set the UTI types the importer supports + + Modify the CFBundleDocumentTypes entry in Info.plist to contain + an array of Uniform Type Identifiers (UTI) for the LSItemContentTypes + that your importer can handle + + ----------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + Step 2 + Implement the GetMetadataForFile function + + Implement the GetMetadataForFile function below to scrape the relevant + metadata from your document and return it as a CFDictionary using standard keys + (defined in MDItem.h) whenever possible. + ----------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + Step 3 (optional) + If you have defined new attributes, update the schema.xml file + + Edit the schema.xml file to include the metadata keys that your importer returns. + Add them to the and elements. + + Add any custom types that your importer requires to the element + + + + ----------------------------------------------------------------------------- */ + + + +/* ----------------------------------------------------------------------------- + Get metadata attributes from file + + This function's job is to extract useful information your file format supports + and return it as a dictionary + ----------------------------------------------------------------------------- */ + +Boolean GetMetadataForFile(void* thisInterface, + CFMutableDictionaryRef attributes, + CFStringRef contentTypeUTI, + CFStringRef pathToFile) +{ + /* Pull any available metadata from the file at the specified path */ + /* Return the attribute keys and attribute values in the dict */ + /* Return TRUE if successful, FALSE if there was no data provided */ + + #warning To complete your importer please implement the function GetMetadataForFile in GetMetadataForFile.c + return FALSE; +} diff --git a/tools/Spotlight Importer/Info.plist b/tools/Spotlight Importer/Info.plist new file mode 100644 index 0000000000..da11c8db5b --- /dev/null +++ b/tools/Spotlight Importer/Info.plist @@ -0,0 +1,87 @@ + + + + + + + + + + CFBundleDevelopmentRegion + English + CFBundleDocumentTypes + + + CFBundleTypeRole + MDImporter + LSItemContentTypes + + SUPPORTED_UTI_TYPE + + + + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleName + ${PRODUCT_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.apple.yourcfbundle + CFBundleInfoDictionaryVersion + 6.0 + CFBundleVersion + 1.0 + CFPlugInDynamicRegisterFunction + + CFPlugInDynamicRegistration + NO + CFPlugInFactories + + D77F8126-18F0-4ADE-917C-4A234A5590B9 + MetadataImporterPluginFactory + + CFPlugInTypes + + 8B08C4BF-415B-11D8-B3F9-0003936726FC + + D77F8126-18F0-4ADE-917C-4A234A5590B9 + + + CFPlugInUnloadFunction + + + diff --git a/tools/Spotlight Importer/Spotlight Importer.xcodeproj/project.pbxproj b/tools/Spotlight Importer/Spotlight Importer.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..39ee943965 --- /dev/null +++ b/tools/Spotlight Importer/Spotlight Importer.xcodeproj/project.pbxproj @@ -0,0 +1,275 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 2C05A19C06CAA52B00D84F6F /* GetMetadataForFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 2C05A19B06CAA52B00D84F6F /* GetMetadataForFile.c */; }; + 8D576312048677EA00EA77CD /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB77B6FE84183AC02AAC07 /* main.c */; settings = {ATTRIBUTES = (); }; }; + 8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */; }; + 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; }; + C86B05270671AA6E00DD9006 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C86B05260671AA6E00DD9006 /* CoreServices.framework */; }; + C88FB7D8067446EC006EBB30 /* schema.xml in Resources */ = {isa = PBXBuildFile; fileRef = C88FB7D7067446EC006EBB30 /* schema.xml */; }; + C88FB7E40674480E006EBB30 /* schema.strings in Resources */ = {isa = PBXBuildFile; fileRef = C88FB7E30674480E006EBB30 /* schema.strings */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 08FB77B6FE84183AC02AAC07 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; + 2C05A19B06CAA52B00D84F6F /* GetMetadataForFile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = GetMetadataForFile.c; sourceTree = ""; }; + 8D576316048677EA00EA77CD /* Spotlight Importer.mdimporter */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Spotlight Importer.mdimporter"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D576317048677EA00EA77CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + C86B05260671AA6E00DD9006 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = ""; }; + C88FB7D7067446EC006EBB30 /* schema.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = schema.xml; sourceTree = ""; }; + C88FB7DB0674470F006EBB30 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/schema.strings; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D576313048677EA00EA77CD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */, + C86B05270671AA6E00DD9006 /* CoreServices.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* Spotlight Importer */ = { + isa = PBXGroup; + children = ( + 08FB77AFFE84173DC02AAC07 /* Source */, + 089C167CFE841241C02AAC07 /* Resources */, + 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */, + 19C28FB6FE9D52B211CA2CBB /* Products */, + ); + name = "Spotlight Importer"; + sourceTree = ""; + }; + 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + C86B05260671AA6E00DD9006 /* CoreServices.framework */, + 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + C88FB7E30674480E006EBB30 /* schema.strings */, + C88FB7D7067446EC006EBB30 /* schema.xml */, + 8D576317048677EA00EA77CD /* Info.plist */, + 8D5B49A704867FD3000E48DA /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77AFFE84173DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 2C05A19B06CAA52B00D84F6F /* GetMetadataForFile.c */, + 08FB77B6FE84183AC02AAC07 /* main.c */, + ); + name = Source; + sourceTree = ""; + }; + 19C28FB6FE9D52B211CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D576316048677EA00EA77CD /* Spotlight Importer.mdimporter */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8D57630E048677EA00EA77CD /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8D57630D048677EA00EA77CD /* Spotlight Importer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 70138C840896BE9A00968C2F /* Build configuration list for PBXNativeTarget "Spotlight Importer" */; + buildPhases = ( + 8D57630E048677EA00EA77CD /* Headers */, + 8D57630F048677EA00EA77CD /* Resources */, + 8D576311048677EA00EA77CD /* Sources */, + 8D576313048677EA00EA77CD /* Frameworks */, + 8D576315048677EA00EA77CD /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Spotlight Importer"; + productInstallPath = /Library/Spotlight; + productName = "Spotlight Importer"; + productReference = 8D576316048677EA00EA77CD /* Spotlight Importer.mdimporter */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 70138C880896BE9A00968C2F /* Build configuration list for PBXProject "Spotlight Importer" */; + hasScannedForEncodings = 1; + mainGroup = 089C166AFE841209C02AAC07 /* Spotlight Importer */; + projectDirPath = ""; + targets = ( + 8D57630D048677EA00EA77CD /* Spotlight Importer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D57630F048677EA00EA77CD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */, + C88FB7D8067446EC006EBB30 /* schema.xml in Resources */, + C88FB7E40674480E006EBB30 /* schema.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 8D576315048677EA00EA77CD /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D576311048677EA00EA77CD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D576312048677EA00EA77CD /* main.c in Sources */, + 2C05A19C06CAA52B00D84F6F /* GetMetadataForFile.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 8D5B49A704867FD3000E48DA /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C167EFE841241C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + C88FB7E30674480E006EBB30 /* schema.strings */ = { + isa = PBXVariantGroup; + children = ( + C88FB7DB0674470F006EBB30 /* English */, + ); + name = schema.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 70138C850896BE9A00968C2F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Spotlight; + LIBRARY_STYLE = Bundle; + PRODUCT_NAME = "Spotlight Importer"; + WRAPPER_EXTENSION = mdimporter; + ZERO_LINK = YES; + }; + name = Debug; + }; + 70138C860896BE9A00968C2F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Spotlight; + LIBRARY_STYLE = Bundle; + PRODUCT_NAME = "Spotlight Importer"; + WRAPPER_EXTENSION = mdimporter; + }; + name = Release; + }; + 70138C890896BE9A00968C2F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Debug; + }; + 70138C8A0896BE9A00968C2F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 70138C840896BE9A00968C2F /* Build configuration list for PBXNativeTarget "Spotlight Importer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 70138C850896BE9A00968C2F /* Debug */, + 70138C860896BE9A00968C2F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 70138C880896BE9A00968C2F /* Build configuration list for PBXProject "Spotlight Importer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 70138C890896BE9A00968C2F /* Debug */, + 70138C8A0896BE9A00968C2F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/tools/Spotlight Importer/main.c b/tools/Spotlight Importer/main.c new file mode 100644 index 0000000000..77a2c02833 --- /dev/null +++ b/tools/Spotlight Importer/main.c @@ -0,0 +1,225 @@ +// +// main.c +// Spotlight Importer +// +// Created by Taybin on 1/24/07. +// Copyright (c) 2007 Penguin Sounds. All rights reserved. +// + + + + + +//============================================================================== +// +// DO NO MODIFY THE CONTENT OF THIS FILE +// +// This file contains the generic CFPlug-in code necessary for your importer +// To complete your importer implement the function in GetMetadataForFile.c +// +//============================================================================== + + + + + + +#include +#include +#include + +// ----------------------------------------------------------------------------- +// constants +// ----------------------------------------------------------------------------- + + +#define PLUGIN_ID "D77F8126-18F0-4ADE-917C-4A234A5590B9" + +// +// Below is the generic glue code for all plug-ins. +// +// You should not have to modify this code aside from changing +// names if you decide to change the names defined in the Info.plist +// + + +// ----------------------------------------------------------------------------- +// typedefs +// ----------------------------------------------------------------------------- + +// The import function to be implemented in GetMetadataForFile.c +Boolean GetMetadataForFile(void *thisInterface, + CFMutableDictionaryRef attributes, + CFStringRef contentTypeUTI, + CFStringRef pathToFile); + +// The layout for an instance of MetaDataImporterPlugIn +typedef struct __MetadataImporterPluginType +{ + MDImporterInterfaceStruct *conduitInterface; + CFUUIDRef factoryID; + UInt32 refCount; +} MetadataImporterPluginType; + +// ----------------------------------------------------------------------------- +// prototypes +// ----------------------------------------------------------------------------- +// Forward declaration for the IUnknown implementation. +// + +MetadataImporterPluginType *AllocMetadataImporterPluginType(CFUUIDRef inFactoryID); +void DeallocMetadataImporterPluginType(MetadataImporterPluginType *thisInstance); +HRESULT MetadataImporterQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv); +void *MetadataImporterPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID); +ULONG MetadataImporterPluginAddRef(void *thisInstance); +ULONG MetadataImporterPluginRelease(void *thisInstance); +// ----------------------------------------------------------------------------- +// testInterfaceFtbl definition +// ----------------------------------------------------------------------------- +// The TestInterface function table. +// + +static MDImporterInterfaceStruct testInterfaceFtbl = { + NULL, + MetadataImporterQueryInterface, + MetadataImporterPluginAddRef, + MetadataImporterPluginRelease, + GetMetadataForFile +}; + + +// ----------------------------------------------------------------------------- +// AllocMetadataImporterPluginType +// ----------------------------------------------------------------------------- +// Utility function that allocates a new instance. +// You can do some initial setup for the importer here if you wish +// like allocating globals etc... +// +MetadataImporterPluginType *AllocMetadataImporterPluginType(CFUUIDRef inFactoryID) +{ + MetadataImporterPluginType *theNewInstance; + + theNewInstance = (MetadataImporterPluginType *)malloc(sizeof(MetadataImporterPluginType)); + memset(theNewInstance,0,sizeof(MetadataImporterPluginType)); + + /* Point to the function table */ + theNewInstance->conduitInterface = &testInterfaceFtbl; + + /* Retain and keep an open instance refcount for each factory. */ + theNewInstance->factoryID = CFRetain(inFactoryID); + CFPlugInAddInstanceForFactory(inFactoryID); + + /* This function returns the IUnknown interface so set the refCount to one. */ + theNewInstance->refCount = 1; + return theNewInstance; +} + +// ----------------------------------------------------------------------------- +// DeallocSpotlight_ImporterMDImporterPluginType +// ----------------------------------------------------------------------------- +// Utility function that deallocates the instance when +// the refCount goes to zero. +// In the current implementation importer interfaces are never deallocated +// but implement this as this might change in the future +// +void DeallocMetadataImporterPluginType(MetadataImporterPluginType *thisInstance) +{ + CFUUIDRef theFactoryID; + + theFactoryID = thisInstance->factoryID; + free(thisInstance); + if (theFactoryID){ + CFPlugInRemoveInstanceForFactory(theFactoryID); + CFRelease(theFactoryID); + } +} + +// ----------------------------------------------------------------------------- +// MetadataImporterQueryInterface +// ----------------------------------------------------------------------------- +// Implementation of the IUnknown QueryInterface function. +// +HRESULT MetadataImporterQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv) +{ + CFUUIDRef interfaceID; + + interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault,iid); + + if (CFEqual(interfaceID,kMDImporterInterfaceID)){ + /* If the Right interface was requested, bump the ref count, + * set the ppv parameter equal to the instance, and + * return good status. + */ + ((MetadataImporterPluginType*)thisInstance)->conduitInterface->AddRef(thisInstance); + *ppv = thisInstance; + CFRelease(interfaceID); + return S_OK; + }else{ + if (CFEqual(interfaceID,IUnknownUUID)){ + /* If the IUnknown interface was requested, same as above. */ + ((MetadataImporterPluginType*)thisInstance )->conduitInterface->AddRef(thisInstance); + *ppv = thisInstance; + CFRelease(interfaceID); + return S_OK; + }else{ + /* Requested interface unknown, bail with error. */ + *ppv = NULL; + CFRelease(interfaceID); + return E_NOINTERFACE; + } + } +} + +// ----------------------------------------------------------------------------- +// MetadataImporterPluginAddRef +// ----------------------------------------------------------------------------- +// Implementation of reference counting for this type. Whenever an interface +// is requested, bump the refCount for the instance. NOTE: returning the +// refcount is a convention but is not required so don't rely on it. +// +ULONG MetadataImporterPluginAddRef(void *thisInstance) +{ + ((MetadataImporterPluginType *)thisInstance )->refCount += 1; + return ((MetadataImporterPluginType*) thisInstance)->refCount; +} + +// ----------------------------------------------------------------------------- +// SampleCMPluginRelease +// ----------------------------------------------------------------------------- +// When an interface is released, decrement the refCount. +// If the refCount goes to zero, deallocate the instance. +// +ULONG MetadataImporterPluginRelease(void *thisInstance) +{ + ((MetadataImporterPluginType*)thisInstance)->refCount -= 1; + if (((MetadataImporterPluginType*)thisInstance)->refCount == 0){ + DeallocMetadataImporterPluginType((MetadataImporterPluginType*)thisInstance ); + return 0; + }else{ + return ((MetadataImporterPluginType*) thisInstance )->refCount; + } +} + +// ----------------------------------------------------------------------------- +// Spotlight_ImporterMDImporterPluginFactory +// ----------------------------------------------------------------------------- +// Implementation of the factory function for this type. +// +void *MetadataImporterPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID) +{ + MetadataImporterPluginType *result; + CFUUIDRef uuid; + + /* If correct type is being requested, allocate an + * instance of TestType and return the IUnknown interface. + */ + if (CFEqual(typeID,kMDImporterTypeID)){ + uuid = CFUUIDCreateFromString(kCFAllocatorDefault,CFSTR(PLUGIN_ID)); + result = AllocMetadataImporterPluginType(uuid); + CFRelease(uuid); + return result; + } + /* If the requested type is incorrect, return NULL. */ + return NULL; +} + diff --git a/tools/Spotlight Importer/schema.xml b/tools/Spotlight Importer/schema.xml new file mode 100644 index 0000000000..2b4099bdca --- /dev/null +++ b/tools/Spotlight Importer/schema.xml @@ -0,0 +1,29 @@ + + + + + Custom attributes that this metadata importer supports. Below + is an example of a multivalued string attribute. Other types + are CFNumber, CFDate, CFBoolean and CFData. + + + + + + + + + The keys that this metadata importer handles. + + + com_Foo_YourAttrName + + + com_Foo_YourAttrName + + + + + diff --git a/tools/osx_packaging/app_build.rb b/tools/osx_packaging/app_build.rb index 4cab635034..48d3837368 100755 --- a/tools/osx_packaging/app_build.rb +++ b/tools/osx_packaging/app_build.rb @@ -3,7 +3,7 @@ # Ruby script for pulling together a MacOSX app bundle. # it will be either powerpc or i386 -versionline = `grep -m 1 '^version =' ../../SConstruct` +versionline = `grep -m 1 '^ardour_version =' ../../SConstruct` version = versionline.split(" = ")[1].chomp().slice(1..-2) $stdout.printf("Version is %s\n", version) @@ -57,7 +57,7 @@ end odir = Dir.getwd Dir.chdir("../..") -result = `otool -L gtk2_ardour/ardour.bin` +result = `otool -L gtk2_ardour/ardour-#{version}` results = result.split("\n") results.delete_at(0) @@ -101,12 +101,12 @@ end Dir.chdir(odir) -# copy ardour.bin to bindir/ardour +# copy ardour binary to bindir/ardour -if File.exist?("../../gtk2_ardour/ardour.bin") then +if File.exist?("../../gtk2_ardour/ardour-#{version}") then $stdout.print("Copying bin to #{bindir} ...\n"); - `cp ../../gtk2_ardour/ardour.bin #{bindir}/ardour` + `cp ../../gtk2_ardour/ardour-#{version} #{bindir}/ardour` end `cp ../../libs/surfaces/*/*.dylib #{libdir}/surfaces` diff --git a/tools/osx_packaging/ardour2_mac_ui.rc b/tools/osx_packaging/ardour2_mac_ui.rc index ad456c305f..e01f2eb357 100644 --- a/tools/osx_packaging/ardour2_mac_ui.rc +++ b/tools/osx_packaging/ardour2_mac_ui.rc @@ -323,6 +323,17 @@ style "ardour_adjusters" = "default_buttons_menus" bg[ACTIVE] = { 0.06, 0.06, 0.06 } } +style "editor_hscrollbar" = "ardour_adjusters" +{ + # + # special case: we want this scrollbar to be as tall as the + # zoom focus selector combobox. scrollbars don't expand to + # fill the space available to them, so we have to explicitly + # make it bigger. + # + GtkRange::slider_width = 27 +} + style "ardour_progressbars" = "default_buttons_menus" { bg[NORMAL] = { 0, 0, 0 } @@ -658,27 +669,44 @@ style "edit_group_3" bg[SELECTED] = { 0.93, 0.34, 0.08 } } -style "region_list_display" = "small_bold_text" +style "treeview_parent_node" { - fg[NORMAL] = { 0.80, 0.80, 0.80 } - fg[ACTIVE] = { 0.80, 0.80, 0.80 } - fg[SELECTED] = { 0.70, 0.70, 0.70 } - bg[NORMAL] = { 0, 0, 0 } - bg[ACTIVE] = { 0, 0, 0 } - bg[SELECTED] = { 0, 0, 0 } - base[NORMAL] = { 0, 0, 0 } - base[ACTIVE] = { 0, 1, 0 } - base[INSENSITIVE] = { 0, 0, 0 } - base[SELECTED] = { 0.80, 0.80, 0.80 } + # specifies *just* the color used for whole file rows when not selected + fg[NORMAL] = { 0.0, 0.6, 0.85 } +} + +style "treeview_display" = "small_bold_text" +{ + # expander arrow border and DnD "icon" text + fg[NORMAL] = { 0.8, 0.8, 0.8 } + + # background with no rows or no selection, plus + # expander arrow core and DnD "icon" background + base[NORMAL] = { 0.20, 0.20, 0.25 } + + # selected row bg when window does not have focus (including during DnD) + base[ACTIVE] = { 0.0, 0.60, 0.60 } + + # selected row bg when window has focus + base[SELECTED] = { 0, 0.75, 0.75 } + + # row text when in normal state and not a parent + text[NORMAL] = { 0.80, 0.80, 0.80 } + + # selected row text with window focus + text[SELECTED] = { 0, 1.0, 1.0 } + + # selected row text without window focus (including during DnD) + text[ACTIVE] = { 0, 1.0, 1.0 } } style "main_canvas_area" { - bg[NORMAL] = { 0.20, 0.20, 0.25 } - bg[ACTIVE] = { 0.20, 0.20, 0.25 } - bg[INSENSITIVE] = { 0.20, 0.20, 0.25 } - bg[SELECTED] = { 0.20, 0.20, 0.25 } - bg[PRELIGHT] = { 0.20, 0.20, 0.25 } + bg[NORMAL] = { 0.30, 0.30, 0.34 } + bg[ACTIVE] = { 0.30, 0.30, 0.34 } + bg[INSENSITIVE] = { 0.30, 0.30, 0.34 } + bg[SELECTED] = { 0.30, 0.30, 0.34 } + bg[PRELIGHT] = { 0.30, 0.30, 0.34 } } style "track_controls_inactive" @@ -955,13 +983,13 @@ style "pan_slider" fg[NORMAL] = { 0.22, 0.73, 0.22 } fg[ACTIVE] = { 0.22, 0.73, 0.22 } - fg[INSENSITIVE] = {0.22, 0.53, 0.22 } + fg[INSENSITIVE] = {0.22, 0.53, 0.22 } fg[SELECTED] = { 0.67, 0.23, 0.22 } fg[PRELIGHT] = { 0.67, 0.23, 0.22 } bg[NORMAL] = { 0.05, 0.05, 0.05 } bg[ACTIVE] = { 0, 0, 0 } - bg[INSENSITIVE] = {0.12, 0.19, 0.25 } + bg[INSENSITIVE] = {0.12, 0.19, 0.25 } bg[SELECTED] = { 0, 0, 0 } bg[PRELIGHT] = { 0, 0, 0 } @@ -975,17 +1003,12 @@ style "pan_slider" base[NORMAL] = { 0.80, 0.80, 0.80 } base[ACTIVE] = { 0.80, 0.80, 0.80 } - base[INSENSITIVE] = {0.32, 0.39, 0.45 } # matches default_base + base[INSENSITIVE] = {0.6, 0.6, 0.6 } base[SELECTED] = { 0.80, 0.80, 0.80 } base[PRELIGHT] = { 0.80, 0.80, 0.80 } } -style "region_list_whole_file" -{ - fg[NORMAL] = { 0.4, 0.4, 0.9 } -} - style "ardour_button" ="default_buttons_menus" { xthickness = 1 @@ -1162,7 +1185,6 @@ widget "*EditorTrackNameDisplay" style "track_name_display" widget "*EditorTrackNameDisplay*" style "track_name_display" widget "*EditorActiveTrackNameDisplay" style "active_track_name_display" widget "*EditorActiveTrackNameDisplay*" style "active_track_name_display" -widget "*EditorRegionList" style "region_list_display" widget "*CrossfadeEditAuditionButton" style "red_when_active" widget "*CrossfadeEditAuditionButton*" style "red_when_active" widget "*CrossfadeEditCurveButton" style "red_when_active" @@ -1197,19 +1219,19 @@ widget "*ParameterValueDisplay" style "medium_bold_entry" widget "*PluginUIClickBox" style "medium_bold_entry" widget "*PluginUIClickBox*" style "medium_bold_entry" widget "*PluginSlider" style "plugin_slider" -widget "*TrackListDisplay" style "track_list_display" -widget "*TrackListDisplay.*" style "small_bold_text" -widget "*EditGroupList" style "track_list_display" -widget "*RegionListDisplay" style "small_bold_entry" -widget "*RegionListDisplay.*" style "small_bold_text" widget "*RedirectSelector" style "redirect_list_display" widget "*RedirectSelector.*" style "redirect_list_display" +widget "*EditGroupDisplay" style "treeview_display" +widget "*TrackListDisplay" style "treeview_display" +widget "*RegionListDisplay" style "treeview_display" +widget "*NamedSelectionDisplay" style "treeview_display" +widget "*SnapshotDisplay" style "treeview_display" widget "*MixerTrackCommentArea" style "option_entry" widget "*MixerPanZone" style "pan_zone" -widget "*MixerTrackDisplayList" style "track_list_display" -widget "*MixerSnapshotDisplayList" style "track_list_display" -widget "*MixerAuxDisplayList" style "track_list_display" -widget "*MixerGroupList" style "track_list_display" +widget "*MixerTrackDisplayList" style "treeview_display" +widget "*MixerSnapshotDisplayList" style "treeview_display" +widget "*MixerAuxDisplayList" style "treeview_display" +widget "*MixerGroupList" style "treeview_display" widget "*RegionEditorLabel" style "medium_text" widget "*RegionEditorSmallLabel" style "small_text" widget "*RegionEditorEntry" style "medium_entry" @@ -1336,7 +1358,8 @@ widget "*PanningLinkDirectionButton" style "very_small_button" widget "*PanningLinkDirectionButton.*" style "very_small_button" widget "*ChannelCountSelector" style "medium_bold_entry" widget "*ChannelCountSelector.GtkArrow" style "default_buttons_menus" -widget "*RegionListWholeFile" style "region_list_whole_file" +widget "*RegionListWholeFile" style "treeview_parent_node" +widget "*EditorHScrollbar" style "editor_hscrollbar" class "GtkWidget" style "default_base" class "GtkScrollbar" style "ardour_adjusters" diff --git a/tools/session_exchange.py b/tools/session_exchange.py new file mode 100755 index 0000000000..825476c967 --- /dev/null +++ b/tools/session_exchange.py @@ -0,0 +1,856 @@ +#! /usr/bin/python + +# Session Exchange +# By Taybin Rutkin +# Copyright 2004-2005, under the GPL + +VERSION='0.1.2' + +#twisted libraries +from twisted.internet import gtk2reactor +gtk2reactor.install() +from twisted.internet import reactor, protocol +import twisted.internet.error + +#pygtk libraries +import gobject +import gtk + +#standard python2.2 libraries +import getopt +import os +import os.path +import re +import shelve +import string +import sys +import xml.dom.minidom + +def get_header_size(filename): + size = 0 + file = open(filename, 'r') + while True: + chunk = file.read(4) + size += 4 + if chunk == "data": + file.close() + return size + 4 #include the size chunk after "data" + if not chunk: + file.close() + return None + +def append_empty_data(self, filename, size): + file = open(filename, 'a') + file.seek(size-1) + file.write('\x00') + file.close() + +def get_sound_list(snapshot): + doc = xml.dom.minidom.parse(snapshot) + + regionlist = [] + playlists_tag = doc.getElementsByTagName('Playlists') + playlists = playlists_tag[0].getElementsByTagName('Playlist') + for play in playlists: + regions = play.getElementsByTagName('Region') + for region in regions: + regionlist.append(region.getAttribute('source-0')) + regionlist.append(region.getAttribute('source-1')) + regionlist.append(region.getAttribute('source-2')) + regionlist.append(region.getAttribute('source-3')) + regionlist.append(region.getAttribute('source-4')) + regionlist.append(region.getAttribute('source-5')) + + sourcelist = {} + sources = doc.getElementsByTagName('Source') + for source in sources: + sourcelist[source.getAttribute('id')] = str(source.getAttribute('name')) + + soundlist = [] + for id in regionlist: + if sourcelist.has_key(id): + soundlist.append(sourcelist[id]) + + return soundlist + +def raise_error(string, parent): + dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, string) + + dialog.run() + dialog.destroy() + +class Data(object): + def delete_snap(self, session, collab, snap): + sessions = self._data['sessions'] + sessions[session]['collabs'][collab]['snaps'].remove(snap) + self._data['sessions'] = sessions + + def delete_collab(self,session, collab): + sessions = self._data['sessions'] + del sessions[session]['collabs'][collab] + self._data['sessions'] = sessions + + def delete_session(self, session): + sessions = self._data['sessions'] + del sessions[session] + self._data['sessions'] = sessions + + def add_snap(self, session_name, collab_name, snap_name): + sessions = self._data['sessions'] + sessions[session_name]['collabs'][collab_name]['snaps'].append(snap_name) + sessions[session_name]['collabs'][collab_name]['snaps'].sort() + self._data['sessions'] = sessions + + g_display.update_snap_view() + + def add_collab(self, session_name, collab_name, ip_address, port): + sessions = self._data['sessions'] + sessions[session_name]['collabs'][collab_name] = {} + sessions[session_name]['collabs'][collab_name]['snaps'] = [] + sessions[session_name]['collabs'][collab_name]['sounds'] = [] + sessions[session_name]['collabs'][collab_name]['ip'] = ip_address + sessions[session_name]['collabs'][collab_name]['port'] = port + self._data['sessions'] = sessions + + client = ExchangeClientFactory(session_name, collab_name, None, self.debug_mode) + reactor.connectTCP(ip_address, port, client) + g_display.show_status("connecting") + + g_display.update_collab_view() + + def add_session(self, session_path): + sessions = self._data['sessions'] + + session_name = session_path[session_path.rfind('/', 0, len(session_path)-2)+1: -1] + sessions[session_name] = {} + sessions[session_name]['path'] = session_path + sessions[session_name]['collabs'] = {} + sessions[session_name]['collabs'][self._data['user']] = {} + sessions[session_name]['collabs'][self._data['user']]['snaps'] = [] + sessions[session_name]['collabs'][self._data['user']]['sounds'] = [] + + self._data['sessions'] = sessions + + self.rescan_session(session_name) + + def rescan_session(self, session_name): + sessions = self._data['sessions'] + + session_path = sessions[session_name]['path'] + sessions[session_name]['collabs'][self._data['user']]['snaps'] = self._scan_snapshots(session_path) + sessions[session_name]['collabs'][self._data['user']]['sounds'] = self._scan_sounds(session_path) + + self._data['sessions'] = sessions + + g_display.update_snap_view() + + print self._data['sessions'] + + def create_session(self, session_path): + try: + os.mkdir(session_path) + os.mkdir(session_path+"/sounds") + except OSError: + raise_error("Could not create session directory", g_display.window) + return + + sessions = self._data['sessions'] + + session_name = session_path[session_path.rfind('/', 0, len(session_path)-2)+1: ] + sessions[session_name] = {} + sessions[session_name]['path'] = session_path + sessions[session_name]['collabs'] = {} + sessions[session_name]['collabs'][self._data['user']] = {} + sessions[session_name]['collabs'][self._data['user']]['snaps'] = [] + sessions[session_name]['collabs'][self._data['user']]['sounds'] = [] + + self._data['sessions'] = sessions + print self._data['sessions'] + + def get_session_path(self, session): + sessions = self._data['sessions'] + return sessions[session]['path'] + + def get_user(self): + return self._data['user'] + + def set_user(self, username): + self._data['user'] = username + + def get_collab_ip(self, session, collab): + sessions = self._data['sessions'] + return sessions[session]['collabs'][collab]['ip'] + + def close(self): + self._data.close() + + def get_sessions(self): + sessions = self._data['sessions'] + sess = sessions.keys() + sess.sort() + return sess + + def get_collabs(self, session): + if session: + sessions = self._data['sessions'] + collabs = sessions[session]['collabs'].keys() + collabs.sort() + return collabs + else: + return [] + + def get_snaps(self, session, collab): + if session and collab: + sessions = self._data['sessions'] + snaps = sessions[session]['collabs'][collab]['snaps'] + snaps.sort() + return snaps + else: + return [] + + def get_sounds(self, session, collab): + if session and collab: + sessions = self._data['sessions'] + sounds = sessions[session]['collabs'][self._data['user']]['sounds'] + sounds.sort() + return sounds + else: + return [] + + def _scan_snapshots(self, session): + snaps = [] + files = os.listdir(session) + pattern = re.compile(r'\.ardour$') + for file in files: + if pattern.search(file): + snaps.append(file[0:-7]) + print file[0:-7] + return snaps + + def _scan_sounds(self, session): + sounds = [] + files = os.listdir(session+'/sounds') + pattern = re.compile(r'\.peak$') + for file in files: + if not pattern.search(file): + sounds.append(file) + return sounds + + def __init__(self, *args): + self._data = shelve.open(os.path.expanduser('~/.session_exchange'), 'c') + self.port = 8970 + self.debug_mode = False + if len(self._data.keys()) < 1: + self._data['sessions'] = {} + self._data['user'] = '' + + self._collabs = {} + +from twisted.protocols.basic import FileSender +class FileSenderLimited(FileSender): + def beginFileTransfer(self, file, consumer, limit, transform = None): + self.file = file + self.consumer = consumer + self.CHUNK_SIZE = limit + self.transform = transform + + self.consumer.registerProducer(self, False) + self.deferred = defer.Deferred() + return self.deferred + + def resumeProducing(self): + chunk = '' + chunk = self.file.read(self.CHUNK_SIZE) + + if self.transform: + chunk = self.transform(chunk) + + self.consumer.write(chunk) + self.lastSent = chunk[-1] + self.file = None + self.consumer.unregisterProducer() + self.deferred.callback(self.lastSent) + self.deferred = None + +from twisted.protocols.basic import LineReceiver +class ExchangeServer (LineReceiver): + def __init__(self): + self.state = "IDLE" + + def error(self, message): + self.sendLine("ERROR") + self.sendLine(message) + self.transport.loseConnection() + + def connectionLost(self, reason): + print "server: connection lost: ", reason + + def connectionMade(self): + print "server: connection made" + + def lineReceived(self, data): + print "server: ", data + + if self.state == "SESSION": + if g_data.get_sessions().count(data): + self.session_name = data + self.state = "IDLE" + self.sendLine("OK") + else: + self.error(data + " doesn't exist on server") + elif self.state == "SNAPSHOT": + if g_data.get_snaps(self.session_name, g_data.get_user()).count(data): + filename = g_data.get_session_path(self.session_name)+data+'.ardour' + print filename + self.sendLine(str(os.stat(filename).st_size)) + self.sendLine("OK") + self.file = open(filename, 'r') + file_sender = FileSender() + cb = file_sender.beginFileTransfer(self.file, self.transport) + cb.addCallback(self.file_done) + else: + self.error("snapshot: " + data + " doesn't exist on server") + elif self.state == "SOUNDFILE" or self.state == "SOUNDFILE_HEADER": + if g_data.get_sounds(self.session_name, g_data.get_user()).count(data): + filename = g_data.get_session_path(self.session_name)+"/sounds/"+data + print filename + if self.state == "SOUNDFILE": + self.sendLine(str(os.stat(filename).st_size)) + else: #SOUNDFILE_HEADER + header_size = get_header_size(filename) + if header_size: + self.sendLine(str(header_size)) + else: + self.error('soundfile: ' + data + 'doesn\'t have "data" chunk') + self.sendLine("OK") + self.file = open(filename, 'r') + if self.state == "SOUNDFILE": + file_sender = FileSender() + cb = file_sender.beginFileTransfer(self.file, self.transport) + else: # SOUNDFILE_HEADER + file_sender = FileSenderLimited() + cb = file_sender.beginFileTransfer(self.file, self.transport, header_size) + cb.addCallback(self.file_done) + else: + self.error("soundfile: " + data + "doesn't exist on server") + elif self.state == "SOUNDFILE_SIZE": + if g_data.get_sounds(self.session_name, g_data.get_user()).count(data): + filename = g_data.get_session_path(self.session_name)+"/sounds/"+data + print filename + self.sendLine(str(os.stat(filename).st_size)) + self.state = "IDLE" + elif data == "SESSION": + self.state = "SESSION" + elif data == "SNAPS": + self.state = "SNAPS" + for snap in g_data.get_snaps(self.session_name, g_data.get_user()): + self.sendLine(snap) + self.sendLine("OK") + self.state = "IDLE" + elif data == "SNAPSHOT": + self.state = "SNAPSHOT" + elif data == "SOUNDFILE": + self.state = "SOUNDFILE" + elif data == "SOUNDFILE_HEADER": + self.state = "SOUNDFILE_HEADER" + elif data == "SOUNDFILE_SIZE": + self.state = "SOUNDFILE_SIZE" + + def file_done(self, data): + print "server: file done" + self.file.close() + self.state = "IDLE" + +class ExchangeServerFactory(protocol.ServerFactory): + protocol = ExchangeServer + + def __init__(self): + pass + +class ExchangeClient (LineReceiver): + def __init__(self, session_name, collab_name, snap_name, debug_mode): + self.session_name = session_name + self.collab_name = collab_name + self.snap_name = snap_name + self.debug_mode = debug_mode + self.state = "IDLE" + + def connectionLost(self, reason): + g_display.show_status("Connection lost") + + def connectionMade(self): + g_display.show_status("Connection made") + self.state = "SESSION" + self.sendLine("SESSION") + self.sendLine(self.session_name) + + def rawDataReceived(self, data): + self.file.write(data) + self.received += len(data) + print self.received, self.filesize + if self.received >= self.filesize: + self.setLineMode() + self.file.close() + g_data.rescan_session(self.session_name) + if self.state == "SNAPSHOT": + self.sounds = get_sound_list(self.filename) + if len(self.sounds): + self.sound_index = 0 + if self.debug_mode: + self.state = "SOUNDFILE_HEADER" + self.sendLine("SOUNDFILE_HEADER") + else: + self.state = "SOUNDFILE" + self.sendLine("SOUNDFILE") + self.sendLine(self.sounds[self.sound_index]) + else: + self.transport.loseConnection() + elif self.state == "SOUNDFILE": + self.sound_index += 1 + if self.sound_index > len(self.sounds)-1: + self.transport.loseConnection() + else: + self.sendLine("SOUNDFILE") + self.sendLine(self.sounds[self.sound_index]) + elif self.state == "SOUNDFILE_HEADER": + self.state = "SOUNDFILE_SIZE" + self.sendLine("SOUNDFILE_SIZE") + self.sendLine(self.sounds[self.sound_index]) + + def lineReceived(self, data): + print "client: ", data + + if data == "ERROR": + self.state = "ERROR" + elif data == "OK": + if self.state == "SESSION": + if self.snap_name: + self.state = "SNAPSHOT" + self.sendLine("SNAPSHOT") + self.sendLine(self.snap_name) + else: + self.state = "SNAPS" + self.sendLine("SNAPS") + elif self.state == "SNAPS": + self.transport.loseConnection() + elif self.state == "SNAPSHOT": + self.setRawMode() + self.filename = g_data.get_session_path(self.session_name)+'/'+self.snap_name+'.ardour' + self.file = open(self.filename, 'w') + self.received = 0 + elif self.state == "SOUNDFILE" or self.state == "SOUNDFILE_HEADER": + self.setRawMode() + self.filename = g_data.get_session_path(self.session_name)+'/sounds/'+self.sounds[self.sound_index] + self.file = open(self.filename, 'w') + self.received = 0 + elif self.state == "ERROR": + raise_error(data, g_display.window) + elif self.state == "SNAPS": + g_data.add_snap(self.session_name, self.collab_name, data) + elif self.state == "SNAPSHOT": + self.filesize = int(data) + elif self.state == "SOUNDFILE": + self.filesize = int(data) + elif self.state == "SOUNDFILE_HEADER": + self.filesize = int(data) + elif self.state == "SOUNDFILE_SIZE": + append_empty_data(self.filename, int(data)) + self.sound_index += 1 + if self.sound_index > len(self.sounds)-1: + self.transport.loseConnection() + else: + self.state = "SOUNDFILE_HEADER" + self.sendLine("SOUNDFILE_HEADER") + self.sendLine(self.sounds[self.sound_index]) + +class ExchangeClientFactory(protocol.ClientFactory): + def buildProtocol(self, addr): + return ExchangeClient(self.session_name, self.collab_name, self.snap_name, self.debug_mode) + + def clientConnectionFailed(self, connector, reason): + raise_error('Connection failed: ' + reason.getErrorMessage(), g_display.window) + g_display.show_status('Connection failed') + + def __init__(self, session_name, collab_name, snap_name, debug_mode): + self.session_name = session_name + self.collab_name = collab_name + self.snap_name = snap_name + self.debug_mode = debug_mode + +class HelperWin(object): + def delete_me(self, window): + self = 0 + +class Preferences(HelperWin): + def __init__(self): + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.set_title('Preferences') + self.window.connect('destroy', self.delete_me) + self.window.set_position(gtk.WIN_POS_MOUSE) + + main_box = gtk.VBox() + self.window.add(main_box) + + hbox1 = gtk.HBox() + label1 = gtk.Label("User") + self.user = gtk.Entry() + self.user.set_text(g_data.get_user()) + hbox1.pack_start(label1) + hbox1.pack_start(self.user) + main_box.pack_start(hbox1) + + ok_btn = gtk.Button("Ok") + ok_btn.connect('clicked', self.ok_clicked) + main_box.pack_start(ok_btn) + + self.window.show_all() + + def ok_clicked(self, btn): + g_data.set_user(self.user.get_text()) + self.window.hide_all() + + def show_all(self): + self.window.show_all() + +class AddCollaborator(HelperWin): + def __init__(self, session): + self.session_name = session + + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.set_title('Fetch Session') + self.window.connect('destroy', self.delete_me) + self.window.set_position(gtk.WIN_POS_MOUSE) + + main_box = gtk.VBox() + self.window.add(main_box) + + hbox0 = gtk.HBox() + label0 = gtk.Label("Collaborator") + self.collab = gtk.Entry() + self.collab.connect('key-release-event', self.key_press) + hbox0.pack_start(label0) + hbox0.pack_start(self.collab) + main_box.pack_start(hbox0) + + hbox1 = gtk.HBox() + label1 = gtk.Label("IP Address") + self.address = gtk.Entry() + self.address.connect('key-release-event', self.key_press) + hbox1.pack_start(label1) + hbox1.pack_start(self.address) + main_box.pack_start(hbox1) + + hbox2 = gtk.HBox() + label2 = gtk.Label("Port Number") + self.port = gtk.Entry() + self.port.connect('key-release-event', self.key_press) + self.port.set_text(str(g_data.port)) + hbox2.pack_start(label2) + hbox2.pack_start(self.port) + main_box.pack_start(hbox2) + + hbox3 = gtk.HBox() + label3 = gtk.Label("Username") + label3.set_sensitive(False) + self.username = gtk.Entry() + self.username.set_sensitive(False) + hbox3.pack_start(label3) + hbox3.pack_start(self.username) + main_box.pack_start(hbox3) + + hbox4 = gtk.HBox() + label4 = gtk.Label("Password") + label4.set_sensitive(False) + self.password = gtk.Entry() + self.password.set_sensitive(False) + hbox4.pack_start(label4) + hbox4.pack_start(self.password) + main_box.pack_start(hbox4) + + self.ok_btn = gtk.Button(gtk.STOCK_OK) + self.ok_btn.set_use_stock(True) + self.ok_btn.connect('clicked', self.ok_clicked) + self.ok_btn.set_sensitive(False) + main_box.pack_start(self.ok_btn) + + self.window.show_all() + + def key_press(self, event, data): + if self.collab.get_text() and self.address.get_text() and self.port.get_text(): + self.ok_btn.set_sensitive(True) + else: + self.ok_btn.set_sensitive(False) + return True + + def ok_clicked(self, btn): + self.window.hide_all() + g_data.add_collab(self.session_name, self.collab.get_text(), self.address.get_text(), int(self.port.get_text())) + self.collab.set_text('') + self.address.set_text('') + self.port.set_text('') + self.username.set_text('') + self.password.set_text('') + + def show_all(self): + self.window.show_all() + +class ArdourShareWindow(object): + def menuitem_cb(self, window, action, widget): + print self, window, action, widget + + def add_collaborator_cb(self, window, action, widget): + if self.session: + self.add_session = AddCollaborator(self.session) + + def fetch_snapshot_cb(self, window, action, widget): + if self.session and self.collab and self.collab != g_data.get_user(): + client = ExchangeClientFactory(self.session, self.collab, self.snap, g_data.debug_mode) + reactor.connectTCP(g_data.get_collab_ip(self.session, self.collab), g_data.port, client) + + def preferences_cb(self, window, action, widget): + self.preferences = Preferences() + + def add_session_ok_file_btn_clicked(self, w): + filename = self.file_sel.get_filename() + if filename.endswith(".ardour"): + g_data.add_session(filename[0:filename.rfind("/")+1]) + self.update_session_view() + else: + raise_error("Not an Ardour session", self.window) + self.file_sel.destroy() + + def add_session_cb(self, window, action, widget): + if g_data.get_user(): + self.file_sel = gtk.FileSelection("Add Session...") + self.file_sel.ok_button.connect("clicked", self.add_session_ok_file_btn_clicked) + self.file_sel.cancel_button.connect("clicked", lambda w: self.file_sel.destroy()) + self.file_sel.connect("destroy", lambda w: self.file_sel.destroy()) + self.file_sel.show() + else: + raise_error("Set the user name in the preferences first", self.window) + + def create_session_cb(self, window, action, widget): + if g_data.get_user(): + self.file_sel = gtk.FileSelection("Create Session...") + self.file_sel.ok_button.connect("clicked", self.create_file_ok_btn_clicked) + self.file_sel.cancel_button.connect("clicked", lambda w: self.file_sel.destroy()) + self.file_sel.connect("destroy", lambda w: self.file_sel.destroy()) + self.file_sel.show() + else: + raise_error("Set the user name in the preferences first", self.window) + + def create_file_ok_btn_clicked(self, w): + filename = self.file_sel.get_filename() + if len(filename) > 0: + g_data.create_session(filename) + self.update_session_view() + else: + raise_error("Not an Ardour session", self.window) + self.file_sel.destroy() + + def update_session_view(self): + self.session_model.clear() + for session in g_data.get_sessions(): + self.session_model.set(self.session_model.append(), 0, session) + + def update_collab_view(self): + self.collab_model.clear() + for collab in g_data.get_collabs(self.session): + self.collab_model.set(self.collab_model.append(), 0, collab) + + def update_snap_view(self): + self.snap_model.clear() + for snap in g_data.get_snaps(self.session, self.collab): + self.snap_model.set(self.snap_model.append(), 0, snap) + + def cb_session_selection_changed(self, selection_object): + selected = [] + selection_object.selected_foreach(lambda model, path, iter, sel = selected: sel.append(path)) + for x in selected: + self.session = self.session_model[x][0] + self.selected_type = "session" + self.update_collab_view() + + def cb_collab_selection_changed(self, selection_object): + selected = [] + selection_object.selected_foreach(lambda model, path, iter, sel = selected: sel.append(path)) + for x in selected: + self.collab = self.collab_model[x][0] + self.selected_type = "collab" + self.update_snap_view() + + def cb_snap_selection_changed(self, selection_object): + selected = [] + selection_object.selected_foreach(lambda model, path, iter, sel = selected: sel.append(path)) + for x in selected: + self.snap = self.snap_model[x][0] + self.selected_type = "snap" + + def delete_cb(self, window, action, widget): + if self.selected_type == "session": + g_data.delete_session(self.session) + self.session = "" + self.collab = "" + self.snap = "" + elif self.selected_type == "collab": + g_data.delete_collab(self.session, self.collab) + self.collab = "" + self.snap = "" + elif self.selected_type == "snap": + g_data.delete_snap(self.session, self.collab, self.snap) + self.snap = "" + + self.update_session_view() + self.update_collab_view() + self.update_snap_view() + self.selected_type = "" + + def show_status(self, text): + mid = self.status_bar.push(self._status_cid, text) + if self._status_mid: + self.status_bar.remove(self._status_cid, self._status_mid) + self._status_mid = mid + + def __init__(self): + self.selected_type = "" + self.session = "" + self.collab = g_data.get_user() + self.snap = "" + + self.preferences = 0 + self.add_collab = 0 + self.add_session = 0 + + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.set_title('Session Exchange') + self.window.set_size_request(400, 200) + self.window.connect('destroy', lambda win: gtk.main_quit()) + self.window.set_position(gtk.WIN_POS_MOUSE) + + accel_group = gtk.AccelGroup() + self.window.add_accel_group(accel_group) + + main_box = gtk.VBox() + self.window.add(main_box) + + menu_items = ( + ('/_File', None, None, 0, ''), + ('/File/_Add Session...','A', self.add_session_cb, 0, ''), + ('/File/Create _Session...', 'S', self.create_session_cb, 0, ''), + ('/File/sep1', None, None, 0, ''), + ('/File/_Quit', 'Q', gtk.main_quit, 0, '', gtk.STOCK_QUIT), + ('/_Edit', None, None, 0, '' ), + ('/Edit/Cu_t', 'X', self.menuitem_cb, 0, '', gtk.STOCK_CUT), + ('/Edit/_Copy', 'C', self.menuitem_cb, 0, '', gtk.STOCK_COPY), + ('/Edit/_Paste', 'V', self.menuitem_cb, 0, '', gtk.STOCK_PASTE), + ('/Edit/_Delete', None, self.delete_cb, 0, '', gtk.STOCK_DELETE), + ('/Edit/sep1', None, None, 0, ''), + ('/Edit/Add Colla_borator...','B', self.add_collaborator_cb,0,''), + ('/Edit/_Fetch Snapshot','F', self.fetch_snapshot_cb,0,''), + ('/Edit/sep1', None, None, 0, ''), + ('/Edit/_Preferences...','P', self.preferences_cb, 0, '') + ) + + #need to hold a reference to the item_factory or the menubar will disappear. + self.item_factory = gtk.ItemFactory(gtk.MenuBar, '
', accel_group) + self.item_factory.create_items(menu_items, self.window) + main_box.pack_start(self.item_factory.get_widget('
'), gtk.FALSE) + + pane1 = gtk.HPaned() + pane2 = gtk.HPaned() + pane1.pack2(pane2, gtk.TRUE, gtk.FALSE) + + scroll1 = gtk.ScrolledWindow() + scroll1.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + pane1.pack1(scroll1, gtk.TRUE, gtk.FALSE) + scroll2 = gtk.ScrolledWindow() + scroll2.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + pane2.pack1(scroll2, gtk.TRUE, gtk.FALSE) + scroll3 = gtk.ScrolledWindow() + scroll3.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + pane2.pack2(scroll3, gtk.TRUE, gtk.FALSE) + + self.session_model = gtk.ListStore(gobject.TYPE_STRING) + view1 = gtk.TreeView(self.session_model) + column1 = gtk.TreeViewColumn('Sessions', gtk.CellRendererText(), text=0) + view1.append_column(column1) + self.session_selection = view1.get_selection() + self.session_selection.connect("changed", self.cb_session_selection_changed) + scroll1.add(view1) + + self.update_session_view() + + self.collab_model = gtk.ListStore(gobject.TYPE_STRING) + view2 = gtk.TreeView(self.collab_model) + column2 = gtk.TreeViewColumn('Collaborators', gtk.CellRendererText(), text=0) + view2.append_column(column2) + self.collab_selection = view2.get_selection() + self.collab_selection.connect("changed", self.cb_collab_selection_changed) + scroll2.add(view2) + + self.snap_model = gtk.ListStore(gobject.TYPE_STRING) + view3 = gtk.TreeView(self.snap_model) + column3 = gtk.TreeViewColumn('Snapshots', gtk.CellRendererText(), text=0) + view3.append_column(column3) + self.snap_selection = view3.get_selection() + self.snap_selection.connect("changed", self.cb_snap_selection_changed) + scroll3.add(view3) + + main_box.pack_start(pane1, gtk.TRUE, gtk.TRUE) + + self.status_bar = gtk.Statusbar() + main_box.pack_start(self.status_bar, gtk.FALSE) + self._status_cid = self.status_bar.get_context_id('display') + self._status_mid = '' + + self.window.show_all() + +def print_help(): + print """ + -h, --help + -n, --no-server Only act as a client + -p, --port Defaults to 8970 + -d, --debug Infers audio files. For debugging Ardour. + -v, --version Version + """ + sys.exit(2) + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "hp:ndv", ["help", "port=", "no-server", "debug", "version"]) + except getopt.GetoptError: + print_help() + + server = True + for o, a in opts: + if o in ("-h", "--help"): + print_help() + if o in ("-d", "--debug"): + g_display.window.set_title('Session Exchange: Debug Mode') + g_data.debug_mode = True + if o in ("-p", "--port"): + g_data.port = int(a) + if o in ("-n", "--no-server"): + server = False + if o in ("-v", "--version"): + print VERSION + sys.exit(2) + + if (server): + try: + reactor.listenTCP(g_data.port, ExchangeServerFactory()) + except twisted.internet.error.CannotListenError: + print "Can not listen on a port number under 1024 unless run as root" + sys.exit(2) + + reactor.run() + + g_data.close() + +# global objects +g_data = Data() +g_display = ArdourShareWindow() + +if __name__ == '__main__': + main() diff --git a/tools/synthesize_sources.pl b/tools/synthesize_sources.pl new file mode 100755 index 0000000000..ebb903cf37 --- /dev/null +++ b/tools/synthesize_sources.pl @@ -0,0 +1,75 @@ +#!/usr/bin/env perl +# Ardour session synthesizer +# (c)Sampo Savolainen 2007 +# +# GPL +# This reads an Ardour session file and creates zero-signal source files +# for each missing source file. The length of each file is determined +# by how far regions using that source file go into the sample data. + +use XML::Parser::PerlSAX; +use XML::Handler::XMLWriter; +use IO::Handle; + +use ARDOUR::SourceInfoLoader; + + +my ($samplerate, $sessionName) = @ARGV; + +if ( ! -d $sessionName || ! -f $sessionName."/".$sessionName.".ardour" ) { + print "usage: synthesize_sources.pl samplerate [session name, the name must match the directory and the .ardour file in it]\n"; + exit; +} + +my $sessionFile = $sessionName."/".$sessionName.".ardour"; + + +my $handler = new ARDOUR::SourceInfoLoader($sessionName); + +my $parser = XML::Parser::PerlSAX->new( Handler => $handler ); + +$parser->parse(Source => { SystemId => $sessionFile }); + +if ( ! -d $sessionName."/interchange" ) { + mkdir $sessionName."/interchange/" || die "couldn't create ".$sessionName."/interchange"; +} + +if ( ! -d $sessionName."/interchange/".$sessionName ) { + mkdir $sessionName."/interchange/".$sessionName || die "couldn't create ".$sessionName."/interchange/".$sessionName; +} + +if ( ! -d $sessionName."/interchange/".$sessionName."/audiofiles" ) { + mkdir $sessionName."/interchange/".$sessionName."/audiofiles" || die "couldn't create ".$sessionName."/interchange/".$sessionName."/audiofiles"; +} + +if ( ! -d $sessionName."/peaks") { + mkdir $sessionName."/peaks/" || die "couldn't create ".$sessionName."/peaks"; +} + +my $audioFileDirectory = $sessionName."/interchange/".$sessionName."/audiofiles"; + +my %sources = %{$handler->{Sources}}; + +foreach my $tmp (keys %sources) { + + print "Generating ".$audioFileDirectory."/".$sources{$tmp}->{name}.".wav\n"; + + system("sox", + "-t", "raw", # /dev/zero is raw :) + "-r", $samplerate, # set sample rate + "-c", "1", # 1 channel + "-b", # input in bytes + "-s", # signed + "/dev/zero", # input signal + + "-w", # output 16 bit + "-t", "wav", # format wav + $audioFileDirectory."/".$sources{$tmp}->{name}, # filename + "trim", "0", $sources{$tmp}->{calculated_length}."s" # trim silence to wanted sample amount + ); + + +} + + + -- cgit v1.2.3