summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-01-28 17:44:13 +0000
committerDavid Robillard <d@drobilla.net>2007-01-28 17:44:13 +0000
commitf9f5ec85fbfd15d0008f70d4185a84eeadfd3891 (patch)
treeadb7e13707b1361604c1ec57c0ea405125a4e98e /tools
parentcd37c36326a165ddf6eb83c176213b0732a6db0d (diff)
Merged with trunk R1393.
git-svn-id: svn://localhost/ardour2/branches/midi@1395 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'tools')
-rw-r--r--tools/ARDOUR/SourceInfoLoader.pm75
-rw-r--r--tools/Spotlight Importer/English.lproj/InfoPlist.stringsbin0 -> 482 bytes
-rw-r--r--tools/Spotlight Importer/English.lproj/schema.stringsbin0 -> 1276 bytes
-rw-r--r--tools/Spotlight Importer/GetMetadataForFile.c56
-rw-r--r--tools/Spotlight Importer/Info.plist87
-rw-r--r--tools/Spotlight Importer/Spotlight Importer.xcodeproj/project.pbxproj275
-rw-r--r--tools/Spotlight Importer/main.c225
-rw-r--r--tools/Spotlight Importer/schema.xml29
-rwxr-xr-xtools/osx_packaging/app_build.rb10
-rw-r--r--tools/osx_packaging/ardour2_mac_ui.rc93
-rwxr-xr-xtools/session_exchange.py856
-rwxr-xr-xtools/synthesize_sources.pl75
12 files changed, 1741 insertions, 40 deletions
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
--- /dev/null
+++ b/tools/Spotlight Importer/English.lproj/InfoPlist.strings
Binary files 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
--- /dev/null
+++ b/tools/Spotlight Importer/English.lproj/schema.strings
Binary files 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 <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+
+/* -----------------------------------------------------------------------------
+ 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 <allattrs> and <displayattrs> elements.
+
+ Add any custom types that your importer requires to the <attributes> element
+
+ <attribute name="com_mycompany_metadatakey" type="CFString" multivalued="true"/>
+
+ ----------------------------------------------------------------------------- */
+
+
+
+/* -----------------------------------------------------------------------------
+ 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+
+ <!--
+ If your application does not already define a UTI, you may want to declare it
+ here, so that your documents are recognized by systems which do not have your
+ application installed.
+
+ To export this declaration, fill in the fields with your application's
+ information, and uncomment the block of XML.
+ -->
+
+ <!--
+ <key>UTExportedTypeDeclarations</key>
+ <array>
+ <dict>
+ <key>UTTypeIdentifier</key>
+ <string>org.ardour.yourUTI</string>
+ <key>UTTypeReferenceURL</key>
+ <string>http://www.ardour.org</string>
+ <key>UTTypeDescription</key>
+ <string>Your Document Kind String</string>
+ <key>UTTypeConformsTo</key>
+ <array>
+ <string>public.data</string>
+ <string>public.content</string>
+ </array>
+ <key>UTTypeTagSpecification</key>
+ <dict>
+ <key>com.apple.ostype</key>
+ <string>XXXX</string>
+ <key>public.filename-extension</key>
+ <array>
+ <string>xxxx</string>
+ </array>
+ </dict>
+ </dict>
+ </array>
+ -->
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>MDImporter</string>
+ <key>LSItemContentTypes</key>
+ <array>
+ <string>SUPPORTED_UTI_TYPE</string>
+ </array>
+ </dict>
+ </array>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.yourcfbundle</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CFPlugInDynamicRegisterFunction</key>
+ <string></string>
+ <key>CFPlugInDynamicRegistration</key>
+ <string>NO</string>
+ <key>CFPlugInFactories</key>
+ <dict>
+ <key>D77F8126-18F0-4ADE-917C-4A234A5590B9</key>
+ <string>MetadataImporterPluginFactory</string>
+ </dict>
+ <key>CFPlugInTypes</key>
+ <dict>
+ <key>8B08C4BF-415B-11D8-B3F9-0003936726FC</key>
+ <array>
+ <string>D77F8126-18F0-4ADE-917C-4A234A5590B9</string>
+ </array>
+ </dict>
+ <key>CFPlugInUnloadFunction</key>
+ <string></string>
+</dict>
+</plist>
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 = "<group>"; };
+ 08FB77B6FE84183AC02AAC07 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+ 2C05A19B06CAA52B00D84F6F /* GetMetadataForFile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = GetMetadataForFile.c; sourceTree = "<group>"; };
+ 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 = "<group>"; };
+ C86B05260671AA6E00DD9006 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
+ C88FB7D7067446EC006EBB30 /* schema.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = schema.xml; sourceTree = "<group>"; };
+ C88FB7DB0674470F006EBB30 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/schema.strings; sourceTree = "<group>"; };
+/* 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 = "<group>";
+ };
+ 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ C86B05260671AA6E00DD9006 /* CoreServices.framework */,
+ 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 089C167CFE841241C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ C88FB7E30674480E006EBB30 /* schema.strings */,
+ C88FB7D7067446EC006EBB30 /* schema.xml */,
+ 8D576317048677EA00EA77CD /* Info.plist */,
+ 8D5B49A704867FD3000E48DA /* InfoPlist.strings */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 08FB77AFFE84173DC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 2C05A19B06CAA52B00D84F6F /* GetMetadataForFile.c */,
+ 08FB77B6FE84183AC02AAC07 /* main.c */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 19C28FB6FE9D52B211CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D576316048677EA00EA77CD /* Spotlight Importer.mdimporter */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* 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 = "<group>";
+ };
+ C88FB7E30674480E006EBB30 /* schema.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ C88FB7DB0674470F006EBB30 /* English */,
+ );
+ name = schema.strings;
+ sourceTree = "<group>";
+ };
+/* 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 <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFPlugInCOM.h>
+#include <CoreServices/CoreServices.h>
+
+// -----------------------------------------------------------------------------
+// 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<schema version="1.0" xmlns="http://www.apple.com/metadata"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.apple.com/metadata file:///System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Resources/MetadataSchema.xsd">
+ <note>
+ Custom attributes that this metadata importer supports. Below
+ is an example of a multivalued string attribute. Other types
+ are CFNumber, CFDate, CFBoolean and CFData.
+ </note>
+ <attributes>
+ <attribute name="com_Foo_YourAttrName" multivalued="true" type="CFString"/>
+ </attributes>
+
+ <types>
+ <type name="SUPPORTED_UTI_TYPE">
+ <note>
+ The keys that this metadata importer handles.
+ </note>
+ <allattrs>
+ com_Foo_YourAttrName
+ </allattrs>
+ <displayattrs>
+ com_Foo_YourAttrName
+ </displayattrs>
+ </type>
+ </types>
+</schema>
+
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, '<Branch>'),
+ ('/File/_Add Session...','<control>A', self.add_session_cb, 0, ''),
+ ('/File/Create _Session...', '<control>S', self.create_session_cb, 0, ''),
+ ('/File/sep1', None, None, 0, '<Separator>'),
+ ('/File/_Quit', '<control>Q', gtk.main_quit, 0, '<StockItem>', gtk.STOCK_QUIT),
+ ('/_Edit', None, None, 0, '<Branch>' ),
+ ('/Edit/Cu_t', '<control>X', self.menuitem_cb, 0, '<StockItem>', gtk.STOCK_CUT),
+ ('/Edit/_Copy', '<control>C', self.menuitem_cb, 0, '<StockItem>', gtk.STOCK_COPY),
+ ('/Edit/_Paste', '<control>V', self.menuitem_cb, 0, '<StockItem>', gtk.STOCK_PASTE),
+ ('/Edit/_Delete', None, self.delete_cb, 0, '<StockItem>', gtk.STOCK_DELETE),
+ ('/Edit/sep1', None, None, 0, '<Separator>'),
+ ('/Edit/Add Colla_borator...','<control>B', self.add_collaborator_cb,0,''),
+ ('/Edit/_Fetch Snapshot','<control>F', self.fetch_snapshot_cb,0,''),
+ ('/Edit/sep1', None, None, 0, '<Separator>'),
+ ('/Edit/_Preferences...','<control>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, '<main>', accel_group)
+ self.item_factory.create_items(menu_items, self.window)
+ main_box.pack_start(self.item_factory.get_widget('<main>'), 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 <port number> 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
+ );
+
+
+}
+
+
+