summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-06-09 02:18:57 +0000
committerDavid Robillard <d@drobilla.net>2006-06-09 02:18:57 +0000
commit2f0e092964f800c0ff82cbd08bf2ee05db814e7b (patch)
treed35a09dc50535aae9292f8ca3262adc5526fe2a6
downloadpatchage-2f0e092964f800c0ff82cbd08bf2ee05db814e7b.tar.gz
patchage-2f0e092964f800c0ff82cbd08bf2ee05db814e7b.tar.bz2
patchage-2f0e092964f800c0ff82cbd08bf2ee05db814e7b.zip
Added patchage
git-svn-id: http://svn.drobilla.net/lad/patchage@5 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--AUTHORS4
-rw-r--r--ChangeLog365
-rw-r--r--Doxyfile1153
-rw-r--r--Makefile.am4
-rw-r--r--NEWS42
-rw-r--r--README1
-rw-r--r--THANKS12
-rw-r--r--aclocal.m41007
-rwxr-xr-xautogen.sh6
-rw-r--r--configure.ac117
-rw-r--r--src/AlsaDriver.cpp484
-rw-r--r--src/AlsaDriver.h72
-rw-r--r--src/Driver.h55
-rw-r--r--src/JackDriver.cpp258
-rw-r--r--src/JackDriver.h68
-rw-r--r--src/LashDriver.cpp146
-rw-r--r--src/LashDriver.h50
-rw-r--r--src/Makefile.am27
-rw-r--r--src/Patchage.cpp411
-rw-r--r--src/Patchage.h116
-rw-r--r--src/PatchageFlowCanvas.cpp117
-rw-r--r--src/PatchageFlowCanvas.h49
-rw-r--r--src/PatchageModule.h120
-rw-r--r--src/PatchagePort.h66
-rw-r--r--src/StateManager.cpp246
-rw-r--r--src/StateManager.h75
-rw-r--r--src/main.cpp49
-rw-r--r--src/patchage.glade607
-rw-r--r--src/patchage.gladep9
29 files changed, 5736 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..d4d803b
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Author:
+
+Dave Robillard <drobilla@connect.carleton.ca>
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..488fc55
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,365 @@
+2005-08-29 13:54 drobilla
+
+ * ChangeLog, NEWS, configure.ac, src/PatchagePatchBayArea.cpp:
+ Fixed "Disconnect All" for real this time
+
+2005-08-23 05:06 drobilla
+
+ * src/: StateManager.cpp, canvas/PatchBayArea.cpp: Fixed blatant
+ guaranteed segfault (shame)
+
+2005-08-19 21:51 drobilla
+
+ * src/canvas/Module.cpp: Added middle click to show Node Control
+ Window, until scrolling actually works
+
+2005-08-19 21:30 drobilla
+
+ * src/canvas/: Connection.cpp, Connection.h, Module.cpp, Module.h,
+ PatchBayArea.cpp, PatchBayArea.h, Port.cpp, Port.h: Updated
+ Copyright year in comment header
+
+2005-08-19 18:48 drobilla
+
+ * src/canvas/: Module.cpp, Module.h: - Response time tuning in the
+ Gtk client - Segfault fixed in engine (destroy patch and other
+ recursive events)
+
+2005-08-17 20:45 drobilla
+
+ * NEWS, configure.ac, src/AlsaDriver.cpp, src/Patchage.cpp,
+ src/PatchageModule.h, src/main.cpp: - Upped version number -
+ Fixed building without LASH (--disable-lash)
+
+2005-08-17 15:43 drobilla
+
+ * src/canvas/: Module.cpp, Module.h: Added ability to show control
+ windows for DSSI plugins (in addition to the plugin's GUI)
+
+2005-08-15 15:50 drobilla
+
+ * src/canvas/PatchBayArea.cpp: Fixed add pluginw window closing
+
+2005-08-14 16:24 drobilla
+
+ * src/canvas/: PatchBayArea.cpp, Port.cpp, Port.h: Added port
+ hiliting on mouse hover
+
+2005-08-08 23:38 drobilla
+
+ * src/canvas/: PatchBayArea.cpp, PatchBayArea.h: - Added patch
+ description and author (client-side only) - Reduced heavy
+ dependancy on PatchModel.h in GTK client
+
+2005-08-06 15:01 drobilla
+
+ * src/: AlsaDriver.cpp, JackDriver.cpp, Patchage.cpp,
+ PatchageModule.h: Fixed problem with randomly moving modules when
+ moving others
+
+2005-08-05 19:06 drobilla
+
+ * src/canvas/: PatchBayArea.cpp, PatchBayArea.h: Fixed subpatch
+ path problem by adding a patch path config option to the client.
+ More testing and better default values required..
+
+2005-05-29 17:11 drobilla
+
+ * .tm_project.cache, src/.PatchageModule.h.swp: Removed
+ accidentally checked in files
+
+2005-05-29 17:08 drobilla
+
+ * .tm_project.cache, AUTHORS, Makefile.am, NEWS, README, THANKS,
+ autogen.sh, configure.ac, ChangeLog, src/PatchageModule.h,
+ src/AlsaDriver.cpp, src/JackDriver.cpp,
+ src/.PatchageModule.h.swp, src/AlsaDriver.h, src/JackDriver.h,
+ src/LashController.cpp, src/LashController.h, src/Makefile.am,
+ src/Patchage.cpp, src/Patchage.h, src/PatchagePatchBayArea.cpp,
+ src/PatchagePatchBayArea.h, src/PatchagePort.h,
+ src/StateManager.cpp, src/StateManager.h, src/main.cpp,
+ src/patchage.glade, src/patchage.gladep: Added patchage module to
+ repository
+
+2005-05-29 17:08 drobilla
+
+ * .tm_project.cache, AUTHORS, Makefile.am, NEWS, README, THANKS,
+ autogen.sh, configure.ac, ChangeLog, src/PatchageModule.h,
+ src/AlsaDriver.cpp, src/JackDriver.cpp,
+ src/.PatchageModule.h.swp, src/AlsaDriver.h, src/JackDriver.h,
+ src/LashController.cpp, src/LashController.h, src/Makefile.am,
+ src/Patchage.cpp, src/Patchage.h, src/PatchagePatchBayArea.cpp,
+ src/PatchagePatchBayArea.h, src/PatchagePort.h,
+ src/StateManager.cpp, src/StateManager.h, src/main.cpp,
+ src/patchage.glade, src/patchage.gladep: Initial revision
+
+2005-05-28 12:44 drobilla
+
+ * src/canvas/: Module.cpp, PatchBayArea.cpp, PatchBayArea.h: Failed
+ attempt at middle-dragging on canvas to scroll.
+
+2005-05-07 22:25 drobilla
+
+ * src/canvas/: Module.cpp, Module.h, PatchBayArea.cpp,
+ PatchBayArea.h, Port.cpp, Port.h: - Fixed problem with slow
+ events depending on each other (ie create patch immediately
+ followed by add node, add node used to fail if patch event
+ wasn't finished yet) - Patch specific enable/disable - Vastly
+ improved patch loading (faster, better) - Updated canvas widget
+ to new Patchage version - Numerous bugfixes - Fixed HORRIBLE
+ problem with OSC communication (sending notifications to
+ clients many, many times, etc) - About 900 other things I've
+ probably forgotten. This commit is too big - Fixed race issue
+ with jack ports introduced by above. May be more...
+
+2005-04-18 02:29 drobilla
+
+ * src/canvas/Makefile.am: Fixed File->Close on patch windows to
+ actually work
+
+2005-04-15 17:39 drobilla
+
+ * src/canvas/Module.cpp: Fixed bug when removing connected
+ input/output nodes
+
+2005-04-13 00:22 drobilla
+
+ * src/canvas/Module.cpp: Fixed some bugs introduced in the last few
+ committs (mostly subpatch related)
+
+2005-04-12 22:37 drobilla
+
+ * src/canvas/: Module.cpp, Module.h, PatchBayArea.cpp,
+ PatchBayArea.h, Port.cpp, Port.h: Made patch loading about 5
+ times as fast, as the expense of anti aliasing :(
+
+2005-03-30 01:05 drobilla
+
+ * src/canvas/: Module.cpp, Module.h: Fixed placement of loaded
+ subpatches' modules, cleaned up some other things in the process.
+
+2005-03-29 20:40 drobilla
+
+ * src/canvas/: Module.cpp, Module.h: - Numerous bugfixes - Fixed
+ removal of connected subpatches - Vastly improved
+ DisconnectAllEvent as a consequence of above - Improved gtk
+ client communication stuff - still too slow though
+
+2005-03-27 19:36 drobilla
+
+ * src/canvas/Module.cpp: - disconnect_all command - Removing of
+ connected nodes - Minor documentation updates
+
+2005-03-26 20:36 drobilla
+
+ * src/canvas/Module.cpp: - Fixed loading patches saved as mono as
+ polyphonic pathches - Sped up client side event stuff using lock
+ free queue instead of std::queue - Fixed a segfault on patch load
+ (and other events) - Changed Queue API to match that of
+ std::queue
+
+2005-03-21 20:46 drobilla
+
+ * src/canvas/PatchBayArea.cpp: Added individual ALSA Midi port for
+ each patch.
+
+2005-03-16 20:49 drobilla
+
+ * src/canvas/: Module.cpp, Module.h: - Proper subpatch module port
+ removal - Proper subpatch deletion - Minor optimizations and
+ de-braindead-izing of client
+
+2005-03-16 00:22 drobilla
+
+ * src/canvas/PatchBayArea.cpp: - Patch control-rate inputs and
+ outputs - One or two minor GUI tweaks
+
+2005-03-12 01:27 drobilla
+
+ * src/canvas/PatchBayArea.cpp: Fixed up the new shinier connection
+ stuff, it was messed up
+
+2005-03-11 18:44 drobilla
+
+ * src/canvas/: Connection.cpp, Connection.h, Module.cpp, Module.h,
+ PatchBayArea.cpp, PatchBayArea.h, Port.cpp, Port.h: Some GUI
+ shinification, arrow on drag connections, snap to port, etc.
+
+2005-03-10 19:18 drobilla
+
+ * src/canvas/: Module.cpp, Module.h, PatchBayArea.cpp, Port.cpp,
+ Port.h: Cleaned up API of patch bay widget.
+
+2005-03-10 18:12 drobilla
+
+ * src/canvas/: Connection.cpp, Connection.h, Module.cpp, Module.h,
+ PatchBayArea.cpp, PatchBayArea.h, Port.cpp, Port.h: Finished
+ namespace-izing everything and some documentation updates.
+
+2005-02-27 20:37 drobilla
+
+ * src/canvas/PatchBayArea.cpp: - More work on subpatching (almost
+ done!) - Made /om/send_all_objects not block the OSC thread and
+ eat CPU - GUI enhancements (better load patch dialogs, etc) -
+ Patch ports now take name of OutputNode (so user can define port
+ names)
+
+2005-02-27 15:15 drobilla
+
+ * src/canvas/: Module.cpp, PatchBayArea.cpp: - Cleaned out
+ remainder of old MIDI binding cruft - Numerous GUI enhancements
+ (double clicking, etc) - More path-related bugfixes
+
+2005-02-09 12:18 drobilla
+
+ * src/canvas/Makefile.am: - Fixed problem with plugins sometimes
+ not showing up in Load Plugin window - Revamped OSC->Gtk event
+ stuff, much cleaner and should be significantly faster now too
+
+2005-02-01 17:59 drobilla
+
+ * src/canvas/: Canvas.cpp, Canvas.h, CanvasController.h,
+ CanvasStateManager.h, Connection.cpp, Makefile.am, Module.cpp,
+ Module.h, PatchBayArea.cpp, PatchBayArea.h, Port.cpp, Port.h,
+ constants.h: - Cleaned up much code in the GUI - Removed redudant
+ files/classes - Cleaned up the canvas widget for use by other
+ apps (ie Patchage)
+
+2005-01-26 20:37 drobilla
+
+ * src/canvas/: Connection.cpp, Connection.h, Module.cpp, Module.h,
+ PatchBayArea.cpp, Port.cpp, Port.h: - Pretty crucial node
+ removing bug fix - Better solution to the connection/node-remove
+ lock problem - GUI visual tweaks (modules, etc)
+
+2005-01-25 13:07 drobilla
+
+ * src/canvas/PatchBayArea.cpp: - Fixed many bugs - Re-enabled MIDI
+ trigger node
+
+2005-01-23 18:23 drobilla
+
+ * src/canvas/: Module.cpp, Module.h, PatchBayArea.cpp,
+ PatchBayArea.h, Port.h: - Bugfixes - Made the engine capable of
+ handingg lots (and lots) of incoming connections etc (ie in the
+ case of Patch Loading, which was always pretty random until
+ now) - Switched the canvas stuff from using vectors to using map
+ like they obviously should (searching by name and all) - Kinda
+ sorta support for the client launching the engine, but not
+ really. :)
+
+2005-01-22 21:45 drobilla
+
+ * src/canvas/: Module.h, PatchBayArea.cpp, Port.cpp: - OSC
+ communication stuff converging on the final solution, I think...
+ - Started work on client being able to reattach to running server
+ - MIDI bindings now update control sliders in control dialog -
+ Um.. bunch of other stuff. It's 6am, I can't remember. ;)
+
+2005-01-20 18:27 drobilla
+
+ * src/canvas/: Module.cpp, Module.h, PatchBayArea.cpp,
+ PatchBayArea.h, README: Partially through the reworking of the
+ OSC communication stuff (finally!) Multiple client support almost
+ a reality Added simple om_patch_loader command line client MIDI
+ Binding saving Made controls in patch file part of a "preset"
+ Added preliminary concept of metadata
+
+2005-01-18 20:26 drobilla
+
+ * src/canvas/Module.h: - MIDI binding range changing support
+
+2005-01-17 19:35 drobilla
+
+ * src/canvas/: Module.cpp, Module.h, PatchBayArea.cpp,
+ PatchBayArea.h, Port.cpp, Port.h: - Preliminary MIDI binding (no
+ learn yet) - Minor refactoring everywhere - Some work on
+ subpatching, still not working though
+
+2005-01-11 18:50 drobilla
+
+ * src/canvas/: CanvasController.h, Module.cpp, Module.h,
+ PatchBayArea.cpp, PatchBayArea.h, Port.cpp, Port.h: - Proper
+ voice stealing for polyphony - Multiple top-level patch support -
+ Fixed patch loading/saving - Added polyphonic information to
+ patch loading/saving
+
+2005-01-07 18:33 drobilla
+
+ * src/canvas/: CanvasController.h, Module.cpp, Module.h,
+ PatchBayArea.cpp, PatchBayArea.h: - LOTS of changes, mostly
+ toward subpatching - Patch loading currently broken - Refactored
+ canvas widget API - Separated connection logic in engine - More
+
+2004-12-06 06:06 drobilla
+
+ * src/canvas/Makefile.in: Removed a bunch of generated files from
+ CVS to make incoming patches manageable.
+
+2004-11-24 16:03 drobilla
+
+ * src/canvas/: Connection.h, Module.cpp, Module.h,
+ PatchBayArea.cpp, PatchBayArea.h, Port.cpp, Port.h: - More work
+ on the event system - Created node tree, nodes in patch now
+ stored in one - Node adding now event-ized. Still has some
+ problems but you can add a node while the patch is running -
+ Lots of cleanup work in the PatchBayArea canvas widget
+
+2004-11-21 10:11 drobilla
+
+ * src/canvas/PatchBayArea.cpp: - Added support for patch destroying
+ in both engine and gtk client
+
+2004-11-19 18:25 drobilla
+
+ * src/canvas/: PatchBayArea.cpp, PatchBayArea.h: Node removing
+ support.
+
+2004-11-19 15:14 drobilla
+
+ * src/canvas/: CanvasController.h, PatchBayArea.cpp,
+ PatchBayArea.h: Added support for disconnecting, numerous other
+ fixes.
+
+2004-11-15 19:19 drobilla
+
+ * src/canvas/: Module.cpp, Module.h, PatchBayArea.cpp: Moved patch
+ loading stuff (PatchLibrarian) from gtk client to libomclient, so
+ all clients can use it.
+
+ Did some more generic-izing of the client stuff, and separated
+ the control of the client from the status updates from the engine
+ (ie so multiple clients can control one engine and reflect each
+ other's changes)
+
+ This that and the other thing..
+
+2004-11-06 09:15 drobilla
+
+ * src/canvas/: Module.cpp, Module.h, PatchBayArea.cpp,
+ PatchBayArea.h, Port.h: - More client fixes, connections now work
+ again - Replaced lots of #includes with forward class
+ declarations - reduces compile time drastically - More cleanups
+
+2004-11-05 20:15 drobilla
+
+ * src/canvas/: CanvasController.h, CanvasStateManager.h,
+ Connection.h, Makefile.am, Makefile.in, Module.cpp, Module.h,
+ ModuleBox.cpp, ModuleBox.h, PatchBayArea.cpp, PatchBayArea.h,
+ Port.cpp, Port.h: Refactored om_gtk to facilitate multiple open
+ patch windows (eventually). Many other changes, cleanups, API
+ changes, etc.
+
+2004-11-01 07:05 drobilla
+
+ * src/canvas/: PatchBayArea.cpp, PatchBayArea.h: Added preliminary
+ MIDI trigger node, added audio in node, minor cleanup.
+
+2004-10-29 16:10 drobilla
+
+ * src/canvas/: Canvas.cpp, Canvas.h, CanvasController.h,
+ CanvasStateManager.h, Connection.cpp, Connection.h, Makefile.am,
+ Makefile.in, Module.cpp, Module.h, ModuleBox.cpp, ModuleBox.h,
+ PatchBayArea.cpp, PatchBayArea.h, Port.cpp, Port.h, README,
+ constants.h: Initial checkin.
+
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..cfc321a
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1153 @@
+# Doxyfile 1.3.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Om
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.0.1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of source
+# files, where putting all generated files in the same directory would otherwise
+# cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is used
+# as the annotated text. Otherwise, the brief description is used as-is. If left
+# blank, the following values are used ("$name" is automatically replaced with the
+# name of the entity): "The $name class" "The $name widget" "The $name file"
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = src
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes that
+# lay further from the root node will be omitted. Note that setting this option to
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that a graph may be further truncated if the graph's image dimensions are
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..2ca5b07
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = src
+
+doc: Doxyfile src/*.h src/*.cpp
+ doxygen
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..3e4ef45
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,42 @@
+Patchage NEWS file
+
+0.2.4:
+ * Multiple module selection/moving
+
+0.2.3:
+ * Updated LASH support for LASH 0.5.0
+ * Smarter module creation (modules not split unecessarily)
+
+0.2.2:
+ * Fixed blatant segfault bug (0.2.1 is unusable)
+
+0.2.1:
+ * Fixed "disconnect all" not working for Jack ports
+ * Minor GUI aesthetic improvements
+ * Preliminary LASH support
+
+0.2.0:
+ * Added ALSA midi patching
+ * Numerous crashes fixed
+ * Canvas widget overhauled (because of Om)
+
+0.1.0:
+ * Fixed refresh segfault problem properly, shouldn't be any more segfaults
+ * Added connection hiliting, mouse over a port and it's connections hilite
+ * Added drag-to-make-connection, Pd style
+
+0.0.4:
+ * You can now load patchage without installing (run from src directory)
+ * Fixed numerous bugs (segfaults)
+
+0.0.3:
+ * UI enhancements (switched UI to libglade)
+ * code cleanup (heavy overhaul)
+ * state saving (window location/size, modules location/size)
+ * put actual content in NEWS, ChangeLog, etc
+
+0.0.2:
+ * zoom support
+
+0.0.1:
+ * initial release
diff --git a/README b/README
new file mode 100644
index 0000000..1d43beb
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+This is Patchage, a modular patch bay for Jack audio and Alsa Midi.
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..06d8783
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,12 @@
+- Robert Ham
+ - For alsa-patch-bay and jack-patch-bay, which much code
+ was.... influenced.... by.. :)
+
+- Alessandro Cominu ("Comix")
+ - Thought of the zoom idea
+
+- Steve Harris
+ - Many good ideas, bug reports
+
+- pasp@ll.pl (?)
+ - Bug reports, ideas
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..bc2e921
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,1007 @@
+# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$PKG_CONFIG"; then
+ if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ else
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+ [pkg_failed=yes])
+ fi
+else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+ [$4])
+elif test $pkg_failed = untried; then
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])],
+ [$4])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION so it can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+ [AM_AUTOMAKE_VERSION([1.9.6])])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 7
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])
+AC_SUBST([$1_FALSE])
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 3
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 12
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.58])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+# test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $1 | $1:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
+#
+# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
+# created by `make install' are always world readable, even if the
+# installer happens to have an overly restrictive umask (e.g. 077).
+# This was a mistake. There are at least two reasons why we must not
+# use `-m 0755':
+# - it causes special bits like SGID to be ignored,
+# - it may be too restrictive (some setups expect 775 directories).
+#
+# Do not use -m 0755 and let people choose whatever they expect by
+# setting umask.
+#
+# We cannot accept any implementation of `mkdir' that recognizes `-p'.
+# Some implementations (such as Solaris 8's) are not thread-safe: if a
+# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
+# concurrently, both version can detect that a/ is missing, but only
+# one can create it and the other will error out. Consequently we
+# restrict ourselves to GNU make (using the --version option ensures
+# this.)
+AC_DEFUN([AM_PROG_MKDIR_P],
+[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ # We used to keeping the `.' as first argument, in order to
+ # allow $(mkdir_p) to be used without argument. As in
+ # $(mkdir_p) $(somedir)
+ # where $(somedir) is conditionally defined. However this is wrong
+ # for two reasons:
+ # 1. if the package is installed by a user who cannot write `.'
+ # make install will fail,
+ # 2. the above comment should most certainly read
+ # $(mkdir_p) $(DESTDIR)$(somedir)
+ # so it does not work when $(somedir) is undefined and
+ # $(DESTDIR) is not.
+ # To support the latter case, we have to write
+ # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+ # so the `.' trick is pointless.
+ mkdir_p='mkdir -p --'
+else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ for d in ./-p ./--version;
+ do
+ test -d $d && rmdir $d
+ done
+ # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+ if test -f "$ac_aux_dir/mkinstalldirs"; then
+ mkdir_p='$(mkinstalldirs)'
+ else
+ mkdir_p='$(install_sh) -d'
+ fi
+fi
+AC_SUBST([mkdir_p])])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..68d4273
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+aclocal-1.9
+autoheader -Wall
+automake-1.9 --gnu --add-missing -Wall
+autoconf -Wall
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..2e0c9cd
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,117 @@
+# configure.in for patchage
+
+AC_INIT(patchage, 0.2.4pre, drobilla@connect.carleton.ca)
+AC_CONFIG_SRCDIR([src/main.cpp])
+AC_CONFIG_HEADER([config.h])
+AM_INIT_AUTOMAKE
+
+# Checks for compilers
+AC_PROG_CXX
+
+# Check other stuff..
+AC_TYPE_SIZE_T
+AC_CHECK_FUNCS([strerror])
+
+# Check for pthreads
+AC_CHECK_LIB(pthread, pthread_create, [],
+ AC_MSG_ERROR([*** Patchage requires POSIX threads support]))
+AC_CHECK_HEADER([pthread.h])
+
+# Check for FlowCanvas
+PKG_CHECK_MODULES(FLOWCANVAS, flowcanvas >= 0.1.0)
+AC_SUBST(FLOWCANVAS_CFLAGS)
+AC_SUBST(FLOWCANVAS_LIBS)
+
+# Check for Jack
+PKG_CHECK_MODULES(JACK, jack >= 0.100.0)
+
+# Check for ALSA
+enable_alsa="yes"
+AC_ARG_ENABLE(alsa,
+[AS_HELP_STRING(--enable-alsa, [Enable Alsa MIDI driver (yes)])],
+[ enable_alsa="$enableval" ]
+)
+
+if test "$enable_alsa" = "yes"; then
+ AC_CHECK_LIB(asound, snd_seq_open, ALSA_FOUND="yes", ALSA_FOUND="no", -lm -ldl -lpthread)
+
+ if test "$ALSA_FOUND" = "yes"; then
+ AC_DEFINE(HAVE_ALSA, 1, [whether or not we have alsa])
+ ALSA_CFLAGS=""
+ ALSA_LIBS="-lasound -lm -ldl -lpthread"
+ AC_SUBST(ALSA_CFLAGS)
+ AC_SUBST(ALSA_LIBS)
+ fi
+else
+ ALSA_FOUND="no"
+fi
+AM_CONDITIONAL(ALSA, test "$ALSA_FOUND" = "yes")
+
+# LASH config option
+build_lash="yes"
+AC_ARG_ENABLE(lash,
+ [AS_HELP_STRING(--enable-lash, [Enable LASH session management support (yes)])],
+ [ if test x$enable_lash = xno ; then build_lash=no ; fi ])
+
+have_lash="no"
+if test "$build_lash" = "yes"; then
+ PKG_CHECK_MODULES(LASH, lash-1.0 >= 0.5.0, have_lash="yes", have_lash="no")
+fi
+if test "$have_lash" = "yes"; then
+ AC_DEFINE(HAVE_LASH, 1, [Has lash.h])
+ AC_SUBST(LASH_CFLAGS)
+ AC_SUBST(LASH_LIBS)
+else
+ AC_MSG_WARN([LASH not found, session support will not be built.])
+fi
+AM_CONDITIONAL(WITH_LASH, [test "$have_lash" = "yes"])
+
+
+# Check for debugging flag
+debug="no"
+AC_ARG_ENABLE(debug,
+ [AS_HELP_STRING(--enable-debug, [Enable debugging (no)])],
+ [debug="$enableval"])
+if test "$debug" = "yes"; then
+ # Useless POS gnomecanvasmm doesn't build w/ -pedantic
+ CFLAGS="-O1 -g -DDEBUG"
+ CXXFLAGS="$CFLAGS"
+else
+ CFLAGS="$CFLAGS -DNDEBUG"
+ CXXFLAGS="$CFLAGS -DNDEBUG"
+fi
+
+# Check for strict flag
+strict="no"
+AC_ARG_ENABLE(strict,
+ [AS_HELP_STRING(--enable-strict, [Enable strict compiler warnings or errors (no)])],
+ [strict="$enableval"])
+if test "$strict" = "yes"; then
+ # Useless POS gnomecanvasmm doesn't build w/ -pedantic
+ CFLAGS="$CFLAGS -ansi -Wall -Wconversion -Winit-self"
+ CXXFLAGS="$CXXFLAGS -ansi -Wall -Wconversion -Winit-self -Woverloaded-virtual -Wsign-promo"
+fi
+
+# Bolt on a few specific flags to CXXFLAGS that should always be used
+CXXFLAGS="$CXXFLAGS -pipe -Wall -fmessage-length=139 -fdiagnostics-show-location=every-line"
+CFLAGS="$CFLAGS -pipe -Wall -fmessage-length=139 -fdiagnostics-show-location=every-line"
+
+# Check for GTKMM
+PKG_CHECK_MODULES(GTKMM, gtkmm-2.4)
+AC_SUBST(GTKMM_CFLAGS)
+AC_SUBST(GTKMM_LIBS)
+
+# Check for gnomecanvasmm
+PKG_CHECK_MODULES(GNOMECANVASMM, libgnomecanvasmm-2.6)
+AC_SUBST(GNOMECANVASMM_CFLAGS)
+AC_SUBST(GNOMECANVASMM_LIBS)
+
+# Check for libglademm
+PKG_CHECK_MODULES(LIBGLADEMM, libglademm-2.4)
+AC_SUBST(LIBGLADEMM_CFLAGS)
+AC_SUBST(LIBGLADEMM_LIBS)
+
+# Write it!
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([src/Makefile])
+AC_OUTPUT
diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp
new file mode 100644
index 0000000..2f4d52e
--- /dev/null
+++ b/src/AlsaDriver.cpp
@@ -0,0 +1,484 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string>
+#include <iostream>
+#include <cassert>
+#include <sys/poll.h>
+#include <errno.h>
+#include "PatchageFlowCanvas.h"
+#include "AlsaDriver.h"
+#include "Patchage.h"
+#include "PatchageModule.h"
+#include "PatchagePort.h"
+
+using std::cerr;
+using std::string;
+
+
+using namespace LibFlowCanvas;
+
+AlsaDriver::AlsaDriver(Patchage* app)
+: m_app(app),
+ m_canvas(app->canvas()),
+ m_seq(NULL)
+{
+}
+
+
+AlsaDriver::~AlsaDriver()
+{
+ detach();
+}
+
+
+/** Attach to ALSA.
+ * @a launch_daemon is ignored, as ALSA has no daemon to launch/connect to.
+ */
+void
+AlsaDriver::attach(bool launch_daemon)
+{
+ cout << "Connecting to Alsa... ";
+ cout.flush();
+
+ int ret = snd_seq_open(&m_seq, "default",
+ SND_SEQ_OPEN_DUPLEX,
+ SND_SEQ_NONBLOCK);
+ if (ret) {
+ cout << "Failed" << endl;
+ m_seq = NULL;
+ } else {
+ cout << "Connected" << endl;
+
+ snd_seq_set_client_name(m_seq, "Patchage");
+
+ ret = pthread_create(&m_refresh_thread, NULL, &AlsaDriver::refresh_main, this);
+ if (ret)
+ cerr << "Couldn't start refresh thread" << endl;
+ }
+}
+
+
+void
+AlsaDriver::detach()
+{
+ if (m_seq != NULL) {
+ pthread_cancel(m_refresh_thread);
+ pthread_join(m_refresh_thread, NULL);
+ snd_seq_close(m_seq);
+ m_seq = NULL;
+ cout << "Disconnected from Alsa" << endl;
+ }
+}
+
+
+/** Refresh all Alsa Midi ports and connections.
+ */
+void
+AlsaDriver::refresh()
+{
+ if (!is_attached())
+ return;
+
+ assert(m_seq);
+
+ refresh_ports();
+ refresh_connections();
+
+ undirty();
+}
+
+
+/** Refresh all Alsa Midi ports.
+ */
+void
+AlsaDriver::refresh_ports()
+{
+ assert(is_attached());
+ assert(m_seq);
+
+ snd_seq_client_info_t* cinfo;
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_client_info_set_client(cinfo, -1);
+
+ snd_seq_port_info_t * pinfo;
+ snd_seq_port_info_alloca(&pinfo);
+
+ string client_name;
+ string port_name;
+ bool is_input = false;
+ bool is_duplex = false;
+ bool is_application = true;
+
+ while (snd_seq_query_next_client (m_seq, cinfo) >= 0) {
+ snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
+ snd_seq_port_info_set_port(pinfo, -1);
+
+ client_name = snd_seq_client_info_get_name(cinfo);
+
+ while (snd_seq_query_next_port(m_seq, pinfo) >= 0) {
+ int caps = snd_seq_port_info_get_capability(pinfo);
+ int type = snd_seq_port_info_get_type(pinfo);
+
+ // Skip ports we shouldn't show
+ if (caps & SND_SEQ_PORT_CAP_NO_EXPORT)
+ continue;
+ else if ( !( (caps & SND_SEQ_PORT_CAP_READ)
+ || (caps & SND_SEQ_PORT_CAP_WRITE)
+ || (caps & SND_SEQ_PORT_CAP_DUPLEX)))
+ continue;
+ else if ((snd_seq_client_info_get_type(cinfo) != SND_SEQ_USER_CLIENT)
+ && ((type == SND_SEQ_PORT_SYSTEM_TIMER
+ || type == SND_SEQ_PORT_SYSTEM_ANNOUNCE)))
+ continue;
+
+ const snd_seq_addr_t addr = *snd_seq_port_info_get_addr(pinfo);
+
+ is_duplex = false;
+
+ // FIXME: Should be CAP_SUBS_READ etc?
+ if ((caps & SND_SEQ_PORT_CAP_READ) && (caps & SND_SEQ_PORT_CAP_WRITE))
+ is_duplex = true;
+ else if (caps & SND_SEQ_PORT_CAP_READ)
+ is_input = false;
+ else if (caps & SND_SEQ_PORT_CAP_WRITE)
+ is_input = true;
+
+ is_application = (type & SND_SEQ_PORT_TYPE_APPLICATION);
+ port_name = snd_seq_port_info_get_name(pinfo);
+ PatchageModule* m = NULL;
+
+ //cout << client_name << " : " << port_name << " is_application = " << is_application
+ // << " is_duplex = " << is_duplex << endl;
+
+ bool split = m_app->state_manager()->get_module_split(client_name, !is_application);
+
+ // Application input/output ports go on the same module
+ if (!split) {
+ m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput);
+ if (m == NULL) {
+ m = new PatchageModule(m_app, client_name, InputOutput);
+ m->load_location();
+ m->store_location();
+ m_canvas->add_module(m);
+ }
+
+ if (!is_duplex) {
+ m->add_patchage_port(port_name, is_input, ALSA_MIDI, addr);
+ } else {
+ m->add_patchage_port(port_name, true, ALSA_MIDI, addr);
+ m->add_patchage_port(port_name, false, ALSA_MIDI, addr);
+ }
+ } else { // non-application input/output ports (hw interface, etc) go on separate modules
+ PatchageModule* m = NULL;
+ ModuleType type = InputOutput;
+
+ // The 'application' hint isn't always set by clients, so this bit
+ // is pretty nasty...
+
+ if (!is_duplex) { // just one port to add
+ if (is_input) type = Input;
+ else type = Output;
+
+ // See if an InputOutput module exists (maybe with Jack ports on it)
+ m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput);
+
+ if (m == NULL)
+ m = (PatchageModule*)m_canvas->find_module(client_name, type);
+ if (m == NULL) {
+ m = new PatchageModule(m_app, client_name, type);
+ m->load_location();
+ m->store_location();
+ m_canvas->add_module(m);
+ }
+ m->add_patchage_port(port_name, is_input, ALSA_MIDI, addr);
+ } else { // two ports to add
+ type = Input;
+
+ // See if an InputOutput module exists (maybe with Jack ports on it)
+ m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput);
+
+ if (m == NULL)
+ m = (PatchageModule*)m_canvas->find_module(client_name, type);
+ if (m == NULL) {
+ m = new PatchageModule(m_app, client_name, type);
+ m->load_location();
+ m->store_location();
+ m_canvas->add_module(m);
+ }
+ m->add_patchage_port(port_name, true, ALSA_MIDI, addr);
+
+ type = Output;
+
+ // See if an InputOutput module exists (maybe with Jack ports on it)
+ m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput);
+
+ if (m == NULL)
+ m = (PatchageModule*)m_canvas->find_module(client_name, type);
+ if (m == NULL) {
+ m = new PatchageModule(m_app, client_name, type);
+ m->load_location();
+ m->store_location();
+ m_canvas->add_module(m);
+ }
+ m->add_patchage_port(port_name, false, ALSA_MIDI, addr);
+ }
+ }
+ }
+ }
+}
+
+
+/** Refresh all Alsa Midi connections.
+ */
+void
+AlsaDriver::refresh_connections()
+{
+ assert(is_attached());
+ assert(m_seq);
+
+ PatchageModule* m = NULL;
+ PatchagePort* p = NULL;
+
+ for (ModuleMap::iterator i = m_canvas->modules().begin();
+ i != m_canvas->modules().end(); ++i) {
+ m = (PatchageModule*)((*i).second);
+ for (PortList::iterator j = m->ports().begin(); j != m->ports().end(); ++j) {
+ p = (PatchagePort*)(*j);
+ if (p->type() == ALSA_MIDI)
+ add_connections(p);
+ }
+ }
+}
+
+
+/** Add all connections for the given port.
+ */
+void
+AlsaDriver::add_connections(PatchagePort* port)
+{
+ assert(is_attached());
+ assert(m_seq);
+
+ const snd_seq_addr_t* addr = port->alsa_addr();
+ PatchagePort* connected_port = NULL;
+
+ // Fix a problem with duplex->duplex connections (would show up twice)
+ // No sense doing them all twice anyway..
+ if (port->is_input())
+ return;
+
+ snd_seq_query_subscribe_t* subsinfo;
+ snd_seq_query_subscribe_alloca(&subsinfo);
+ snd_seq_query_subscribe_set_root(subsinfo, addr);
+ snd_seq_query_subscribe_set_index(subsinfo, 0);
+
+ while(!snd_seq_query_port_subscribers(m_seq, subsinfo)) {
+ const snd_seq_addr_t* connected_addr = snd_seq_query_subscribe_get_addr(subsinfo);
+
+ connected_port = m_canvas->find_port(connected_addr, !port->is_input());
+
+ if (connected_port != NULL) {
+ m_canvas->add_connection(port, connected_port);
+ }
+
+ snd_seq_query_subscribe_set_index(subsinfo, snd_seq_query_subscribe_get_index(subsinfo) + 1);
+ }
+
+}
+
+
+/** Connects two Alsa Midi ports.
+ *
+ * \return Whether connection succeeded.
+ */
+bool
+AlsaDriver::connect(const PatchagePort* const src_port, const PatchagePort* const dst_port)
+{
+ const snd_seq_addr_t* src = src_port->alsa_addr();
+ const snd_seq_addr_t* dst = dst_port->alsa_addr();
+
+ bool result = false;
+
+ if (src && dst) {
+ snd_seq_port_subscribe_t* subs;
+ snd_seq_port_subscribe_malloc(&subs);
+ snd_seq_port_subscribe_set_sender(subs, src);
+ snd_seq_port_subscribe_set_dest(subs, dst);
+ snd_seq_port_subscribe_set_exclusive(subs, 0);
+ snd_seq_port_subscribe_set_time_update(subs, 0);
+ snd_seq_port_subscribe_set_time_real(subs, 0);
+
+ // Already connected (shouldn't happen)
+ if (!snd_seq_get_port_subscription(m_seq, subs)) {
+ cerr << "Error: Attempt to subscribe Alsa ports that are already subscribed." << endl;
+ result = false;
+ }
+
+ int ret = snd_seq_subscribe_port(m_seq, subs);
+ if (ret < 0) {
+ cerr << "Alsa subscription failed: " << snd_strerror(ret) << endl;
+ result = false;
+ }
+ }
+
+ return (!result);
+}
+
+
+/** Disconnects two Alsa Midi ports.
+ *
+ * \return Whether disconnection succeeded.
+ */
+bool
+AlsaDriver::disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port)
+{
+ const snd_seq_addr_t* src = src_port->alsa_addr();
+ const snd_seq_addr_t* dst = dst_port->alsa_addr();
+
+ bool result = false;
+
+ snd_seq_port_subscribe_t* subs;
+ snd_seq_port_subscribe_malloc(&subs);
+ snd_seq_port_subscribe_set_sender(subs, src);
+ snd_seq_port_subscribe_set_dest(subs, dst);
+ snd_seq_port_subscribe_set_exclusive(subs, 0);
+ snd_seq_port_subscribe_set_time_update(subs, 0);
+ snd_seq_port_subscribe_set_time_real(subs, 0);
+
+ // Not connected (shouldn't happen)
+ if (snd_seq_get_port_subscription(m_seq, subs) != 0) {
+ cerr << "Error: Attempt to unsubscribe Alsa ports that are not subscribed." << endl;
+ result = false;
+ }
+
+ int ret = snd_seq_unsubscribe_port(m_seq, subs);
+ if (ret < 0) {
+ cerr << "Alsa unsubscription failed: " << snd_strerror(ret) << endl;
+ result = false;
+ }
+
+ return (!result);
+}
+
+
+bool
+AlsaDriver::create_refresh_port()
+{
+ // Mostly lifted from alsa-patch-bay, (C) 2002 Robert Ham, released under GPL
+
+ int ret;
+ snd_seq_port_info_t* port_info;
+
+ snd_seq_port_info_alloca(&port_info);
+ snd_seq_port_info_set_name(port_info, "System Announcement Reciever");
+ snd_seq_port_info_set_capability(port_info,
+ SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE|SND_SEQ_PORT_CAP_NO_EXPORT);
+
+ snd_seq_port_info_set_type(port_info, SND_SEQ_PORT_TYPE_APPLICATION);
+
+ ret = snd_seq_create_port(m_seq, port_info);
+ if (ret) {
+ cerr << "Error creating alsa port: " << snd_strerror(ret) << endl;
+ return false;
+ }
+
+ // Subscribe the port to the system announcer
+ ret = snd_seq_connect_from(m_seq,
+ snd_seq_port_info_get_port(port_info),
+ SND_SEQ_CLIENT_SYSTEM,
+ SND_SEQ_PORT_SYSTEM_ANNOUNCE);
+
+ if (ret) {
+ cerr << "Could not connect to system announcer port: " << snd_strerror(ret) << endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+void*
+AlsaDriver::refresh_main(void* me)
+{
+ AlsaDriver* ad = (AlsaDriver*)me;
+ ad->m_refresh_main();
+ return NULL;
+}
+
+
+void
+AlsaDriver::m_refresh_main()
+{
+ // "Heavily influenced" from alsa-patch-bay
+ // (C) 2002 Robert Ham, released under GPL
+
+ int ret;
+ int nfds = snd_seq_poll_descriptors_count(m_seq, POLLIN);
+ struct pollfd* pfds = new struct pollfd[nfds];
+ unsigned short* revents = new unsigned short[nfds];
+
+ if (!create_refresh_port()) {
+ cerr << "Could not create Alsa listen port. Auto refreshing will not work." << endl;
+ return;
+ }
+
+ snd_seq_poll_descriptors(m_seq, pfds, nfds, POLLIN);
+
+ while (true) {
+ ret = poll(pfds, nfds, -1);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+
+ cerr << "Error polling Alsa sequencer: " << strerror(errno) << endl;
+ continue;
+ }
+
+ ret = snd_seq_poll_descriptors_revents(m_seq, pfds, nfds, revents);
+ if (ret) {
+ cerr << "Error getting Alsa sequencer poll events: "
+ << snd_strerror(ret) << endl;
+ continue;
+ }
+
+ for (int i = 0; i < nfds; ++i) {
+ if (revents[i] > 0) {
+ snd_seq_event_t* ev;
+ snd_seq_event_input(m_seq, &ev);
+
+ if (ev == NULL)
+ continue;
+
+ switch (ev->type) {
+ case SND_SEQ_EVENT_RESET:
+ case SND_SEQ_EVENT_CLIENT_START:
+ case SND_SEQ_EVENT_CLIENT_EXIT:
+ case SND_SEQ_EVENT_CLIENT_CHANGE:
+ case SND_SEQ_EVENT_PORT_START:
+ case SND_SEQ_EVENT_PORT_EXIT:
+ case SND_SEQ_EVENT_PORT_CHANGE:
+ case SND_SEQ_EVENT_PORT_SUBSCRIBED:
+ case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
+ m_is_dirty = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/src/AlsaDriver.h b/src/AlsaDriver.h
new file mode 100644
index 0000000..d6e910f
--- /dev/null
+++ b/src/AlsaDriver.h
@@ -0,0 +1,72 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef ALSADRIVER_H
+#define ALSADRIVER_H
+
+#include <iostream>
+#include <alsa/asoundlib.h>
+#include <pthread.h>
+#include <queue>
+#include <string>
+#include "Driver.h"
+class Patchage;
+class PatchagePort;
+class PatchageFlowCanvas;
+
+using std::queue; using std::string;
+
+
+/** Handles all externally driven functionality, registering ports etc.
+ */
+class AlsaDriver : public Driver
+{
+public:
+ AlsaDriver(Patchage* app);
+ ~AlsaDriver();
+
+ void attach(bool launch_daemon = false);
+ void detach();
+
+ bool is_attached() const { return (m_seq != NULL); }
+
+ void refresh();
+
+ bool connect(const PatchagePort* const src_port, const PatchagePort* const dst_port);
+ bool disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port);
+
+ PatchageFlowCanvas* canvas() { return m_canvas; }
+
+private:
+ void refresh_ports();
+ void refresh_connections();
+
+ void add_connections(PatchagePort* port);
+
+ bool create_refresh_port();
+ static void* refresh_main(void* me);
+ void m_refresh_main();
+
+ Patchage* m_app;
+ PatchageFlowCanvas* m_canvas;
+
+ snd_seq_t* m_seq;
+
+ pthread_t m_refresh_thread;
+};
+
+
+#endif // ALSADRIVER_H
diff --git a/src/Driver.h b/src/Driver.h
new file mode 100644
index 0000000..43b919a
--- /dev/null
+++ b/src/Driver.h
@@ -0,0 +1,55 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+class PatchagePort;
+
+/** Trival driver base class */
+class Driver {
+public:
+ virtual ~Driver() {}
+
+ virtual void attach(bool launch_daemon) = 0;
+ virtual void detach() = 0;
+ virtual bool is_attached() const = 0;
+
+ virtual void refresh() = 0;
+
+ virtual bool connect(const PatchagePort* src_port,
+ const PatchagePort* dst_port)
+ { return false; }
+
+ virtual bool disconnect(const PatchagePort* src_port,
+ const PatchagePort* dst_port)
+ { return false; }
+
+ /** Returns whether or not a refresh is required. */
+ bool is_dirty() const { return m_is_dirty; }
+
+ /** Clear 'dirty' status after a refresh. */
+ void undirty() { m_is_dirty = false; }
+
+protected:
+ Driver() : m_is_dirty(false) {}
+
+ bool m_is_dirty;
+};
+
+
+#endif // DRIVER_H
+
diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp
new file mode 100644
index 0000000..5bb084e
--- /dev/null
+++ b/src/JackDriver.cpp
@@ -0,0 +1,258 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <cassert>
+#include <cstring>
+#include <string>
+#include <iostream>
+#include <jack/jack.h>
+#include "PatchageFlowCanvas.h"
+#include "JackDriver.h"
+#include "Patchage.h"
+#include "PatchageModule.h"
+
+using std::cerr; using std::endl; using std::cout;
+using std::string;
+
+using namespace LibFlowCanvas;
+
+
+JackDriver::JackDriver(Patchage* app)
+: m_app(app),
+ m_canvas(app->canvas()),
+ m_client(NULL)
+{
+}
+
+
+JackDriver::~JackDriver()
+{
+ detach();
+}
+
+
+/** Connect to Jack.
+ */
+void
+JackDriver::attach(bool launch_daemon)
+{
+ cout << "Connecting to Jack... ";
+ cout.flush();
+
+ if (m_client != NULL) {
+ cout << "already connected. " << endl;
+ return;
+ }
+
+ jack_options_t options = (!launch_daemon) ? JackNoStartServer : JackNullOption;
+ m_client = jack_client_open("Patchage", options, NULL);
+ if (m_client == NULL) {
+ cout << "Failed" << endl;
+ } else {
+ jack_set_port_registration_callback(m_client, jack_port_registration_cb, this);
+ jack_set_graph_order_callback(m_client, jack_graph_order_cb, this);
+ jack_on_shutdown(m_client, jack_shutdown_cb, this);
+
+ jack_activate(m_client);
+
+ cout << "Connected" << endl;
+
+ m_canvas->destroy();
+
+ m_is_dirty = true;
+ }
+}
+
+
+void
+JackDriver::detach()
+{
+ if (m_client != NULL) {
+ jack_deactivate(m_client);
+ jack_client_close(m_client);
+ m_client = NULL;
+ cout << "Disconnected from Jack" << endl;
+ }
+}
+
+
+/** Refresh all Jack audio ports/connections.
+ * To be called from GTK thread only.
+ */
+void
+JackDriver::refresh()
+{
+ if (m_client == NULL)
+ return;
+
+ const char** ports;
+ jack_port_t* port;
+
+ ports = jack_get_ports(m_client, NULL, NULL, 0); // get all existing ports
+
+ string client1_name;
+ string port1_name;
+ string client2_name;
+ string port2_name;
+ PatchageModule* m = NULL;
+
+ // Add all ports
+ if (ports != NULL)
+ for (int i=0; ports[i]; ++i) {
+ port = jack_port_by_name(m_client, ports[i]);
+ client1_name = ports[i];
+ client1_name = client1_name.substr(0, client1_name.find(":"));
+
+ ModuleType type = InputOutput;
+ //if (m_app->state_manager()->get_module_split(client1_name)
+ // || jack_port_flags(port) & JackPortIsTerminal) {
+ if (m_app->state_manager()->get_module_split(client1_name,
+ (jack_port_flags(port) & JackPortIsTerminal))) {
+ if (jack_port_flags(port) & JackPortIsInput) {
+ type = Input;
+ } else {
+ type = Output;
+ }
+ }
+
+ m = (PatchageModule*)m_canvas->find_module(client1_name, type);
+
+ if (m == NULL) {
+ m = new PatchageModule(m_app, client1_name, type);
+ m->load_location();
+ m->store_location();
+ m_canvas->add_module(m);
+ }
+
+ // FIXME: leak? jack docs don't say
+ const char* const type_str = jack_port_type(port);
+ PortType port_type = JACK_AUDIO;
+ if (!strcmp(type_str, "8 bit raw midi"))
+ port_type = JACK_MIDI;
+
+ m->add_patchage_port(jack_port_short_name(port),
+ (jack_port_flags(port) & JackPortIsInput),
+ port_type);
+ }
+
+ // Add all connections
+ if (ports != NULL) {
+ for (int i=0; ports[i]; ++i) {
+ port = jack_port_by_name(m_client, ports[i]);
+ const char** connected_ports = jack_port_get_all_connections(m_client, port);
+
+ if (connected_ports != NULL)
+ for (int j=0; connected_ports[j]; ++j) {
+ client1_name = ports[i];
+ port1_name = client1_name.substr(client1_name.find(':')+1);
+ client1_name = client1_name.substr(0, client1_name.find(':'));
+
+ client2_name = connected_ports[j];
+ port2_name = client2_name.substr(client2_name.find(':')+1);
+ client2_name = client2_name.substr(0, client2_name.find(':'));
+
+ m_canvas->add_connection(client1_name, port1_name, client2_name, port2_name);
+ }
+ free(connected_ports);
+ }
+ free(ports);
+ }
+
+ undirty();
+}
+
+
+/** Connects two Jack audio ports.
+ * To be called from GTK thread only.
+ * \return Whether connection succeeded.
+ */
+bool
+JackDriver::connect(const PatchagePort* const src_port, const PatchagePort* const dst_port)
+{
+ if (m_client == NULL)
+ return false;
+
+ int result = jack_connect(m_client, src_port->full_name().c_str(), dst_port->full_name().c_str());
+
+ string msg;
+
+ if (result == 0) {
+ msg = "Successfully connected jack ports";
+ } else {
+ msg = "Unable to connect ";
+ msg += src_port->full_name() + " -> " + dst_port->full_name();
+ }
+ m_app->status_message(msg);
+
+ return (!result);
+}
+
+
+/** Disconnects two Jack audio ports.
+ * To be called from GTK thread only.
+ * \return Whether disconnection succeeded.
+ */
+bool
+JackDriver::disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port)
+{
+ if (m_client == NULL)
+ return false;
+
+ int result = jack_disconnect(m_client, src_port->full_name().c_str(), dst_port->full_name().c_str());
+
+ string msg;
+
+ if (result == 0) {
+ msg = "Successfully disconnected jack ports";
+ } else {
+ msg = "Unable to disconnect ";
+ msg += src_port->full_name() + " -> " + dst_port->full_name();
+ }
+ m_app->status_message(msg);
+
+ return (!result);
+}
+
+
+void
+JackDriver::jack_port_registration_cb(jack_port_id_t port_id, int registered, void* me)
+{
+ assert(me != NULL);
+ assert(((JackDriver*)me)->m_client != NULL);
+ ((JackDriver*)me)->m_is_dirty = true;
+}
+
+
+int
+JackDriver::jack_graph_order_cb(void* me)
+{
+ assert(me != NULL);
+ assert(((JackDriver*)me)->m_client != NULL);
+ ((JackDriver*)me)->m_is_dirty = true;
+
+ return 0;
+}
+
+
+void
+JackDriver::jack_shutdown_cb(void* me)
+{
+ assert(me != NULL);
+ ((JackDriver*)me)->m_client = NULL;
+ ((JackDriver*)me)->m_is_dirty = true;
+}
+
+
diff --git a/src/JackDriver.h b/src/JackDriver.h
new file mode 100644
index 0000000..6b69900
--- /dev/null
+++ b/src/JackDriver.h
@@ -0,0 +1,68 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef JACKDRIVER_H
+#define JACKDRIVER_H
+
+#include <iostream>
+#include <jack/jack.h>
+#include <string>
+#include "Driver.h"
+class Patchage;
+class PatchageFlowCanvas;
+class PatchagePort;
+
+using std::string;
+
+
+/** Handles all externally driven functionality, registering ports etc.
+ *
+ * Jack callbacks and connect methods and things like that live here.
+ * Right now just for jack ports, but that will change...
+ */
+class JackDriver : public Driver
+{
+public:
+ JackDriver(Patchage* app);
+ ~JackDriver();
+
+ void attach(bool launch_daemon);
+ void detach();
+
+ bool is_attached() const { return (m_client != NULL); }
+ void refresh();
+
+ bool connect(const PatchagePort* const src_port, const PatchagePort* const dst_port);
+ bool disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port);
+ /*bool connect(const string& src_module_name, const string& src_port_name,
+ const string& dst_module_name, const string& dest_port_name);
+
+ bool disconnect(const string& src_module_name, const string& src_port_name,
+ const string& dst_module_name, const string& dest_port_name);*/
+
+private:
+ Patchage* m_app;
+ PatchageFlowCanvas* m_canvas;
+
+ jack_client_t* m_client;
+
+ static void jack_port_registration_cb(jack_port_id_t port_id, int registered, void* controller);
+ static int jack_graph_order_cb(void* controller);
+ static void jack_shutdown_cb(void* controller);
+};
+
+
+#endif // JACKDRIVER_H
diff --git a/src/LashDriver.cpp b/src/LashDriver.cpp
new file mode 100644
index 0000000..c4a89b2
--- /dev/null
+++ b/src/LashDriver.cpp
@@ -0,0 +1,146 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "LashDriver.h"
+#include "config.h"
+#include <iostream>
+#include <string>
+#include "Patchage.h"
+#include "StateManager.h"
+
+using std::cerr; using std::cout; using std::endl;
+using std::string;
+
+
+LashDriver::LashDriver(Patchage* app, int argc, char** argv)
+: m_app(app),
+ m_client(NULL),
+ m_args(NULL)
+{
+ m_args = lash_extract_args(&argc, &argv);
+}
+
+
+LashDriver::~LashDriver()
+{
+ if (m_args)
+ lash_args_destroy(m_args);
+}
+
+
+void
+LashDriver::attach(bool launch_daemon)
+{
+ cout << "Connecting to Lash... ";
+ cout.flush();
+
+ if (m_client != NULL) {
+ cout << "already connected." << endl;
+ return;
+ }
+
+ int lash_flags = LASH_Config_File;
+ if (launch_daemon)
+ lash_flags |= LASH_No_Start_Server;
+ m_client = lash_init(m_args, PACKAGE_NAME, lash_flags, LASH_PROTOCOL(2, 0));
+ if (m_client == NULL) {
+ cout << "Failed. Session management will not occur." << endl;
+ } else {
+ lash_event_t* event = lash_event_new_with_type(LASH_Client_Name);
+ lash_event_set_string(event, "Patchage");
+ lash_send_event(m_client, event);
+ cout << "Connected" << endl;
+ }
+}
+
+
+void
+LashDriver::detach()
+{
+ // FIXME: send some notification that we're gone??
+ m_client = NULL;
+ cout << "Disconnected from Lash" << endl;
+}
+
+
+void
+LashDriver::process_events()
+{
+ lash_event_t* ev = NULL;
+ lash_config_t* conf = NULL;
+
+ // Process events
+ while ((ev = lash_get_event(m_client)) != NULL) {
+ handle_event(ev);
+ lash_event_destroy(ev);
+ }
+
+ // Process configs
+ while ((conf = lash_get_config(m_client)) != NULL) {
+ handle_config(conf);
+ lash_config_destroy(conf);
+ }
+}
+
+
+void
+LashDriver::handle_event(lash_event_t* ev)
+{
+ LASH_Event_Type type = lash_event_get_type(ev);
+ const char* c_str = lash_event_get_string(ev);
+ string str = (c_str == NULL) ? "" : c_str;
+
+ //cout << "[LashDriver] LASH Event. Type = " << type << ", string = " << str << "**********" << endl;
+
+ if (type == LASH_Save_File) {
+ //cout << "[LashDriver] LASH Save File - " << str << endl;
+ m_app->store_window_location();
+ m_app->state_manager()->save(str.append("/locations"));
+ lash_send_event(m_client, lash_event_new_with_type(LASH_Save_File));
+ } else if (type == LASH_Restore_File) {
+ //cout << "[LashDriver] LASH Restore File - " << str << endl;
+ m_app->state_manager()->load(str.append("/locations"));
+ m_app->update_state();
+ lash_send_event(m_client, lash_event_new_with_type(LASH_Restore_File));
+ } else if (type == LASH_Save_Data_Set) {
+ //cout << "[LashDriver] LASH Save Data Set - " << endl;
+
+ // Tell LASH we're done
+ lash_send_event(m_client, lash_event_new_with_type(LASH_Save_Data_Set));
+ } else if (type == LASH_Quit) {
+ //stop_thread();
+ m_client = NULL;
+ m_app->quit();
+ }
+}
+
+
+void
+LashDriver::handle_config(lash_config_t* conf)
+{
+ const char* key = NULL;
+ const void* val = NULL;
+ size_t val_size = 0;
+
+ //cout << "[LashDriver] LASH Config. Key = " << key << endl;
+
+ key = lash_config_get_key(conf);
+ val = lash_config_get_value(conf);
+ val_size = lash_config_get_value_size(conf);
+}
+
+
+
diff --git a/src/LashDriver.h b/src/LashDriver.h
new file mode 100644
index 0000000..742c249
--- /dev/null
+++ b/src/LashDriver.h
@@ -0,0 +1,50 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef LASHDRIVER_H
+#define LASHDRIVER_H
+
+#include <lash/lash.h>
+#include "Driver.h"
+
+class Patchage;
+
+class LashDriver : public Driver
+{
+public:
+ LashDriver(Patchage* app, int argc, char** argv);
+ ~LashDriver();
+
+ void attach(bool launch_daemon);
+ void detach();
+
+ bool is_attached() const { return lash_enabled(m_client); }
+
+ void refresh() {}
+
+ void process_events();
+
+private:
+ Patchage* m_app;
+ lash_client_t* m_client;
+ lash_args_t* m_args;
+
+ void handle_event(lash_event_t* conf);
+ void handle_config(lash_config_t* conf);
+};
+
+
+#endif // LASHDRIVER_H
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..6e6eb5f
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,27 @@
+AM_CXXFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @JACK_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @FLOWCANVAS_CFLAGS@
+patchage_LDADD = @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @JACK_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @FLOWCANVAS_LIBS@
+
+EXTRA_DIST = patchage.gladep
+
+sharefilesdir = $(pkgdatadir)
+dist_sharefiles_DATA = patchage.glade
+
+bin_PROGRAMS = patchage
+patchage_SOURCES = \
+ main.cpp \
+ Patchage.h \
+ Patchage.cpp \
+ StateManager.h \
+ StateManager.cpp \
+ PatchageModule.h \
+ PatchagePort.h \
+ JackDriver.h \
+ JackDriver.cpp \
+ AlsaDriver.h \
+ AlsaDriver.cpp \
+ PatchageFlowCanvas.h \
+ PatchageFlowCanvas.cpp
+
+if WITH_LASH
+patchage_SOURCES += LashDriver.h LashDriver.cpp
+endif
diff --git a/src/Patchage.cpp b/src/Patchage.cpp
new file mode 100644
index 0000000..38d17f7
--- /dev/null
+++ b/src/Patchage.cpp
@@ -0,0 +1,411 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Patchage.h"
+#include "config.h"
+#include <libgnomecanvasmm.h>
+#include <libglademm/xml.h>
+#include <fstream>
+#include <pthread.h>
+#include "StateManager.h"
+#include "PatchageFlowCanvas.h"
+#include "AlsaDriver.h"
+#include "JackDriver.h"
+#ifdef HAVE_LASH
+#include "LashDriver.h"
+#endif
+
+
+Patchage::Patchage(int argc, char** argv)
+:
+#ifdef HAVE_LASH
+ m_lash_driver(NULL),
+#endif
+#ifdef HAVE_ALSA
+ m_alsa_driver(NULL),
+#endif
+ m_canvas(NULL),
+ m_jack_driver(NULL),
+ m_state_manager(NULL),
+ m_refresh(false)
+{
+ m_settings_filename = getenv("HOME");
+ m_settings_filename += "/.patchagerc";
+
+ m_state_manager = new StateManager();
+ m_canvas = new PatchageFlowCanvas(this, 1600*2, 1200*2);
+ m_jack_driver = new JackDriver(this);
+#ifdef HAVE_ALSA
+ m_alsa_driver = new AlsaDriver(this);
+#endif
+
+ m_state_manager->load(m_settings_filename);
+
+#ifdef HAVE_LASH
+ m_lash_driver = new LashDriver(this, argc, argv);
+#endif
+
+ Glib::RefPtr<Gnome::Glade::Xml> refXml;
+
+ // Check for the .glade file in current directory
+ string glade_filename = "./patchage.glade";
+ ifstream fs(glade_filename.c_str());
+ if (fs.fail()) { // didn't find it, check PKGDATADIR
+ fs.clear();
+ glade_filename = PKGDATADIR;
+ glade_filename += "/patchage.glade";
+
+ fs.open(glade_filename.c_str());
+ if (fs.fail()) {
+ cerr << "Unable to find patchage.glade in current directory or " << PKGDATADIR << "." << endl;
+ exit(EXIT_FAILURE);
+ }
+ fs.close();
+ }
+
+ try {
+ refXml = Gnome::Glade::Xml::create(glade_filename);
+ } catch(const Gnome::Glade::XmlError& ex) {
+ std::cerr << ex.what() << std::endl;
+ throw;
+ }
+
+ refXml->get_widget("patchage_win", m_main_window);
+ refXml->get_widget("about_win", m_about_window);
+ refXml->get_widget("about_project_label", m_about_project_label);
+ refXml->get_widget("launch_jack_menuitem", m_menu_jack_launch);
+ refXml->get_widget("connect_to_jack_menuitem", m_menu_jack_connect);
+ refXml->get_widget("disconnect_from_jack_menuitem", m_menu_jack_disconnect);
+#ifdef HAVE_LASH
+ refXml->get_widget("launch_lash_menuitem", m_menu_lash_launch);
+ refXml->get_widget("connect_to_lash_menuitem", m_menu_lash_connect);
+ refXml->get_widget("disconnect_from_lash_menuitem", m_menu_lash_disconnect);
+#endif
+#ifdef HAVE_ALSA
+ refXml->get_widget("connect_to_alsa_menuitem", m_menu_alsa_connect);
+ refXml->get_widget("disconnect_from_alsa_menuitem", m_menu_alsa_disconnect);
+#endif
+ refXml->get_widget("file_save_menuitem", m_menu_file_save);
+ refXml->get_widget("file_quit_menuitem", m_menu_file_quit);
+ refXml->get_widget("view_refresh_menuitem", m_menu_view_refresh);
+ refXml->get_widget("help_about_menuitem", m_menu_help_about);
+ refXml->get_widget("canvas_scrolledwindow", m_canvas_scrolledwindow);
+ refXml->get_widget("zoom_scale", m_zoom_slider);
+ refXml->get_widget("about_close_button", m_about_close_button);
+ refXml->get_widget("status_lab", m_status_label);
+
+ m_main_window->resize(
+ static_cast<int>(m_state_manager->get_window_size().x),
+ static_cast<int>(m_state_manager->get_window_size().y));
+
+ m_main_window->move(
+ static_cast<int>(m_state_manager->get_window_location().x),
+ static_cast<int>(m_state_manager->get_window_location().y));
+
+ m_canvas_scrolledwindow->add(*m_canvas);
+ //m_canvas_scrolledwindow->signal_event().connect(sigc::mem_fun(m_canvas, &FlowCanvas::scroll_event_handler));
+ m_canvas->scroll_to(static_cast<int>(m_canvas->width()/2 - 320),
+ static_cast<int>(m_canvas->height()/2 - 240)); // FIXME: hardcoded
+ m_canvas->show();
+
+ // Idle callback, check if we need to refresh (every 250msec)
+ Glib::signal_timeout().connect(sigc::mem_fun(this, &Patchage::idle_callback), 250);
+
+ m_zoom_slider->signal_value_changed().connect( sigc::mem_fun(this, &Patchage::zoom_changed));
+ m_menu_jack_launch->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_jack_launch));
+ m_menu_jack_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_jack_connect));
+ m_menu_jack_disconnect->signal_activate().connect(sigc::mem_fun(this, &Patchage::menu_jack_disconnect));
+#ifdef HAVE_LASH
+ m_menu_lash_launch->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_lash_launch));
+ m_menu_lash_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_lash_connect));
+ m_menu_lash_disconnect->signal_activate().connect(sigc::mem_fun(this, &Patchage::menu_lash_disconnect));
+#endif
+ m_menu_alsa_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_alsa_connect));
+ m_menu_alsa_disconnect->signal_activate().connect(sigc::mem_fun(this, &Patchage::menu_alsa_disconnect));
+ m_menu_file_save->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_file_save));
+ m_menu_file_quit->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_file_quit));
+ m_menu_view_refresh->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_view_refresh));
+ m_menu_help_about->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_help_about));
+ m_about_close_button->signal_clicked().connect( sigc::mem_fun(this, &Patchage::close_about));
+
+ //_about_project_label->use_markup(true);
+ m_about_project_label->set_markup("<span size=\"xx-large\" weight=\"bold\">Patchage " PACKAGE_VERSION "</span>");
+}
+
+
+Patchage::~Patchage()
+{
+#ifdef HAVE_LASH
+ delete m_lash_driver;
+#endif
+ delete m_jack_driver;
+ delete m_alsa_driver;
+ delete m_canvas;
+ delete m_state_manager;
+}
+
+
+void
+Patchage::attach()
+{
+ m_jack_driver->attach(false);
+
+#ifdef HAVE_LASH
+ m_lash_driver->attach(false);
+#endif
+#ifdef HAVE_ALSA
+ m_alsa_driver->attach();
+#endif
+
+ update_menu_items();
+ menu_view_refresh();
+}
+
+
+bool
+Patchage::idle_callback()
+{
+ // FIXME: no need to destroy the whole canvas every time
+ if (m_refresh || (m_jack_driver && m_jack_driver->is_dirty())
+#ifdef HAVE_ALSA
+ || (m_alsa_driver && m_alsa_driver->is_dirty())
+#endif
+ ) {
+ m_canvas->destroy();
+ m_jack_driver->refresh();
+#ifdef HAVE_ALSA
+ m_alsa_driver->refresh();
+#endif
+ update_menu_items();
+ m_refresh = false;
+ }
+
+#ifdef HAVE_LASH
+ if (m_lash_driver->is_attached())
+ m_lash_driver->process_events();
+#endif
+
+ return true;
+}
+
+
+void
+Patchage::zoom_changed()
+{
+ const float z = m_zoom_slider->get_value();
+
+ m_canvas->zoom(z);
+ m_state_manager->set_zoom(z);
+}
+
+
+void
+Patchage::update_state()
+{
+ for (ModuleMap::iterator i = m_canvas->modules().begin(); i != m_canvas->modules().end(); ++i)
+ (*i).second->load_location();
+
+ cerr << "[Patchage] Resizing window: (" << m_state_manager->get_window_size().x
+ << "," << m_state_manager->get_window_size().y << ")" << endl;
+
+ m_main_window->resize(
+ static_cast<int>(m_state_manager->get_window_size().x),
+ static_cast<int>(m_state_manager->get_window_size().y));
+
+ cerr << "[Patchage] Moving window: (" << m_state_manager->get_window_location().x
+ << "," << m_state_manager->get_window_location().y << ")" << endl;
+ m_main_window->move(
+ static_cast<int>(m_state_manager->get_window_location().x),
+ static_cast<int>(m_state_manager->get_window_location().y));
+}
+
+
+void
+Patchage::status_message(const string& msg)
+{
+ m_status_label->set_text(msg);
+}
+
+
+
+
+/** Update the sensitivity status of menus to reflect the present.
+ *
+ * (eg. disable "Connect to Jack" when Patchage is already connected to Jack)
+ */
+void
+Patchage::update_menu_items()
+{
+ // Update Jack menu items
+ const bool jack_attached = m_jack_driver->is_attached();
+ m_menu_jack_launch->set_sensitive(!jack_attached);
+ m_menu_jack_connect->set_sensitive(!jack_attached);
+ m_menu_jack_disconnect->set_sensitive(jack_attached);
+
+ // Update Lash menu items
+#ifdef HAVE_LASH
+ const bool lash_attached = m_lash_driver->is_attached();
+ m_menu_lash_launch->set_sensitive(!lash_attached);
+ m_menu_lash_connect->set_sensitive(!lash_attached);
+ m_menu_lash_disconnect->set_sensitive(lash_attached);
+#endif
+
+#ifdef HAVE_ALSA
+ // Update Alsa menu items
+ const bool alsa_attached = m_alsa_driver->is_attached();
+ m_menu_alsa_connect->set_sensitive(!alsa_attached);
+ m_menu_alsa_disconnect->set_sensitive(alsa_attached);
+#endif
+}
+
+
+void
+Patchage::menu_jack_launch()
+{
+ m_jack_driver->attach(true);
+ update_menu_items();
+}
+
+
+void
+Patchage::menu_jack_connect()
+{
+ m_jack_driver->attach(false);
+ update_menu_items();
+}
+
+
+void
+Patchage::menu_jack_disconnect()
+{
+ m_jack_driver->detach();
+ menu_view_refresh();
+ update_menu_items();
+}
+
+#ifdef HAVE_LASH
+void
+Patchage::menu_lash_launch()
+{
+ m_lash_driver->attach(true);
+ update_menu_items();
+}
+
+
+void
+Patchage::menu_lash_connect()
+{
+ m_lash_driver->attach(false);
+ update_menu_items();
+}
+
+
+void
+Patchage::menu_lash_disconnect()
+{
+ m_lash_driver->detach();
+ update_menu_items();
+}
+#endif
+
+#ifdef HAVE_ALSA
+void
+Patchage::menu_alsa_connect()
+{
+ m_alsa_driver->attach(false);
+ update_menu_items();
+}
+
+
+void
+Patchage::menu_alsa_disconnect()
+{
+ m_alsa_driver->detach();
+ menu_view_refresh();
+ update_menu_items();
+}
+#endif
+
+void
+Patchage::menu_file_save()
+{
+ store_window_location();
+ m_state_manager->save(m_settings_filename);
+}
+
+
+void
+Patchage::menu_file_quit()
+{
+#ifdef HAVE_ALSA
+ m_alsa_driver->detach();
+#endif
+ m_jack_driver->detach();
+ m_main_window->hide();
+}
+
+
+void
+Patchage::menu_view_refresh()
+{
+ assert(m_canvas);
+
+ // FIXME: rebuilding the entire canvas each time is garbage
+ m_canvas->destroy();
+
+ if (m_jack_driver)
+ m_jack_driver->refresh();
+
+#ifdef HAVE_ALSA
+ if (m_alsa_driver)
+ m_alsa_driver->refresh();
+#endif
+}
+
+
+void
+Patchage::menu_help_about()
+{
+ m_about_window->show();
+}
+
+
+void
+Patchage::close_about()
+{
+ m_about_window->hide();
+}
+
+
+/** Update the stored window location and size in the StateManager (in memory).
+ */
+void
+Patchage::store_window_location()
+{
+ int loc_x, loc_y, size_x, size_y;
+ m_main_window->get_position(loc_x, loc_y);
+ m_main_window->get_size(size_x, size_y);
+ Coord window_location;
+ window_location.x = loc_x;
+ window_location.y = loc_y;
+ Coord window_size;
+ window_size.x = size_x;
+ window_size.y = size_y;
+ m_state_manager->set_window_location(window_location);
+ m_state_manager->set_window_size(window_size);
+}
+
+
diff --git a/src/Patchage.h b/src/Patchage.h
new file mode 100644
index 0000000..f686e49
--- /dev/null
+++ b/src/Patchage.h
@@ -0,0 +1,116 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PATCHAGE_H
+#define PATCHAGE_H
+
+#include "config.h"
+#include <string>
+#include <libgnomecanvasmm.h>
+
+using namespace std;
+
+class PatchageFlowCanvas;
+class JackDriver;
+class AlsaDriver;
+class LashDriver;
+class StateManager;
+
+
+class Patchage
+{
+public:
+ Patchage(int argc, char** argv);
+ ~Patchage();
+
+ PatchageFlowCanvas* canvas() { return m_canvas; }
+ StateManager* state_manager() { return m_state_manager; }
+ Gtk::Window* window() { return m_main_window; }
+ JackDriver* jack_driver() { return m_jack_driver; }
+#ifdef HAVE_ALSA
+ AlsaDriver* alsa_driver() { return m_alsa_driver; }
+#endif
+#ifdef HAVE_LASH
+ LashDriver* lash_driver() { return m_lash_driver; }
+#endif
+
+ void attach();
+ void quit() { m_main_window->hide(); }
+
+ void update_state();
+ void store_window_location();
+
+ void status_message(const string& msg);
+ inline void queue_refresh() { m_refresh = true; }
+
+protected:
+ void update_menu_items();
+
+ void menu_jack_launch();
+ void menu_jack_connect();
+ void menu_jack_disconnect();
+ void menu_file_save();
+ void menu_file_quit();
+ void menu_view_refresh();
+ void menu_help_about();
+ void close_about();
+ void zoom_changed();
+ bool idle_callback();
+
+#ifdef HAVE_LASH
+ LashDriver* m_lash_driver;
+ Gtk::MenuItem* m_menu_lash_launch;
+ Gtk::MenuItem* m_menu_lash_connect;
+ Gtk::MenuItem* m_menu_lash_disconnect;
+ void menu_lash_launch();
+ void menu_lash_connect();
+ void menu_lash_disconnect();
+#endif
+
+#ifdef HAVE_ALSA
+ AlsaDriver* m_alsa_driver;
+ Gtk::MenuItem* m_menu_alsa_connect;
+ Gtk::MenuItem* m_menu_alsa_disconnect;
+ void menu_alsa_connect();
+ void menu_alsa_disconnect();
+#endif
+
+ PatchageFlowCanvas* m_canvas;
+ JackDriver* m_jack_driver;
+ StateManager* m_state_manager;
+
+ Gtk::Main* m_gtk_main;
+
+ string m_settings_filename;
+ bool m_refresh;
+
+ Gtk::Window* m_main_window;
+ Gtk::Window* m_about_window;
+ Gtk::Label* m_about_project_label;
+ Gtk::MenuItem* m_menu_jack_launch;
+ Gtk::MenuItem* m_menu_jack_connect;
+ Gtk::MenuItem* m_menu_jack_disconnect;
+ Gtk::MenuItem* m_menu_file_save;
+ Gtk::MenuItem* m_menu_file_quit;
+ Gtk::MenuItem* m_menu_view_refresh;
+ Gtk::MenuItem* m_menu_help_about;
+ Gtk::ScrolledWindow* m_canvas_scrolledwindow;
+ Gtk::HScale* m_zoom_slider;
+ Gtk::Button* m_about_close_button;
+ Gtk::Label* m_status_label;
+};
+
+#endif // PATCHAGE_H
diff --git a/src/PatchageFlowCanvas.cpp b/src/PatchageFlowCanvas.cpp
new file mode 100644
index 0000000..2b9b19d
--- /dev/null
+++ b/src/PatchageFlowCanvas.cpp
@@ -0,0 +1,117 @@
+/* This file is part of Patchage. Copyright (C) 2004 Dave Robillard.
+ *
+ * Patchage is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "PatchageFlowCanvas.h"
+#include "Patchage.h"
+#include "JackDriver.h"
+#include "AlsaDriver.h"
+#include "PatchageModule.h"
+#include "PatchagePort.h"
+
+
+PatchageFlowCanvas::PatchageFlowCanvas(Patchage* app, int width, int height)
+: FlowCanvas(width, height),
+ m_app(app)
+{
+}
+
+
+PatchageModule*
+PatchageFlowCanvas::find_module(const string& name, ModuleType type)
+{
+ PatchageModule* pm = NULL;
+
+ for (ModuleMap::iterator m = m_modules.begin(); m != m_modules.end(); ++m) {
+ pm = (PatchageModule*)(*m).second;
+ if (pm->name() == name && pm->type() == type) {
+ return pm;
+ }
+ }
+
+ return NULL;
+}
+
+
+PatchagePort*
+PatchageFlowCanvas::find_port(const snd_seq_addr_t* alsa_addr, bool is_input)
+{
+ PatchagePort* pp = NULL;
+ for (ModuleMap::iterator m = m_modules.begin(); m != m_modules.end(); ++m) {
+ for (PortList::iterator p = (*m).second->ports().begin(); p != (*m).second->ports().end(); ++p) {
+ pp = (PatchagePort*)(*p);
+ if (pp->type() == ALSA_MIDI && pp->alsa_addr()
+ && pp->alsa_addr()->client == alsa_addr->client
+ && pp->alsa_addr()->port == alsa_addr->port)
+ if (is_input == pp->is_input())
+ return pp;
+ }
+ }
+
+ return NULL;
+}
+
+
+void
+PatchageFlowCanvas::connect(const Port* port1, const Port* port2)
+{
+ PatchagePort* p1 = (PatchagePort*)port1;
+ PatchagePort* p2 = (PatchagePort*)port2;
+
+ if (p1->type() == JACK_AUDIO && p2->type() == JACK_AUDIO
+ || (p1->type() == JACK_MIDI && p2->type() == JACK_MIDI))
+ /*m_app->jack_driver()->connect(p1->module()->name(), p1->name(),
+ p2->module()->name(), p2->name());*/
+ m_app->jack_driver()->connect(p1, p2);
+ else if (p1->type() == ALSA_MIDI && p2->type() == ALSA_MIDI)
+ m_app->alsa_driver()->connect(p1, p2);
+ else
+ m_app->status_message("Cannot make connection, incompatible port types.");
+}
+
+
+void
+PatchageFlowCanvas::disconnect(const Port* port1, const Port* port2)
+{
+ PatchagePort* input = NULL;
+ PatchagePort* output = NULL;
+
+ if (port1->is_input() && !port2->is_input()) {
+ input = (PatchagePort*)port1;
+ output = (PatchagePort*)port2;
+ } else if (port2->is_input() && !port1->is_input()) {
+ input = (PatchagePort*)port2;
+ output = (PatchagePort*)port1;
+ } else {
+ m_app->status_message("Attempt to disconnect two input (or output) ports?? Please report bug.");
+ return;
+ }
+
+ if (input->type() == JACK_AUDIO && output->type() == JACK_AUDIO
+ || input->type() == JACK_MIDI && output->type() == JACK_MIDI)
+ m_app->jack_driver()->disconnect(output, input);
+ else if (input->type() == ALSA_MIDI && output->type() == ALSA_MIDI)
+ m_app->alsa_driver()->disconnect(output, input);
+ else
+ m_app->status_message("Attempt to disconnect Jack audio port from Alsa Midi port?? Please report bug.");
+}
+
+
+void
+PatchageFlowCanvas::status_message(const string& msg)
+{
+ m_app->status_message(msg);
+}
+
diff --git a/src/PatchageFlowCanvas.h b/src/PatchageFlowCanvas.h
new file mode 100644
index 0000000..2636920
--- /dev/null
+++ b/src/PatchageFlowCanvas.h
@@ -0,0 +1,49 @@
+/* This file is part of Patchage. Copyright (C) 2004 Dave Robillard.
+ *
+ * Patchage is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PATCHAGEPATCHBAYAREA_H
+#define PATCHAGEPATCHBAYAREA_H
+
+#include <string>
+#include <alsa/asoundlib.h>
+#include <flowcanvas/FlowCanvas.h>
+#include "StateManager.h"
+class Patchage;
+class PatchageModule;
+class PatchagePort;
+
+using std::string;
+using namespace LibFlowCanvas;
+
+class PatchageFlowCanvas : public FlowCanvas
+{
+public:
+ PatchageFlowCanvas(Patchage* m_app, int width, int height);
+
+ PatchageModule* find_module(const string& name, ModuleType type);
+ PatchagePort* find_port(const snd_seq_addr_t* alsa_addr, bool is_input);
+
+ void connect(const Port* port1, const Port* port2);
+ void disconnect(const Port* port1, const Port* port2);
+
+ void status_message(const string& msg);
+
+private:
+ Patchage* m_app;
+};
+
+
+#endif // PATCHAGEPATCHBAYAREA_H
diff --git a/src/PatchageModule.h b/src/PatchageModule.h
new file mode 100644
index 0000000..b511eec
--- /dev/null
+++ b/src/PatchageModule.h
@@ -0,0 +1,120 @@
+/* This file is part of Patchage. Copyright (C) 2004 Dave Robillard.
+ *
+ * Patchage is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef PATCHAGEMODULE_H
+#define PATCHAGEMODULE_H
+
+#include <string>
+#include <libgnomecanvasmm.h>
+#include <alsa/asoundlib.h>
+#include <flowcanvas/FlowCanvas.h>
+#include <flowcanvas/Module.h>
+#include "PatchageFlowCanvas.h"
+#include "StateManager.h"
+#include "PatchagePort.h"
+
+using std::string; using std::list;
+
+using namespace LibFlowCanvas;
+
+class PatchageModule : public Module
+{
+public:
+ PatchageModule(Patchage* app, const string& title, ModuleType type, double x=0, double y=0)
+ : Module(app->canvas(), title, x, y),
+ m_app(app),
+ m_type(type)
+ {
+ Gtk::Menu::MenuList& items = m_menu.items();
+ if (type == InputOutput) {
+ items.push_back(Gtk::Menu_Helpers::MenuElem("Split",
+ sigc::mem_fun(this, &PatchageModule::split)));
+ } else {
+ items.push_back(Gtk::Menu_Helpers::MenuElem("Join",
+ sigc::mem_fun(this, &PatchageModule::join)));
+ }
+ items.push_back(Gtk::Menu_Helpers::MenuElem("Disconnect All",
+ sigc::mem_fun(this, &PatchageModule::menu_disconnect_all)));
+ }
+
+ virtual ~PatchageModule() { }
+
+ virtual void add_patchage_port(const string& port_name, bool is_input, PortType type)
+ {
+ PatchagePort* port = new PatchagePort(this, type, port_name, is_input,
+ m_app->state_manager()->get_port_color(type));
+
+ Module::add_port(port, true);
+ }
+
+ virtual void add_patchage_port(const string& port_name, bool is_input, PortType type, const snd_seq_addr_t addr)
+ {
+ PatchagePort* port = new PatchagePort(this, type, port_name, is_input,
+ m_app->state_manager()->get_port_color(type));
+
+ port->alsa_addr(addr);
+
+ Module::add_port(port, true);
+ }
+
+
+ virtual void load_location() {
+ Coord loc = m_app->state_manager()->get_module_location(m_name, m_type);
+
+ //cerr << "******" << m_name << " MOVING TO (" << loc.x << "," << loc.y << ")" << endl;
+
+ if (loc.x != -1)
+ move_to(loc.x, loc.y);
+ else
+ move_to((m_canvas->width()/2) - 100 + rand() % 400,
+ (m_canvas->height()/2) - 100 + rand() % 400);
+ }
+
+ void split() {
+ assert(m_type == InputOutput);
+ m_app->state_manager()->set_module_split(m_name, true);
+ m_app->queue_refresh();
+ }
+
+ void join() {
+ assert(m_type != InputOutput);
+ m_app->state_manager()->set_module_split(m_name, false);
+ m_app->queue_refresh();
+ }
+
+ virtual void store_location() {
+ Coord loc = { property_x().get_value(), property_y().get_value() };
+ m_app->state_manager()->set_module_location(m_name, m_type, loc);
+ }
+
+ virtual void show_dialog() {}
+ virtual void on_right_click(GdkEventButton* ev) { m_menu.popup(ev->button, ev->time); }
+ virtual void menu_disconnect_all() {
+ for (PortList::iterator p = m_ports.begin(); p != m_ports.end(); ++p)
+ (*p)->disconnect_all();
+ }
+
+ ModuleType type() { return m_type; }
+
+protected:
+ Patchage* m_app;
+ Gtk::Menu m_menu;
+ ModuleType m_type;
+};
+
+
+#endif // PATCHAGEMODULE_H
diff --git a/src/PatchagePort.h b/src/PatchagePort.h
new file mode 100644
index 0000000..601bce9
--- /dev/null
+++ b/src/PatchagePort.h
@@ -0,0 +1,66 @@
+/* This file is part of Om. Copyright (C) 2004 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef PATCHAGEPORT_H
+#define PATCHAGEPORT_H
+
+#include <string>
+#include <list>
+#include <alsa/asoundlib.h>
+#include <flowcanvas/Port.h>
+#include <flowcanvas/Module.h>
+
+using namespace LibFlowCanvas;
+using std::string; using std::list;
+
+enum PortType { JACK_AUDIO, JACK_MIDI, ALSA_MIDI };
+
+
+/** A Port on a PatchageModule
+ *
+ * \ingroup OmGtk
+ */
+class PatchagePort : public LibFlowCanvas::Port
+{
+public:
+ PatchagePort(LibFlowCanvas::Module* module, PortType type, const string& name, bool is_input, int color)
+ : Port(module, name, is_input, color),
+ m_type(type)
+ {
+ m_alsa_addr.client = '\0';
+ m_alsa_addr.port = '\0';
+ }
+
+ virtual ~PatchagePort() {}
+
+ // FIXME: This driver specific crap really needs to go
+ void alsa_addr(const snd_seq_addr_t addr) { m_alsa_addr = addr; }
+ const snd_seq_addr_t* alsa_addr() const
+ { return (m_type == ALSA_MIDI) ? &m_alsa_addr : NULL; }
+
+ /** Returns the full name of this port, as "modulename:portname" */
+ string full_name() const { return m_module->name() + ":" + m_name; }
+
+ PortType type() const { return m_type; }
+
+private:
+ snd_seq_addr_t m_alsa_addr;
+ PortType m_type;
+};
+
+
+#endif // PATCHAGEPORT_H
diff --git a/src/StateManager.cpp b/src/StateManager.cpp
new file mode 100644
index 0000000..50429e1
--- /dev/null
+++ b/src/StateManager.cpp
@@ -0,0 +1,246 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "StateManager.h"
+#include <stdlib.h>
+#include <iostream>
+#include <fstream>
+#include "Patchage.h"
+
+using std::map; using std::list;
+using std::cerr; using std::cout; using std::endl;
+
+
+StateManager::StateManager()
+{
+ m_window_location.x = 0;
+ m_window_location.y = 0;
+ m_window_size.x = 640;
+ m_window_size.y = 480;
+ m_zoom = 1.0;
+}
+
+
+Coord
+StateManager::get_module_location(const string& name, ModuleType type)
+{
+ for (std::list<ModuleLocation>::iterator i = m_module_locations.begin(); i != m_module_locations.end(); ++i) {
+ if ((*i).name == name && (*i).type == type)
+ return (*i).loc;
+ }
+
+ // -1 used as a flag value
+ Coord r = { -1, -1 };
+ return r;
+}
+
+
+void
+StateManager::set_module_location(const string& name, ModuleType type, Coord loc)
+{
+ for (std::list<ModuleLocation>::iterator i = m_module_locations.begin(); i != m_module_locations.end(); ++i) {
+ if ((*i).name == name && (*i).type == type) {
+ (*i).loc = loc;
+ return;
+ }
+ }
+
+ // If we get here, module isn't in list yet
+ ModuleLocation ml = { name, type, loc };
+ m_module_locations.push_back(ml);
+}
+
+
+/** Returns whether or not this module should be split.
+ *
+ * If nothing is known about the given module, @a default_val is returned (this is
+ * to allow driver's to request terminal ports get split by default).
+ */
+bool
+StateManager::get_module_split(const string& name, bool default_val) const
+{
+ map<string, bool>::const_iterator i = m_module_splits.find(name);
+ if (i == m_module_splits.end())
+ return default_val;
+ else
+ return (*i).second;
+}
+
+
+void
+StateManager::set_module_split(const string& name, bool split)
+{
+ m_module_splits[name] = split;
+}
+
+
+void
+StateManager::load(const string& filename)
+{
+ m_module_locations.clear();
+
+ cerr << "Loading configuration file " << filename << endl;
+
+ std::ifstream is;
+ is.open(filename.c_str(), std::ios::in);
+
+ if ( ! is.good()) {
+ std::cerr << "Unable to load file " << filename << "!" << endl;
+ return;
+ }
+
+ string s;
+
+ is >> s;
+ if (s != "window_location") throw "Corrupt settings file.";
+ is >> s;
+ m_window_location.x = atoi(s.c_str());
+ is >> s;
+ m_window_location.y = atoi(s.c_str());
+
+ is >> s;
+ if (s != "window_size") throw "Corrupt settings file.";
+ is >> s;
+ m_window_size.x = atoi(s.c_str());
+ is >> s;
+ m_window_size.y = atoi(s.c_str());
+
+ is >> s;
+ if (s != "zoom_level") throw "Corrupt settings file.";
+ is >> s;
+ m_zoom = atof(s.c_str());
+
+ ModuleLocation ml;
+ while (1) {
+ is >> s;
+ if (is.eof()) break;
+
+ // Old versions didn't quote, so need to support both :/
+ if (s[0] == '\"') {
+ if (s.length() > 1 && s[s.length()-1] == '\"') {
+ ml.name = s.substr(1, s.length()-2);
+ } else {
+ ml.name = s.substr(1);
+ is >> s;
+ while (s[s.length()-1] != '\"') {
+ ml.name.append(" ").append(s);
+ is >> s;
+ }
+ ml.name.append(" ").append(s.substr(0, s.length()-1));
+ }
+ } else {
+ ml.name = s;
+ }
+
+ is >> s;
+ if (s == "input") ml.type = Input;
+ else if (s == "output") ml.type = Output;
+ else if (s == "inputoutput") ml.type = InputOutput;
+ else throw "Corrupt settings file.";
+
+ is >> s;
+ ml.loc.x = atoi(s.c_str());
+ is >> s;
+ ml.loc.y = atoi(s.c_str());
+
+ m_module_locations.push_back(ml);
+ }
+
+ is.close();
+}
+
+
+void
+StateManager::save(const string& filename)
+{
+ std::ofstream os;
+ os.open(filename.c_str(), std::ios::out);
+
+ os << "window_location " << m_window_location.x << " " << m_window_location.y << std::endl;
+ os << "window_size " << m_window_size.x << " " << m_window_size.y << std::endl;
+ os << "zoom_level " << m_zoom << std::endl;
+
+ ModuleLocation ml;
+ for (std::list<ModuleLocation>::iterator i = m_module_locations.begin(); i != m_module_locations.end(); ++i) {
+ ml = *i;
+ os << "\"" << ml.name << "\"";
+
+ if (ml.type == Input) os << " input ";
+ else if (ml.type == Output) os << " output ";
+ else if (ml.type == InputOutput) os << " inputoutput ";
+ else throw;
+
+ os << ml.loc.x << " " << ml.loc.y << std::endl;
+ }
+
+ os.close();
+}
+
+
+Coord
+StateManager::get_window_location()
+{
+ return m_window_location;
+}
+
+
+void
+StateManager::set_window_location(Coord loc)
+{
+ m_window_location = loc;
+}
+
+
+Coord
+StateManager::get_window_size()
+{
+ return m_window_size;
+}
+
+
+void
+StateManager::set_window_size(Coord size)
+{
+ m_window_size = size;
+}
+
+
+float
+StateManager::get_zoom()
+{
+ return m_zoom;
+}
+
+
+void
+StateManager::set_zoom(float zoom)
+{
+ m_zoom = zoom;
+}
+
+
+int
+StateManager::get_port_color(PortType type)
+{
+ if (type == JACK_AUDIO)
+ return 0x305171FF;
+ else if (type == JACK_MIDI)
+ return 0x663939FF;
+ else if (type == ALSA_MIDI)
+ return 0x307130FF;
+ else
+ return 0xFF0000FF;
+}
diff --git a/src/StateManager.h b/src/StateManager.h
new file mode 100644
index 0000000..b584308
--- /dev/null
+++ b/src/StateManager.h
@@ -0,0 +1,75 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef STATEMANAGER_H
+#define STATEMANAGER_H
+
+#include <string>
+#include <list>
+#include <map>
+#include <iostream>
+#include "PatchagePort.h"
+
+using std::string; using std::list; using std::map;
+
+
+enum ModuleType { Input, Output, InputOutput };
+struct Coord { double x; double y; };
+
+// This should probably be moved out in to a seperate class/file....
+typedef struct ModuleLocation
+{
+ string name;
+ ModuleType type; // for distinguishing terminal modules (input or output)
+ Coord loc;
+};
+
+
+class StateManager
+{
+public:
+ StateManager();
+
+ void load(const string& filename);
+ void save(const string& filename);
+
+ Coord get_module_location(const string& name, ModuleType type);
+ void set_module_location(const string& name, ModuleType type, Coord loc);
+
+ void set_module_split(const string& name, bool split);
+ bool get_module_split(const string& name, bool default_val) const;
+
+ Coord get_window_location();
+ void set_window_location(Coord loc);
+
+ Coord get_window_size();
+ void set_window_size(Coord loc);
+
+ float get_zoom();
+ void set_zoom(float zoom);
+
+ int get_port_color(PortType type);
+
+private:
+ list<ModuleLocation> m_module_locations;
+ map<string,bool> m_module_splits;
+ Coord m_window_location;
+ Coord m_window_size;
+ float m_zoom;
+};
+
+
+#endif // STATEMANAGER_H
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..5646b1c
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,49 @@
+/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <iostream>
+#include <libgnomecanvasmm.h>
+
+#include "Patchage.h"
+#include "JackDriver.h"
+
+#ifdef HAVE_LASH
+#include <lash/lash.h>
+#endif // HAVE_LASH
+
+int main(int argc, char** argv)
+{
+ try {
+
+ Gnome::Canvas::init();
+ Gtk::Main app(argc, argv);
+
+ Patchage patchage(argc, argv);
+ patchage.attach();
+
+ app.run(*patchage.window());
+
+ } catch (std::string msg) {
+ std::cerr << "Caught exception, aborting. Error message was: " << msg << std::endl;
+ return 1;
+ }
+
+ return 0;
+}
+
+
diff --git a/src/patchage.glade b/src/patchage.glade
new file mode 100644
index 0000000..322a714
--- /dev/null
+++ b/src/patchage.glade
@@ -0,0 +1,607 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="patchage_win">
+ <property name="border_width">1</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Patchage</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">640</property>
+ <property name="default_height">480</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="main_vbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkMenuBar" id="menubar">
+ <property name="visible">True</property>
+ <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property>
+ <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="file_menu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="file_menu_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="launch_jack_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Launch Jack</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_launch_jack_menuitem_activate" last_modification_time="Wed, 05 Apr 2006 04:52:35 GMT"/>
+ <accelerator key="J" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image143">
+ <property name="visible">True</property>
+ <property name="stock">gtk-execute</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="connect_to_jack_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Connect to _Jack</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_connect_to_jack_menuitem_activate" last_modification_time="Wed, 05 Apr 2006 04:27:40 GMT"/>
+ <accelerator key="J" modifiers="GDK_MOD1_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image144">
+ <property name="visible">True</property>
+ <property name="stock">gtk-connect</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="disconnect_from_jack_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Disconnect from Jack</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_disconnect_from_jack1_activate" last_modification_time="Sun, 21 May 2006 23:48:26 GMT"/>
+ <accelerator key="J" modifiers="GDK_SHIFT_MASK | GDK_MOD1_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image145">
+ <property name="visible">True</property>
+ <property name="stock">gtk-disconnect</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="launch_lash_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Launch Lash</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_launch_lash1_activate" last_modification_time="Mon, 22 May 2006 01:14:33 GMT"/>
+ <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image146">
+ <property name="visible">True</property>
+ <property name="stock">gtk-execute</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="connect_to_lash_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Connect to _Lash</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_connect_to_lash1_activate" last_modification_time="Mon, 22 May 2006 01:14:33 GMT"/>
+ <accelerator key="L" modifiers="GDK_MOD1_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image147">
+ <property name="visible">True</property>
+ <property name="stock">gtk-connect</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="disconnect_from_lash_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Disconnect from Lash</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_disconnect_from_lash1_activate" last_modification_time="Mon, 22 May 2006 01:14:33 GMT"/>
+ <accelerator key="L" modifiers="GDK_SHIFT_MASK | GDK_MOD1_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image148">
+ <property name="visible">True</property>
+ <property name="stock">gtk-disconnect</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator4">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="connect_to_alsa_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Connect to _Alsa</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_connect_to_alsa_menuitem_activate" last_modification_time="Mon, 22 May 2006 00:10:31 GMT"/>
+ <accelerator key="A" modifiers="GDK_MOD1_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image149">
+ <property name="visible">True</property>
+ <property name="stock">gtk-connect</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="disconnect_from_alsa_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Disconnect from Alsa</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_disconnect_from_alsa_menuitem_activate" last_modification_time="Mon, 22 May 2006 00:10:31 GMT"/>
+ <accelerator key="A" modifiers="GDK_SHIFT_MASK | GDK_MOD1_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image150">
+ <property name="visible">True</property>
+ <property name="stock">gtk-disconnect</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator3">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="file_save_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Store Positions</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_save_settings1_activate" last_modification_time="Mon, 13 Sep 2004 02:42:14 GMT"/>
+ <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image151">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator2">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="file_quit_menuitem">
+ <property name="visible">True</property>
+ <property name="label">gtk-quit</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_quit1_activate" last_modification_time="Sat, 11 Sep 2004 20:05:11 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="view_menu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="view_menu_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="view_refresh_menuitem">
+ <property name="visible">True</property>
+ <property name="label">gtk-refresh</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_item1_activate" last_modification_time="Sat, 11 Sep 2004 20:05:50 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="help_menu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="help_menu_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="help_about_menuitem">
+ <property name="visible">True</property>
+ <property name="label">gtk-about</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_about1_activate" last_modification_time="Sat, 11 Sep 2004 20:05:11 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="canvas_scrolledwindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="status_lab">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">2</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorToolItem" id="separatortoolitem1">
+ <property name="visible">True</property>
+ <property name="draw">True</property>
+ <property name="visible_horizontal">False</property>
+ <property name="visible_vertical">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Zoom: </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHScale" id="zoom_scale">
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="draw_value">True</property>
+ <property name="value_pos">GTK_POS_RIGHT</property>
+ <property name="digits">1</property>
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="inverted">False</property>
+ <property name="adjustment">1 0.1 2 0 0 0</property>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">2</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="about_win">
+ <property name="width_request">320</property>
+ <property name="height_request">200</property>
+ <property name="title" translatable="yes">About Patchage</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="skip_pager_hint">True</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="about_project_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;span size=&quot;xx-large&quot; weight=&quot;bold&quot;&gt;Patchage&lt;/span&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">A modular patch bay for:
+
+Jack Audio Connection Kit
+ALSA Sequencer</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Copyright © 2005 Dave Robillard</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">10</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
+ <property name="spacing">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="about_close_button">
+ <property name="width_request">66</property>
+ <property name="height_request">26</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/src/patchage.gladep b/src/patchage.gladep
new file mode 100644
index 0000000..8d205c3
--- /dev/null
+++ b/src/patchage.gladep
@@ -0,0 +1,9 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
+
+<glade-project>
+ <name>Patchage</name>
+ <program_name>patchage</program_name>
+ <language>C++</language>
+ <gnome_support>FALSE</gnome_support>
+</glade-project>