From 47246db7e9d71ba694b719001033fba1766a58c4 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 10 Jun 2006 02:43:54 +0000 Subject: More juggling git-svn-id: http://svn.drobilla.net/lad/grauph@16 a436a847-0d15-0410-975c-d299462d15a1 --- src/clients/ConnectionModel.cpp | 54 - src/clients/ConnectionModel.h | 70 - src/clients/ControlModel.h | 53 - src/clients/DirectSigClientInterface.h | 112 - src/clients/Makefile.am | 51 - src/clients/ModelClientInterface.cpp | 135 - src/clients/ModelClientInterface.h | 87 - src/clients/ModelEngineInterface.h | 58 - src/clients/NodeModel.cpp | 117 - src/clients/NodeModel.h | 93 - src/clients/OSCEngineInterface.cpp | 332 -- src/clients/OSCEngineInterface.h | 139 - src/clients/OSCListener.cpp | 413 --- src/clients/OSCListener.h | 116 - src/clients/OSCModelEngineInterface.cpp | 364 -- src/clients/OSCModelEngineInterface.h | 117 - src/clients/ObjectController.h | 43 - src/clients/ObjectModel.cpp | 64 - src/clients/ObjectModel.h | 84 - src/clients/PatchLibrarian.cpp | 834 ----- src/clients/PatchLibrarian.cpp.new | 830 ----- src/clients/PatchLibrarian.h | 78 - src/clients/PatchModel.cpp | 229 -- src/clients/PatchModel.h | 88 - src/clients/PluginModel.h | 105 - src/clients/PortModel.h | 118 - src/clients/PresetModel.h | 66 - src/clients/SigClientInterface.h | 120 - src/clients/ThreadedSigClientInterface.cpp | 71 - src/clients/ThreadedSigClientInterface.h | 177 - src/clients/console/ConsoleClientHooks.cpp | 33 - src/clients/console/ConsoleClientHooks.h | 66 - src/clients/console/Makefile.am | 12 - src/clients/console/README | 4 - src/clients/console/console_client.cpp | 110 - src/clients/console/patches/COPYING | 2 - src/clients/console/patches/dssi_test.omp | 19 - src/clients/console/patches/filter_patch.omp | 54 - .../console/patches/old_super_simple_patch.omp | 36 - src/clients/console/patches/send_test.omp | 2 - src/clients/console/patches/simple_patch.omp | 54 - src/clients/console/patches/super_simple_patch.omp | 36 - src/clients/console/patches/test_patch.omp | 48 - .../demolition/DemolitionClientInterface.cpp | 109 - src/clients/demolition/DemolitionClientInterface.h | 75 - src/clients/demolition/DemolitionModel.cpp | 246 -- src/clients/demolition/DemolitionModel.h | 60 - src/clients/demolition/Makefile.am | 17 - src/clients/demolition/README | 7 - src/clients/demolition/cmdline.c | 149 - src/clients/demolition/cmdline.ggo | 7 - src/clients/demolition/cmdline.h | 45 - src/clients/demolition/demolition.cpp | 334 -- src/clients/gtk/App.cpp | 230 -- src/clients/gtk/App.h | 123 - src/clients/gtk/BreadCrumb.h | 66 - src/clients/gtk/ConfigWindow.cpp | 86 - src/clients/gtk/ConfigWindow.h | 63 - src/clients/gtk/Configuration.cpp | 184 - src/clients/gtk/Configuration.h | 76 - src/clients/gtk/ConnectWindow.cpp | 170 - src/clients/gtk/ConnectWindow.h | 61 - src/clients/gtk/ControlGroups.cpp | 419 --- src/clients/gtk/ControlGroups.h | 196 -- src/clients/gtk/ControlInterface.cpp | 302 -- src/clients/gtk/ControlInterface.h | 129 - src/clients/gtk/ControlPanel.cpp | 279 -- src/clients/gtk/ControlPanel.h | 129 - src/clients/gtk/Controller.cpp | 173 - src/clients/gtk/Controller.h | 112 - src/clients/gtk/DSSIController.cpp | 280 -- src/clients/gtk/DSSIController.h | 79 - src/clients/gtk/DSSIModule.cpp | 38 - src/clients/gtk/DSSIModule.h | 43 - src/clients/gtk/GladeFactory.cpp | 69 - src/clients/gtk/GladeFactory.h | 48 - src/clients/gtk/GtkClientInterface.cpp | 81 - src/clients/gtk/GtkClientInterface.h | 156 - src/clients/gtk/GtkObjectController.cpp | 40 - src/clients/gtk/GtkObjectController.h | 77 - src/clients/gtk/LashController.cpp | 168 - src/clients/gtk/LashController.h | 53 - src/clients/gtk/LoadPatchWindow.cpp | 131 - src/clients/gtk/LoadPatchWindow.h | 73 - src/clients/gtk/LoadPluginWindow.cpp | 407 --- src/clients/gtk/LoadPluginWindow.h | 145 - src/clients/gtk/LoadSubpatchWindow.cpp | 177 - src/clients/gtk/LoadSubpatchWindow.h | 78 - src/clients/gtk/Loader.cpp | 233 -- src/clients/gtk/Loader.h | 154 - src/clients/gtk/Makefile.am | 98 - src/clients/gtk/MessagesWindow.cpp | 64 - src/clients/gtk/MessagesWindow.h | 55 - src/clients/gtk/NewSubpatchWindow.cpp | 110 - src/clients/gtk/NewSubpatchWindow.h | 67 - src/clients/gtk/NodeControlWindow.cpp | 127 - src/clients/gtk/NodeControlWindow.h | 69 - src/clients/gtk/NodeController.cpp | 408 --- src/clients/gtk/NodeController.h | 114 - src/clients/gtk/NodePropertiesWindow.cpp | 62 - src/clients/gtk/NodePropertiesWindow.h | 55 - src/clients/gtk/OmFlowCanvas.cpp | 166 - src/clients/gtk/OmFlowCanvas.h | 70 - src/clients/gtk/OmModule.cpp | 85 - src/clients/gtk/OmModule.h | 77 - src/clients/gtk/OmPort.cpp | 57 - src/clients/gtk/OmPort.h | 59 - src/clients/gtk/PatchController.cpp | 685 ---- src/clients/gtk/PatchController.h | 127 - src/clients/gtk/PatchDescriptionWindow.cpp | 72 - src/clients/gtk/PatchDescriptionWindow.h | 59 - src/clients/gtk/PatchTreeWindow.cpp | 252 -- src/clients/gtk/PatchTreeWindow.h | 105 - src/clients/gtk/PatchView.cpp | 119 - src/clients/gtk/PatchView.h | 86 - src/clients/gtk/PatchWindow.cpp | 532 --- src/clients/gtk/PatchWindow.h | 142 - src/clients/gtk/PortController.cpp | 143 - src/clients/gtk/PortController.h | 75 - src/clients/gtk/RenameWindow.cpp | 113 - src/clients/gtk/RenameWindow.h | 57 - src/clients/gtk/Store.cpp | 155 - src/clients/gtk/Store.h | 75 - src/clients/gtk/SubpatchModule.cpp | 102 - src/clients/gtk/SubpatchModule.h | 69 - src/clients/gtk/cmdline.c | 149 - src/clients/gtk/cmdline.ggo | 7 - src/clients/gtk/cmdline.h | 45 - src/clients/gtk/main.cpp | 103 - src/clients/gtk/om-icon.png | Bin 1189 -> 0 bytes src/clients/gtk/om_gtk.glade | 3555 -------------------- src/clients/gtk/om_gtk.glade.bak | 3555 -------------------- src/clients/gtk/om_gtk.gladep | 9 - src/clients/gtk/om_gtk.gladep.bak | 9 - src/clients/gtk/singletons.cpp | 29 - src/clients/new/PatchLibrarian.cpp | 824 ----- src/clients/new/PatchLibrarian.h | 66 - src/clients/new/patch_loader/Makefile.am | 13 - src/clients/new/patch_loader/README | 5 - src/clients/new/patch_loader/cmdline.c | 163 - src/clients/new/patch_loader/cmdline.ggo | 7 - src/clients/new/patch_loader/cmdline.h | 47 - src/clients/new/patch_loader/patch_loader.cpp | 76 - src/clients/patch_loader/Makefile.am | 13 - src/clients/patch_loader/README | 5 - src/clients/patch_loader/cmdline.c | 163 - src/clients/patch_loader/cmdline.ggo | 7 - src/clients/patch_loader/cmdline.h | 47 - src/clients/patch_loader/new_patch_loader.cpp | 76 - src/clients/patch_loader/patch_loader.cpp | 82 - src/clients/python/Makefile.am | 4 - src/clients/python/OSC.py | 374 -- src/clients/python/omecho.py | 40 - src/clients/python/omsynth.py | 635 ---- src/clients/python/scripts/Makefile.am | 2 - src/clients/python/scripts/flatten.py | 232 -- src/clients/python/scripts/sillysinepatch.py | 41 - src/clients/supercollider/Makefile.am | 2 - src/clients/supercollider/Om.sc | 746 ---- src/clients/supercollider/README | 11 - src/clients/supercollider/example.sc | 27 - src/libs/client/ConnectionModel.cpp | 54 + src/libs/client/ConnectionModel.h | 70 + src/libs/client/ControlModel.h | 53 + src/libs/client/DirectSigClientInterface.h | 112 + src/libs/client/Makefile.am | 51 + src/libs/client/ModelClientInterface.cpp | 135 + src/libs/client/ModelClientInterface.h | 87 + src/libs/client/ModelEngineInterface.h | 58 + src/libs/client/NodeModel.cpp | 117 + src/libs/client/NodeModel.h | 93 + src/libs/client/OSCEngineInterface.cpp | 332 ++ src/libs/client/OSCEngineInterface.h | 139 + src/libs/client/OSCListener.cpp | 413 +++ src/libs/client/OSCListener.h | 116 + src/libs/client/OSCModelEngineInterface.cpp | 364 ++ src/libs/client/OSCModelEngineInterface.h | 117 + src/libs/client/ObjectController.h | 43 + src/libs/client/ObjectModel.cpp | 64 + src/libs/client/ObjectModel.h | 84 + src/libs/client/PatchLibrarian.cpp | 834 +++++ src/libs/client/PatchLibrarian.cpp.new | 830 +++++ src/libs/client/PatchLibrarian.h | 78 + src/libs/client/PatchModel.cpp | 229 ++ src/libs/client/PatchModel.h | 88 + src/libs/client/PluginModel.h | 105 + src/libs/client/PortModel.h | 118 + src/libs/client/PresetModel.h | 66 + src/libs/client/SigClientInterface.h | 120 + src/libs/client/ThreadedSigClientInterface.cpp | 71 + src/libs/client/ThreadedSigClientInterface.h | 177 + src/libs/engine/Makefile.am | 83 +- src/libs/engine/cmdline.c | 150 - src/libs/engine/cmdline.ggo | 7 - src/libs/engine/cmdline.h | 45 - src/libs/engine/main.cpp | 153 - src/progs/console/ConsoleClientHooks.cpp | 33 + src/progs/console/ConsoleClientHooks.h | 66 + src/progs/console/Makefile.am | 12 + src/progs/console/README | 4 + src/progs/console/console_client.cpp | 110 + src/progs/console/patches/COPYING | 2 + src/progs/console/patches/dssi_test.omp | 19 + src/progs/console/patches/filter_patch.omp | 54 + .../console/patches/old_super_simple_patch.omp | 36 + src/progs/console/patches/send_test.omp | 2 + src/progs/console/patches/simple_patch.omp | 54 + src/progs/console/patches/super_simple_patch.omp | 36 + src/progs/console/patches/test_patch.omp | 48 + src/progs/demolition/DemolitionClientInterface.cpp | 109 + src/progs/demolition/DemolitionClientInterface.h | 75 + src/progs/demolition/DemolitionModel.cpp | 246 ++ src/progs/demolition/DemolitionModel.h | 60 + src/progs/demolition/Makefile.am | 17 + src/progs/demolition/README | 7 + src/progs/demolition/cmdline.c | 149 + src/progs/demolition/cmdline.ggo | 7 + src/progs/demolition/cmdline.h | 45 + src/progs/demolition/demolition.cpp | 334 ++ src/progs/gtk/App.cpp | 230 ++ src/progs/gtk/App.h | 123 + src/progs/gtk/BreadCrumb.h | 66 + src/progs/gtk/ConfigWindow.cpp | 86 + src/progs/gtk/ConfigWindow.h | 63 + src/progs/gtk/Configuration.cpp | 184 + src/progs/gtk/Configuration.h | 76 + src/progs/gtk/ConnectWindow.cpp | 170 + src/progs/gtk/ConnectWindow.h | 61 + src/progs/gtk/ControlGroups.cpp | 419 +++ src/progs/gtk/ControlGroups.h | 196 ++ src/progs/gtk/ControlInterface.cpp | 302 ++ src/progs/gtk/ControlInterface.h | 129 + src/progs/gtk/ControlPanel.cpp | 279 ++ src/progs/gtk/ControlPanel.h | 129 + src/progs/gtk/Controller.cpp | 173 + src/progs/gtk/Controller.h | 112 + src/progs/gtk/DSSIController.cpp | 280 ++ src/progs/gtk/DSSIController.h | 79 + src/progs/gtk/DSSIModule.cpp | 38 + src/progs/gtk/DSSIModule.h | 43 + src/progs/gtk/GladeFactory.cpp | 69 + src/progs/gtk/GladeFactory.h | 48 + src/progs/gtk/GtkClientInterface.cpp | 81 + src/progs/gtk/GtkClientInterface.h | 156 + src/progs/gtk/GtkObjectController.cpp | 40 + src/progs/gtk/GtkObjectController.h | 77 + src/progs/gtk/LashController.cpp | 168 + src/progs/gtk/LashController.h | 53 + src/progs/gtk/LoadPatchWindow.cpp | 131 + src/progs/gtk/LoadPatchWindow.h | 73 + src/progs/gtk/LoadPluginWindow.cpp | 407 +++ src/progs/gtk/LoadPluginWindow.h | 145 + src/progs/gtk/LoadSubpatchWindow.cpp | 177 + src/progs/gtk/LoadSubpatchWindow.h | 78 + src/progs/gtk/Loader.cpp | 233 ++ src/progs/gtk/Loader.h | 154 + src/progs/gtk/Makefile.am | 98 + src/progs/gtk/MessagesWindow.cpp | 64 + src/progs/gtk/MessagesWindow.h | 55 + src/progs/gtk/NewSubpatchWindow.cpp | 110 + src/progs/gtk/NewSubpatchWindow.h | 67 + src/progs/gtk/NodeControlWindow.cpp | 127 + src/progs/gtk/NodeControlWindow.h | 69 + src/progs/gtk/NodeController.cpp | 408 +++ src/progs/gtk/NodeController.h | 114 + src/progs/gtk/NodePropertiesWindow.cpp | 62 + src/progs/gtk/NodePropertiesWindow.h | 55 + src/progs/gtk/OmFlowCanvas.cpp | 166 + src/progs/gtk/OmFlowCanvas.h | 70 + src/progs/gtk/OmModule.cpp | 85 + src/progs/gtk/OmModule.h | 77 + src/progs/gtk/OmPort.cpp | 57 + src/progs/gtk/OmPort.h | 59 + src/progs/gtk/PatchController.cpp | 685 ++++ src/progs/gtk/PatchController.h | 127 + src/progs/gtk/PatchDescriptionWindow.cpp | 72 + src/progs/gtk/PatchDescriptionWindow.h | 59 + src/progs/gtk/PatchTreeWindow.cpp | 252 ++ src/progs/gtk/PatchTreeWindow.h | 105 + src/progs/gtk/PatchView.cpp | 119 + src/progs/gtk/PatchView.h | 86 + src/progs/gtk/PatchWindow.cpp | 532 +++ src/progs/gtk/PatchWindow.h | 142 + src/progs/gtk/PortController.cpp | 143 + src/progs/gtk/PortController.h | 75 + src/progs/gtk/RenameWindow.cpp | 113 + src/progs/gtk/RenameWindow.h | 57 + src/progs/gtk/Store.cpp | 155 + src/progs/gtk/Store.h | 75 + src/progs/gtk/SubpatchModule.cpp | 102 + src/progs/gtk/SubpatchModule.h | 69 + src/progs/gtk/cmdline.c | 149 + src/progs/gtk/cmdline.ggo | 7 + src/progs/gtk/cmdline.h | 45 + src/progs/gtk/main.cpp | 103 + src/progs/gtk/om-icon.png | Bin 0 -> 1189 bytes src/progs/gtk/om_gtk.glade | 3555 ++++++++++++++++++++ src/progs/gtk/om_gtk.glade.bak | 3555 ++++++++++++++++++++ src/progs/gtk/om_gtk.gladep | 9 + src/progs/gtk/om_gtk.gladep.bak | 9 + src/progs/gtk/singletons.cpp | 29 + src/progs/om/Makefile.am | 254 +- src/progs/om/cmdline.c | 150 + src/progs/om/cmdline.ggo | 7 + src/progs/om/cmdline.h | 45 + src/progs/om/main.cpp | 153 + src/progs/patch_loader/Makefile.am | 13 + src/progs/patch_loader/README | 5 + src/progs/patch_loader/cmdline.c | 163 + src/progs/patch_loader/cmdline.ggo | 7 + src/progs/patch_loader/cmdline.h | 47 + src/progs/patch_loader/new_patch_loader.cpp | 76 + src/progs/patch_loader/patch_loader.cpp | 82 + src/progs/python/Makefile.am | 4 + src/progs/python/OSC.py | 374 ++ src/progs/python/omecho.py | 40 + src/progs/python/omsynth.py | 635 ++++ src/progs/python/scripts/Makefile.am | 2 + src/progs/python/scripts/flatten.py | 232 ++ src/progs/python/scripts/sillysinepatch.py | 41 + src/progs/supercollider/Makefile.am | 2 + src/progs/supercollider/Om.sc | 746 ++++ src/progs/supercollider/README | 11 + src/progs/supercollider/example.sc | 27 + 324 files changed, 27141 insertions(+), 28607 deletions(-) delete mode 100644 src/clients/ConnectionModel.cpp delete mode 100644 src/clients/ConnectionModel.h delete mode 100644 src/clients/ControlModel.h delete mode 100644 src/clients/DirectSigClientInterface.h delete mode 100644 src/clients/Makefile.am delete mode 100644 src/clients/ModelClientInterface.cpp delete mode 100644 src/clients/ModelClientInterface.h delete mode 100644 src/clients/ModelEngineInterface.h delete mode 100644 src/clients/NodeModel.cpp delete mode 100644 src/clients/NodeModel.h delete mode 100644 src/clients/OSCEngineInterface.cpp delete mode 100644 src/clients/OSCEngineInterface.h delete mode 100644 src/clients/OSCListener.cpp delete mode 100644 src/clients/OSCListener.h delete mode 100644 src/clients/OSCModelEngineInterface.cpp delete mode 100644 src/clients/OSCModelEngineInterface.h delete mode 100644 src/clients/ObjectController.h delete mode 100644 src/clients/ObjectModel.cpp delete mode 100644 src/clients/ObjectModel.h delete mode 100644 src/clients/PatchLibrarian.cpp delete mode 100644 src/clients/PatchLibrarian.cpp.new delete mode 100644 src/clients/PatchLibrarian.h delete mode 100644 src/clients/PatchModel.cpp delete mode 100644 src/clients/PatchModel.h delete mode 100644 src/clients/PluginModel.h delete mode 100644 src/clients/PortModel.h delete mode 100644 src/clients/PresetModel.h delete mode 100644 src/clients/SigClientInterface.h delete mode 100644 src/clients/ThreadedSigClientInterface.cpp delete mode 100644 src/clients/ThreadedSigClientInterface.h delete mode 100644 src/clients/console/ConsoleClientHooks.cpp delete mode 100644 src/clients/console/ConsoleClientHooks.h delete mode 100644 src/clients/console/Makefile.am delete mode 100644 src/clients/console/README delete mode 100644 src/clients/console/console_client.cpp delete mode 100644 src/clients/console/patches/COPYING delete mode 100644 src/clients/console/patches/dssi_test.omp delete mode 100644 src/clients/console/patches/filter_patch.omp delete mode 100644 src/clients/console/patches/old_super_simple_patch.omp delete mode 100644 src/clients/console/patches/send_test.omp delete mode 100644 src/clients/console/patches/simple_patch.omp delete mode 100644 src/clients/console/patches/super_simple_patch.omp delete mode 100644 src/clients/console/patches/test_patch.omp delete mode 100644 src/clients/demolition/DemolitionClientInterface.cpp delete mode 100644 src/clients/demolition/DemolitionClientInterface.h delete mode 100644 src/clients/demolition/DemolitionModel.cpp delete mode 100644 src/clients/demolition/DemolitionModel.h delete mode 100644 src/clients/demolition/Makefile.am delete mode 100644 src/clients/demolition/README delete mode 100644 src/clients/demolition/cmdline.c delete mode 100644 src/clients/demolition/cmdline.ggo delete mode 100644 src/clients/demolition/cmdline.h delete mode 100644 src/clients/demolition/demolition.cpp delete mode 100644 src/clients/gtk/App.cpp delete mode 100644 src/clients/gtk/App.h delete mode 100644 src/clients/gtk/BreadCrumb.h delete mode 100644 src/clients/gtk/ConfigWindow.cpp delete mode 100644 src/clients/gtk/ConfigWindow.h delete mode 100644 src/clients/gtk/Configuration.cpp delete mode 100644 src/clients/gtk/Configuration.h delete mode 100644 src/clients/gtk/ConnectWindow.cpp delete mode 100644 src/clients/gtk/ConnectWindow.h delete mode 100644 src/clients/gtk/ControlGroups.cpp delete mode 100644 src/clients/gtk/ControlGroups.h delete mode 100644 src/clients/gtk/ControlInterface.cpp delete mode 100644 src/clients/gtk/ControlInterface.h delete mode 100644 src/clients/gtk/ControlPanel.cpp delete mode 100644 src/clients/gtk/ControlPanel.h delete mode 100644 src/clients/gtk/Controller.cpp delete mode 100644 src/clients/gtk/Controller.h delete mode 100644 src/clients/gtk/DSSIController.cpp delete mode 100644 src/clients/gtk/DSSIController.h delete mode 100644 src/clients/gtk/DSSIModule.cpp delete mode 100644 src/clients/gtk/DSSIModule.h delete mode 100644 src/clients/gtk/GladeFactory.cpp delete mode 100644 src/clients/gtk/GladeFactory.h delete mode 100644 src/clients/gtk/GtkClientInterface.cpp delete mode 100644 src/clients/gtk/GtkClientInterface.h delete mode 100644 src/clients/gtk/GtkObjectController.cpp delete mode 100644 src/clients/gtk/GtkObjectController.h delete mode 100644 src/clients/gtk/LashController.cpp delete mode 100644 src/clients/gtk/LashController.h delete mode 100644 src/clients/gtk/LoadPatchWindow.cpp delete mode 100644 src/clients/gtk/LoadPatchWindow.h delete mode 100644 src/clients/gtk/LoadPluginWindow.cpp delete mode 100644 src/clients/gtk/LoadPluginWindow.h delete mode 100644 src/clients/gtk/LoadSubpatchWindow.cpp delete mode 100644 src/clients/gtk/LoadSubpatchWindow.h delete mode 100644 src/clients/gtk/Loader.cpp delete mode 100644 src/clients/gtk/Loader.h delete mode 100644 src/clients/gtk/Makefile.am delete mode 100644 src/clients/gtk/MessagesWindow.cpp delete mode 100644 src/clients/gtk/MessagesWindow.h delete mode 100644 src/clients/gtk/NewSubpatchWindow.cpp delete mode 100644 src/clients/gtk/NewSubpatchWindow.h delete mode 100644 src/clients/gtk/NodeControlWindow.cpp delete mode 100644 src/clients/gtk/NodeControlWindow.h delete mode 100644 src/clients/gtk/NodeController.cpp delete mode 100644 src/clients/gtk/NodeController.h delete mode 100644 src/clients/gtk/NodePropertiesWindow.cpp delete mode 100644 src/clients/gtk/NodePropertiesWindow.h delete mode 100644 src/clients/gtk/OmFlowCanvas.cpp delete mode 100644 src/clients/gtk/OmFlowCanvas.h delete mode 100644 src/clients/gtk/OmModule.cpp delete mode 100644 src/clients/gtk/OmModule.h delete mode 100644 src/clients/gtk/OmPort.cpp delete mode 100644 src/clients/gtk/OmPort.h delete mode 100644 src/clients/gtk/PatchController.cpp delete mode 100644 src/clients/gtk/PatchController.h delete mode 100644 src/clients/gtk/PatchDescriptionWindow.cpp delete mode 100644 src/clients/gtk/PatchDescriptionWindow.h delete mode 100644 src/clients/gtk/PatchTreeWindow.cpp delete mode 100644 src/clients/gtk/PatchTreeWindow.h delete mode 100644 src/clients/gtk/PatchView.cpp delete mode 100644 src/clients/gtk/PatchView.h delete mode 100644 src/clients/gtk/PatchWindow.cpp delete mode 100644 src/clients/gtk/PatchWindow.h delete mode 100644 src/clients/gtk/PortController.cpp delete mode 100644 src/clients/gtk/PortController.h delete mode 100644 src/clients/gtk/RenameWindow.cpp delete mode 100644 src/clients/gtk/RenameWindow.h delete mode 100644 src/clients/gtk/Store.cpp delete mode 100644 src/clients/gtk/Store.h delete mode 100644 src/clients/gtk/SubpatchModule.cpp delete mode 100644 src/clients/gtk/SubpatchModule.h delete mode 100644 src/clients/gtk/cmdline.c delete mode 100644 src/clients/gtk/cmdline.ggo delete mode 100644 src/clients/gtk/cmdline.h delete mode 100644 src/clients/gtk/main.cpp delete mode 100644 src/clients/gtk/om-icon.png delete mode 100644 src/clients/gtk/om_gtk.glade delete mode 100644 src/clients/gtk/om_gtk.glade.bak delete mode 100644 src/clients/gtk/om_gtk.gladep delete mode 100644 src/clients/gtk/om_gtk.gladep.bak delete mode 100644 src/clients/gtk/singletons.cpp delete mode 100644 src/clients/new/PatchLibrarian.cpp delete mode 100644 src/clients/new/PatchLibrarian.h delete mode 100644 src/clients/new/patch_loader/Makefile.am delete mode 100644 src/clients/new/patch_loader/README delete mode 100644 src/clients/new/patch_loader/cmdline.c delete mode 100644 src/clients/new/patch_loader/cmdline.ggo delete mode 100644 src/clients/new/patch_loader/cmdline.h delete mode 100644 src/clients/new/patch_loader/patch_loader.cpp delete mode 100644 src/clients/patch_loader/Makefile.am delete mode 100644 src/clients/patch_loader/README delete mode 100644 src/clients/patch_loader/cmdline.c delete mode 100644 src/clients/patch_loader/cmdline.ggo delete mode 100644 src/clients/patch_loader/cmdline.h delete mode 100644 src/clients/patch_loader/new_patch_loader.cpp delete mode 100644 src/clients/patch_loader/patch_loader.cpp delete mode 100644 src/clients/python/Makefile.am delete mode 100755 src/clients/python/OSC.py delete mode 100644 src/clients/python/omecho.py delete mode 100644 src/clients/python/omsynth.py delete mode 100644 src/clients/python/scripts/Makefile.am delete mode 100755 src/clients/python/scripts/flatten.py delete mode 100644 src/clients/python/scripts/sillysinepatch.py delete mode 100644 src/clients/supercollider/Makefile.am delete mode 100644 src/clients/supercollider/Om.sc delete mode 100644 src/clients/supercollider/README delete mode 100644 src/clients/supercollider/example.sc create mode 100644 src/libs/client/ConnectionModel.cpp create mode 100644 src/libs/client/ConnectionModel.h create mode 100644 src/libs/client/ControlModel.h create mode 100644 src/libs/client/DirectSigClientInterface.h create mode 100644 src/libs/client/Makefile.am create mode 100644 src/libs/client/ModelClientInterface.cpp create mode 100644 src/libs/client/ModelClientInterface.h create mode 100644 src/libs/client/ModelEngineInterface.h create mode 100644 src/libs/client/NodeModel.cpp create mode 100644 src/libs/client/NodeModel.h create mode 100644 src/libs/client/OSCEngineInterface.cpp create mode 100644 src/libs/client/OSCEngineInterface.h create mode 100644 src/libs/client/OSCListener.cpp create mode 100644 src/libs/client/OSCListener.h create mode 100644 src/libs/client/OSCModelEngineInterface.cpp create mode 100644 src/libs/client/OSCModelEngineInterface.h create mode 100644 src/libs/client/ObjectController.h create mode 100644 src/libs/client/ObjectModel.cpp create mode 100644 src/libs/client/ObjectModel.h create mode 100644 src/libs/client/PatchLibrarian.cpp create mode 100644 src/libs/client/PatchLibrarian.cpp.new create mode 100644 src/libs/client/PatchLibrarian.h create mode 100644 src/libs/client/PatchModel.cpp create mode 100644 src/libs/client/PatchModel.h create mode 100644 src/libs/client/PluginModel.h create mode 100644 src/libs/client/PortModel.h create mode 100644 src/libs/client/PresetModel.h create mode 100644 src/libs/client/SigClientInterface.h create mode 100644 src/libs/client/ThreadedSigClientInterface.cpp create mode 100644 src/libs/client/ThreadedSigClientInterface.h delete mode 100644 src/libs/engine/cmdline.c delete mode 100644 src/libs/engine/cmdline.ggo delete mode 100644 src/libs/engine/cmdline.h delete mode 100644 src/libs/engine/main.cpp create mode 100644 src/progs/console/ConsoleClientHooks.cpp create mode 100644 src/progs/console/ConsoleClientHooks.h create mode 100644 src/progs/console/Makefile.am create mode 100644 src/progs/console/README create mode 100644 src/progs/console/console_client.cpp create mode 100644 src/progs/console/patches/COPYING create mode 100644 src/progs/console/patches/dssi_test.omp create mode 100644 src/progs/console/patches/filter_patch.omp create mode 100644 src/progs/console/patches/old_super_simple_patch.omp create mode 100644 src/progs/console/patches/send_test.omp create mode 100644 src/progs/console/patches/simple_patch.omp create mode 100644 src/progs/console/patches/super_simple_patch.omp create mode 100644 src/progs/console/patches/test_patch.omp create mode 100644 src/progs/demolition/DemolitionClientInterface.cpp create mode 100644 src/progs/demolition/DemolitionClientInterface.h create mode 100644 src/progs/demolition/DemolitionModel.cpp create mode 100644 src/progs/demolition/DemolitionModel.h create mode 100644 src/progs/demolition/Makefile.am create mode 100644 src/progs/demolition/README create mode 100644 src/progs/demolition/cmdline.c create mode 100644 src/progs/demolition/cmdline.ggo create mode 100644 src/progs/demolition/cmdline.h create mode 100644 src/progs/demolition/demolition.cpp create mode 100644 src/progs/gtk/App.cpp create mode 100644 src/progs/gtk/App.h create mode 100644 src/progs/gtk/BreadCrumb.h create mode 100644 src/progs/gtk/ConfigWindow.cpp create mode 100644 src/progs/gtk/ConfigWindow.h create mode 100644 src/progs/gtk/Configuration.cpp create mode 100644 src/progs/gtk/Configuration.h create mode 100644 src/progs/gtk/ConnectWindow.cpp create mode 100644 src/progs/gtk/ConnectWindow.h create mode 100644 src/progs/gtk/ControlGroups.cpp create mode 100644 src/progs/gtk/ControlGroups.h create mode 100644 src/progs/gtk/ControlInterface.cpp create mode 100644 src/progs/gtk/ControlInterface.h create mode 100644 src/progs/gtk/ControlPanel.cpp create mode 100644 src/progs/gtk/ControlPanel.h create mode 100644 src/progs/gtk/Controller.cpp create mode 100644 src/progs/gtk/Controller.h create mode 100644 src/progs/gtk/DSSIController.cpp create mode 100644 src/progs/gtk/DSSIController.h create mode 100644 src/progs/gtk/DSSIModule.cpp create mode 100644 src/progs/gtk/DSSIModule.h create mode 100644 src/progs/gtk/GladeFactory.cpp create mode 100644 src/progs/gtk/GladeFactory.h create mode 100644 src/progs/gtk/GtkClientInterface.cpp create mode 100644 src/progs/gtk/GtkClientInterface.h create mode 100644 src/progs/gtk/GtkObjectController.cpp create mode 100644 src/progs/gtk/GtkObjectController.h create mode 100644 src/progs/gtk/LashController.cpp create mode 100644 src/progs/gtk/LashController.h create mode 100644 src/progs/gtk/LoadPatchWindow.cpp create mode 100644 src/progs/gtk/LoadPatchWindow.h create mode 100644 src/progs/gtk/LoadPluginWindow.cpp create mode 100644 src/progs/gtk/LoadPluginWindow.h create mode 100644 src/progs/gtk/LoadSubpatchWindow.cpp create mode 100644 src/progs/gtk/LoadSubpatchWindow.h create mode 100644 src/progs/gtk/Loader.cpp create mode 100644 src/progs/gtk/Loader.h create mode 100644 src/progs/gtk/Makefile.am create mode 100644 src/progs/gtk/MessagesWindow.cpp create mode 100644 src/progs/gtk/MessagesWindow.h create mode 100644 src/progs/gtk/NewSubpatchWindow.cpp create mode 100644 src/progs/gtk/NewSubpatchWindow.h create mode 100644 src/progs/gtk/NodeControlWindow.cpp create mode 100644 src/progs/gtk/NodeControlWindow.h create mode 100644 src/progs/gtk/NodeController.cpp create mode 100644 src/progs/gtk/NodeController.h create mode 100644 src/progs/gtk/NodePropertiesWindow.cpp create mode 100644 src/progs/gtk/NodePropertiesWindow.h create mode 100644 src/progs/gtk/OmFlowCanvas.cpp create mode 100644 src/progs/gtk/OmFlowCanvas.h create mode 100644 src/progs/gtk/OmModule.cpp create mode 100644 src/progs/gtk/OmModule.h create mode 100644 src/progs/gtk/OmPort.cpp create mode 100644 src/progs/gtk/OmPort.h create mode 100644 src/progs/gtk/PatchController.cpp create mode 100644 src/progs/gtk/PatchController.h create mode 100644 src/progs/gtk/PatchDescriptionWindow.cpp create mode 100644 src/progs/gtk/PatchDescriptionWindow.h create mode 100644 src/progs/gtk/PatchTreeWindow.cpp create mode 100644 src/progs/gtk/PatchTreeWindow.h create mode 100644 src/progs/gtk/PatchView.cpp create mode 100644 src/progs/gtk/PatchView.h create mode 100644 src/progs/gtk/PatchWindow.cpp create mode 100644 src/progs/gtk/PatchWindow.h create mode 100644 src/progs/gtk/PortController.cpp create mode 100644 src/progs/gtk/PortController.h create mode 100644 src/progs/gtk/RenameWindow.cpp create mode 100644 src/progs/gtk/RenameWindow.h create mode 100644 src/progs/gtk/Store.cpp create mode 100644 src/progs/gtk/Store.h create mode 100644 src/progs/gtk/SubpatchModule.cpp create mode 100644 src/progs/gtk/SubpatchModule.h create mode 100644 src/progs/gtk/cmdline.c create mode 100644 src/progs/gtk/cmdline.ggo create mode 100644 src/progs/gtk/cmdline.h create mode 100644 src/progs/gtk/main.cpp create mode 100644 src/progs/gtk/om-icon.png create mode 100644 src/progs/gtk/om_gtk.glade create mode 100644 src/progs/gtk/om_gtk.glade.bak create mode 100644 src/progs/gtk/om_gtk.gladep create mode 100644 src/progs/gtk/om_gtk.gladep.bak create mode 100644 src/progs/gtk/singletons.cpp create mode 100644 src/progs/om/cmdline.c create mode 100644 src/progs/om/cmdline.ggo create mode 100644 src/progs/om/cmdline.h create mode 100644 src/progs/om/main.cpp create mode 100644 src/progs/patch_loader/Makefile.am create mode 100644 src/progs/patch_loader/README create mode 100644 src/progs/patch_loader/cmdline.c create mode 100644 src/progs/patch_loader/cmdline.ggo create mode 100644 src/progs/patch_loader/cmdline.h create mode 100644 src/progs/patch_loader/new_patch_loader.cpp create mode 100644 src/progs/patch_loader/patch_loader.cpp create mode 100644 src/progs/python/Makefile.am create mode 100755 src/progs/python/OSC.py create mode 100644 src/progs/python/omecho.py create mode 100644 src/progs/python/omsynth.py create mode 100644 src/progs/python/scripts/Makefile.am create mode 100755 src/progs/python/scripts/flatten.py create mode 100644 src/progs/python/scripts/sillysinepatch.py create mode 100644 src/progs/supercollider/Makefile.am create mode 100644 src/progs/supercollider/Om.sc create mode 100644 src/progs/supercollider/README create mode 100644 src/progs/supercollider/example.sc (limited to 'src') diff --git a/src/clients/ConnectionModel.cpp b/src/clients/ConnectionModel.cpp deleted file mode 100644 index 1c7541b9..00000000 --- a/src/clients/ConnectionModel.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Om. 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 "ConnectionModel.h" -#include "PortModel.h" - -namespace LibOmClient { - - -ConnectionModel::ConnectionModel(const Path& src_port, const Path& dst_port) -: m_src_port_path(src_port), - m_dst_port_path(dst_port), - m_src_port(NULL), - m_dst_port(NULL) -{ - // Be sure connection is within one patch - assert(m_src_port_path.parent().parent() - == m_dst_port_path.parent().parent()); -} - - -const Path& -ConnectionModel::src_port_path() const -{ - if (m_src_port == NULL) - return m_src_port_path; - else - return m_src_port->path(); -} - - -const Path& -ConnectionModel::dst_port_path() const -{ - if (m_dst_port == NULL) - return m_dst_port_path; - else - return m_dst_port->path(); -} - -} // namespace LibOmClient diff --git a/src/clients/ConnectionModel.h b/src/clients/ConnectionModel.h deleted file mode 100644 index ef909850..00000000 --- a/src/clients/ConnectionModel.h +++ /dev/null @@ -1,70 +0,0 @@ -/* This file is part of Om. 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 CONNECTIONMODEL_H -#define CONNECTIONMODEL_H - -#include -#include "util/Path.h" -#include -using std::string; -using Om::Path; - -namespace LibOmClient { - -class PortModel; - - -/** Class to represent a port->port connection in the engine. - * - * This can either have pointers to the connection ports' models, or just - * paths as strings. LibOmClient passes just strings (by necessity), but - * clients can set the pointers then they don't have to worry about port - * renaming, as the connections will always return the port's path, even - * if it changes. - * - * \ingroup libomclient - */ -class ConnectionModel -{ -public: - ConnectionModel(const Path& src_port, const Path& dst_port); - - PortModel* src_port() const { return m_src_port; } - PortModel* dst_port() const { return m_dst_port; } - - void set_src_port(PortModel* port) { m_src_port = port; m_src_port_path = ""; } - void set_dst_port(PortModel* port) { m_dst_port = port; m_dst_port_path = ""; } - - void src_port_path(const string& s) { m_src_port_path = s; } - void dst_port_path(const string& s) { m_dst_port_path = s; } - - const Path& src_port_path() const; - const Path& dst_port_path() const; - const Path patch_path() const { return src_port_path().parent().parent(); } - -private: - Path m_src_port_path; ///< Only used if m_src_port == NULL - Path m_dst_port_path; ///< Only used if m_dst_port == NULL - PortModel* m_src_port; - PortModel* m_dst_port; -}; - - -} // namespace LibOmClient - -#endif // CONNECTIONMODEL_H diff --git a/src/clients/ControlModel.h b/src/clients/ControlModel.h deleted file mode 100644 index 872dcca2..00000000 --- a/src/clients/ControlModel.h +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of Om. 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 alongCont - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CONTROLMODEL_H -#define CONTROLMODEL_H - -#include -#include "util/Path.h" - -namespace LibOmClient { - - -/** A single port's control setting (in a preset). - * - * \ingroup libomclient - */ -class ControlModel -{ -public: - ControlModel(const Path& port_path, float value) - : m_port_path(port_path), - m_value(value) - { - assert(m_port_path.find("//") == string::npos); - } - - const Path& port_path() const { return m_port_path; } - void port_path(const string& p) { m_port_path = p; } - float value() const { return m_value; } - void value(float v) { m_value = v; } - -private: - Path m_port_path; - float m_value; -}; - - -} // namespace LibOmClient - -#endif // CONTROLMODEL diff --git a/src/clients/DirectSigClientInterface.h b/src/clients/DirectSigClientInterface.h deleted file mode 100644 index 12672a48..00000000 --- a/src/clients/DirectSigClientInterface.h +++ /dev/null @@ -1,112 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 DIRECTSIGCLIENTINTERFACE_H -#define DIRECTSIGCLIENTINTERFACE_H - -#include -#include -#include -#include "SigClientInterface.h" -using std::string; - -namespace LibOmClient { - - -/** A direct (nonthreaded) LibSigC++ signal emitting interface for clients to use. - * - * The signals from SigClientInterface will be emitted in the same thread as the - * ClientInterface functions are called. You can not set this directly as an - * in-engine client interface and connect the signals to GTK. - * - * For maximum performance of a monolithic single-client GUI app, it would be - * nice if the post processing thread in the engine could actually be the GTK - * thread, then you could use this directly and minimize queueing of events and - * thread/scheduling overhead. - * - * sed would have the copyright to this code if it was a legal person. - */ -class DirectSigClientInterface : virtual public SigClientInterface -{ -public: - DirectSigClientInterface(); - -private: - - // ClientInterface function implementations to drive SigClientInterface signals - - virtual void bundle_begin() - { emit_bundle_begin(); } - - virtual void bundle_end() - { emit_bundle_end(); } - - virtual void error(const string& msg) - { emit_error(msg); } - - virtual void num_plugins(uint32_t num) - { emit_num_plugins(num); } - - virtual void new_plugin(const string& type, const string& uri, const string& name) - { emit_new_plugin(type, uri, name); } - - virtual void new_patch(const string& path, uint32_t poly) - { emit_new_patch(path, poly); } - - virtual void new_node(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports) - { emit_new_node(plugin_type, plugin_uri, node_path, is_polyphonic, num_ports); } - - virtual void new_port(const string& path, const string& data_type, bool is_output) - { emit_new_port(path, data_type, is_output); } - - virtual void patch_enabled(const string& path) - { emit_patch_enabled(path); } - - virtual void patch_disabled(const string& path) - { emit_patch_disabled(path); } - - virtual void patch_cleared(const string& path) - { emit_patch_cleared(path); } - - virtual void object_renamed(const string& old_path, const string& new_path) - { emit_object_renamed(old_path, new_path); } - - virtual void object_destroyed(const string& path) - { emit_object_destroyed(path); } - - virtual void connection(const string& src_port_path, const string& dst_port_path) - { emit_connection(src_port_path, dst_port_path); } - - virtual void disconnection(const string& src_port_path, const string& dst_port_path) - { emit_disconnection(src_port_path, dst_port_path); } - - virtual void metadata_update(const string& subject_path, const string& predicate, const string& value) - { emit_metadata_update(subject_path, predicate, value); } - - virtual void control_change(const string& port_path, float value) - { emit_control_change(port_path, value); } - - virtual void program_add(const string& node_path, uint32_t bank, uint32_t program, const string& program_name) - { emit_program_add(node_path, bank, program, program_name); } - - virtual void program_remove(const string& node_path, uint32_t bank, uint32_t program) - { emit_program_remove(node_path, bank, program); } -}; - - -} // namespace LibOmClient - -#endif diff --git a/src/clients/Makefile.am b/src/clients/Makefile.am deleted file mode 100644 index 24e6a3bb..00000000 --- a/src/clients/Makefile.am +++ /dev/null @@ -1,51 +0,0 @@ -AM_CXXFLAGS = -I$(top_srcdir)/src/common -fno-exceptions -fno-rtti - -SUBDIRS = . python supercollider - -if BUILD_CONSOLE_CLIENTS -noinst_LIBRARIES = libomclient.a - -libomclient_a_CXXFLAGS = -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LIBGLADEMM_CFLAGS) $(GNOMECANVASMM_CFLAGS) $(JACK_CFLAGS) $(LXML2_CFLAGS) - -libomclient_a_SOURCES = \ - ClientInterface.h \ - OSCEngineInterface.h \ - OSCEngineInterface.cpp \ - OSCModelEngineInterface.h \ - OSCModelEngineInterface.cpp \ - OSCListener.h \ - OSCListener.cpp \ - SigClientInterface.h \ - DirectSigClientInterface.h \ - ThreadedSigClientInterface.h \ - ThreadedSigClientInterface.cpp \ - ModelEngineInterface.h \ - ModelClientInterface.h \ - ModelClientInterface.cpp \ - PresetModel.h \ - ControlModel.h \ - ObjectController.h \ - ObjectModel.h \ - ObjectModel.cpp \ - NodeModel.h \ - NodeModel.cpp \ - PortModel.h \ - PatchModel.h \ - PatchModel.cpp \ - PluginModel.h \ - PatchLibrarian.h \ - PatchLibrarian.cpp \ - ConnectionModel.h \ - ConnectionModel.cpp \ - $(top_srcdir)/src/common/util/Path.h \ - $(top_srcdir)/src/common/interface/ClientInterface.h \ - $(top_srcdir)/src/common/interface/EngineInterface.h - -SUBDIRS += patch_loader patches demolition - -endif # BUILD_CONSOLE_CLIENTS - -if BUILD_GTK_CLIENT -SUBDIRS += gtk -endif - diff --git a/src/clients/ModelClientInterface.cpp b/src/clients/ModelClientInterface.cpp deleted file mode 100644 index 46754161..00000000 --- a/src/clients/ModelClientInterface.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* This file is part of Om. 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 "ModelClientInterface.h" -#include "PatchModel.h" -#include "ConnectionModel.h" -#include "PresetModel.h" -#include "NodeModel.h" -#include "PluginModel.h" - -namespace LibOmClient { - - -void -ModelClientInterface::new_plugin_model(PluginModel* pi) -{ -} - - -void -ModelClientInterface::new_patch_model(PatchModel* pm) -{ -} - - -void -ModelClientInterface::new_node_model(NodeModel* nm) -{ -} - - -void -ModelClientInterface::new_port_model(PortModel* port_info) -{ -} - - -void -ModelClientInterface::connection_model(ConnectionModel* cm) -{ -} - - - -/* Implementations of ClientInterface functions to drive - * the above functions: - */ - - - -void -ModelClientInterface::new_plugin(const string& type, - const string& uri, - const string& name) -{ - PluginModel* plugin = new PluginModel(type, uri); - plugin->name(name); - new_plugin_model(plugin); -} - - - -void -ModelClientInterface::new_patch(const string& path, uint32_t poly) -{ - PatchModel* pm = new PatchModel(path, poly); - PluginModel* pi = new PluginModel(PluginModel::Patch); - pm->plugin(pi); - new_patch_model(pm); -} - - - -void -ModelClientInterface::new_node(const string& plugin_type, - const string& plugin_uri, - const string& node_path, - bool is_polyphonic, - uint32_t num_ports) -{ - cerr << "FIXME: NEW NODE\n"; - - PluginModel* plugin = new PluginModel(plugin_type, plugin_uri); - - NodeModel* nm = new NodeModel(node_path); - nm->plugin(plugin); - - new_node_model(nm); -} - - - -void -ModelClientInterface::new_port(const string& path, - const string& type, - bool is_output) -{ - PortModel::Type ptype = PortModel::CONTROL; - if (type != "AUDIO") ptype = PortModel::AUDIO; - else if (type != "CONTROL") ptype = PortModel::CONTROL; - else if (type != "MIDI") ptype = PortModel::MIDI; - else cerr << "[ModelClientInterface] WARNING: Unknown port type received (" << type << ")" << endl; - - PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; - - PortModel* port_model = new PortModel(path, ptype, pdir); - new_port_model(port_model); -} - - - -void -ModelClientInterface::connection(const string& src_port_path, - const string& dst_port_path) -{ - connection_model(new ConnectionModel(src_port_path, dst_port_path)); -} - - - - -} // namespace LibOmClient diff --git a/src/clients/ModelClientInterface.h b/src/clients/ModelClientInterface.h deleted file mode 100644 index 1f5ea09d..00000000 --- a/src/clients/ModelClientInterface.h +++ /dev/null @@ -1,87 +0,0 @@ -/* This file is part of Om. 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 MODELCLIENTINTERFACE_H -#define MODELCLIENTINTERFACE_H - -#include -#include -using std::string; using std::auto_ptr; -#include "interface/ClientInterface.h" - -namespace LibOmClient { - -class PatchModel; -class NodeModel; -class ConnectionModel; -class PortModel; -class PluginModel; - - -/** A client interface that creates Model objects to represent the engine's state. - * - * This calls it's own methods with the models as parameters; clients can inherit - * this and implement a class with a similar interface to ClientInterface except - * with model classes passed where appropriate instead of primitives. - * - * \ingroup libomclient - */ -class ModelClientInterface : virtual public Om::Shared::ClientInterface -{ -public: - ModelClientInterface(Om::Shared::ClientInterface& extend) - : Om::Shared::ClientInterface(extend) - {} - - virtual ~ModelClientInterface() {} - - // FIXME: make these auto_ptr's - - virtual void new_plugin_model(PluginModel* pi); - virtual void new_patch_model(PatchModel* pm); - virtual void new_node_model(NodeModel* nm); - virtual void new_port_model(PortModel* port_info); - virtual void connection_model(ConnectionModel* cm); - - // ClientInterface functions to drive the above: - - virtual void new_plugin(const string& type, - const string& uri, - const string& name); - - virtual void new_patch(const string& path, uint32_t poly); - - virtual void new_node(const string& plugin_type, - const string& plugin_uri, - const string& node_path, - bool is_polyphonic, - uint32_t num_ports); - - virtual void new_port(const string& path, - const string& data_type, - bool is_output); - - virtual void connection(const string& src_port_path, - const string& dst_port_path); - -protected: - ModelClientInterface() {} -}; - - -} // namespace LibOmClient - -#endif // MODELCLIENTINTERFACE_H diff --git a/src/clients/ModelEngineInterface.h b/src/clients/ModelEngineInterface.h deleted file mode 100644 index aa041aef..00000000 --- a/src/clients/ModelEngineInterface.h +++ /dev/null @@ -1,58 +0,0 @@ -/* This file is part of Om. 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 MODELENGINEINTERFACE_H -#define MODELENGINEINTERFACE_H - -#include -#include -#include "interface/EngineInterface.h" -using std::string; - -/** \defgroup libomclient Client Library - */ - -namespace LibOmClient { - -class NodeModel; -class PresetModel; -class PatchModel; -class OSCListener; -class ModelClientInterface; - - -/** Model-based engine command interface. - * - * \ingroup libomclient - */ -class ModelEngineInterface -{ -public: - virtual ~ModelEngineInterface() {} - - virtual void create_patch_from_model(const PatchModel* pm) = 0; - virtual void create_node_from_model(const NodeModel* nm) = 0; - - virtual void set_all_metadata(const NodeModel* nm) = 0; - virtual void set_preset(const string& patch_path, const PresetModel* pm) = 0; - -protected: - ModelEngineInterface() {} -}; - -} // namespace LibOmClient - -#endif // MODELENGINEINTERFACE_H diff --git a/src/clients/NodeModel.cpp b/src/clients/NodeModel.cpp deleted file mode 100644 index efdae494..00000000 --- a/src/clients/NodeModel.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* This file is part of Om. 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 "NodeModel.h" -#include "PatchModel.h" -#include - -namespace LibOmClient { - - -NodeModel::NodeModel(const Path& path) -: ObjectModel(path), - m_polyphonic(false), - m_plugin(NULL), - m_x(0.0f), - m_y(0.0f) -{ -} - -NodeModel::~NodeModel() -{ - for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - delete(*i); -} - - -void -NodeModel::remove_port(const string& port_path) -{ - for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) { - if ((*i)->path() == port_path) { - m_ports.erase(i); - break; - } - } -} - - -void -NodeModel::clear() -{ - for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - delete (*i); - - m_ports.clear(); - - assert(m_ports.empty()); -} - - -void -NodeModel::set_path(const Path& p) -{ - const string old_path = m_path; - - ObjectModel::set_path(p); - - for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - (*i)->set_path(m_path + "/" + (*i)->name()); - - if (parent_patch() != NULL && old_path.length() > 0) - parent_patch()->rename_node(old_path, p); -} - - -void -NodeModel::add_port(PortModel* pm) -{ - assert(pm->name() != ""); - assert(pm->path().length() > m_path.length()); - assert(pm->path().substr(0, m_path.length()) == m_path); - assert(pm->parent() == NULL); - assert(get_port(pm->name()) == NULL); - - m_ports.push_back(pm); - pm->set_parent(this); -} - - -PortModel* -NodeModel::get_port(const string& port_name) -{ - assert(port_name.find("/") == string::npos); - for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - if ((*i)->name() == port_name) - return (*i); - return NULL; -} - - -void -NodeModel::add_program(int bank, int program, const string& name) -{ - m_banks[bank][program] = name; -} -void -NodeModel::remove_program(int bank, int program) -{ - m_banks[bank].erase(program); - if (m_banks[bank].size() == 0) - m_banks.erase(bank); -} - -} diff --git a/src/clients/NodeModel.h b/src/clients/NodeModel.h deleted file mode 100644 index af4171ed..00000000 --- a/src/clients/NodeModel.h +++ /dev/null @@ -1,93 +0,0 @@ -/* This file is part of Om. 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 NODEMODEL_H -#define NODEMODEL_H - -#include -#include -#include -#include -#include "ObjectModel.h" -#include "PortModel.h" -#include "util/Path.h" - -using std::string; using std::map; using std::find; -using std::cout; using std::cerr; using std::endl; - -namespace LibOmClient { - -class PatchModel; -class PluginModel; - - -/** Node model class, used by the client to store engine's state. - * - * \ingroup libomclient - */ -class NodeModel : public ObjectModel -{ -public: - NodeModel(const Path& node_path); - virtual ~NodeModel(); - - PortModel* get_port(const string& port_name); - void add_port(PortModel* pm); - void remove_port(const string& port_path); - - virtual void clear(); - - const map >& get_programs() const { return m_banks; } - void add_program(int bank, int program, const string& name); - void remove_program(int bank, int program); - - const PluginModel* plugin() const { return m_plugin; } - void plugin(const PluginModel* const pi) { m_plugin = pi; } - - virtual void set_path(const Path& p); - - int num_ports() const { return m_ports.size(); } - const PortModelList& ports() const { return m_ports; } - virtual bool polyphonic() const { return m_polyphonic; } - void polyphonic(bool b) { m_polyphonic = b; } - float x() const { return m_x; } - void x(float a) { m_x = a; } - float y() const { return m_y; } - void y(float a) { m_y = a; } - - PatchModel* parent_patch() const { return (PatchModel*)m_parent; } - -protected: - bool m_polyphonic; - PortModelList m_ports; ///< List of ports (instead of map to preserve order) - const PluginModel* m_plugin; ///< The plugin this node is an instance of - float m_x; ///< Just metadata, here as an optimization for OmGtk - float m_y; ///< Just metadata, here as an optimization for OmGtk - map > m_banks; ///< DSSI banks - -private: - // Prevent copies (undefined) - NodeModel(const NodeModel& copy); - NodeModel& operator=(const NodeModel& copy); -}; - - -typedef map NodeModelMap; - - -} // namespace LibOmClient - -#endif // NODEMODEL_H diff --git a/src/clients/OSCEngineInterface.cpp b/src/clients/OSCEngineInterface.cpp deleted file mode 100644 index 5ac598f1..00000000 --- a/src/clients/OSCEngineInterface.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "OSCEngineInterface.h" -#include "interface/ClientKey.h" - -namespace LibOmClient { - -/** Note the sending port is implicitly set by liblo, lo_send by default sends - * from the most recently created server, so create the OSC listener before - * this to have it all happen on the same port. Yeah, this is a big magic :/ - */ -OSCEngineInterface::OSCEngineInterface(const string& engine_url) -: _engine_url(engine_url) -, _engine_addr(lo_address_new_from_url(engine_url.c_str())) -, _id(0) -{ -} - - -OSCEngineInterface::~OSCEngineInterface() -{ - lo_address_free(_engine_addr); -} - - -/* *** EngineInterface implementation below here *** */ - - -/** Register with the engine via OSC. - * - * Note that this does not actually use 'key', since the engine creates - * it's own key for OSC clients (namely the incoming URL), for NAT - * traversal. It is a parameter to remain compatible with EngineInterface. - */ -void -OSCEngineInterface::register_client(ClientKey key, CountedPtr client) -{ - // FIXME: use parameters.. er, somehow. - assert(_engine_addr); - lo_send(_engine_addr, "/om/engine/register_client", "i", next_id()); -} - - -void -OSCEngineInterface::unregister_client(ClientKey key) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/engine/unregister_client", "i", next_id()); -} - - - -// Engine commands -void -OSCEngineInterface::load_plugins() -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/engine/load_plugins", "i", next_id()); -} - - -void -OSCEngineInterface::activate() -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/engine/activate", "i", next_id()); -} - - -void -OSCEngineInterface::deactivate() -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/engine/deactivate", "i", next_id()); -} - - -void -OSCEngineInterface::quit() -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/engine/quit", "i", next_id()); -} - - - -// Object commands - -void -OSCEngineInterface::create_patch(const string& path, - uint32_t poly) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/create_patch", "isi", - next_id(), - path.c_str(), - poly); -} - - -void -OSCEngineInterface::create_node(const string& path, - const string& plugin_type, - const string& plugin_uri, - bool polyphonic) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/create_node", "isssi", - next_id(), - path.c_str(), - plugin_type.c_str(), - plugin_uri.c_str(), - (polyphonic ? 1 : 0)); -} - - -void -OSCEngineInterface::rename(const string& old_path, - const string& new_name) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/rename", "iss", - next_id(), - old_path.c_str(), - new_name.c_str()); -} - - -void -OSCEngineInterface::destroy(const string& path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/destroy", "is", - next_id(), - path.c_str()); -} - - -void -OSCEngineInterface::clear_patch(const string& patch_path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/clear_patch", "is", - next_id(), - patch_path.c_str()); -} - - -void -OSCEngineInterface::enable_patch(const string& patch_path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/enable_patch", "is", - next_id(), - patch_path.c_str()); -} - - -void -OSCEngineInterface::disable_patch(const string& patch_path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/disable_patch", "is", - next_id(), - patch_path.c_str()); -} - - -void -OSCEngineInterface::connect(const string& src_port_path, - const string& dst_port_path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/connect", "iss", - next_id(), - src_port_path.c_str(), - dst_port_path.c_str()); -} - - -void -OSCEngineInterface::disconnect(const string& src_port_path, - const string& dst_port_path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/disconnect", "iss", - next_id(), - src_port_path.c_str(), - dst_port_path.c_str()); -} - - -void -OSCEngineInterface::disconnect_all(const string& node_path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/disconnect_all", "is", - next_id(), - node_path.c_str()); -} - - -void -OSCEngineInterface::set_port_value(const string& port_path, - float val) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/set_port_value", "isf", - next_id(), - port_path.c_str(), - val); -} - - -void -OSCEngineInterface::set_port_value(const string& port_path, - uint32_t voice, - float val) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/set_port_value", "isif", - next_id(), - port_path.c_str(), - voice, - val); -} - - -void -OSCEngineInterface::set_port_value_queued(const string& port_path, - float val) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/set_port_value_queued", "isf", - next_id(), - port_path.c_str(), - val); -} - - -void -OSCEngineInterface::set_program(const string& node_path, - uint32_t bank, - uint32_t program) -{ - assert(_engine_addr); - lo_send(_engine_addr, - (string("/dssi") + node_path + "/program").c_str(), - "ii", - bank, - program); -} - - -void -OSCEngineInterface::midi_learn(const string& node_path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/midi_learn", "is", - next_id(), - node_path.c_str()); -} - - -void -OSCEngineInterface::set_metadata(const string& obj_path, - const string& predicate, - const string& value) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/metadata/set", "isss", - next_id(), - obj_path.c_str(), - predicate.c_str(), - value.c_str()); -} - - -// Requests // - -void -OSCEngineInterface::ping() -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/ping", "i", next_id()); -} - - -void -OSCEngineInterface::request_port_value(const string& port_path) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/request/port_value", "is", - next_id(), - port_path.c_str()); -} - - -void -OSCEngineInterface::request_plugins() -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/request/plugins", "i", next_id()); -} - - -void -OSCEngineInterface::request_all_objects() -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/request/all_objects", "i", next_id()); -} - - - -} // namespace LibOmClient - - diff --git a/src/clients/OSCEngineInterface.h b/src/clients/OSCEngineInterface.h deleted file mode 100644 index 63157da1..00000000 --- a/src/clients/OSCEngineInterface.h +++ /dev/null @@ -1,139 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 OSCENGINEINTERFACE_H -#define OSCENGINEINTERFACE_H - -#include -#include -#include -#include "interface/EngineInterface.h" -using std::string; -using Om::Shared::EngineInterface; -using Om::Shared::ClientInterface; -using Om::Shared::ClientKey; - - -namespace LibOmClient { - -/* OSC (via liblo) interface to the engine. - * - * Clients can use this opaquely as an EngineInterface* to control the engine - * over OSC (whether over a network or not, etc). - * - * \ingroup libomclient - */ -class OSCEngineInterface : public EngineInterface -{ -public: - OSCEngineInterface(const string& engine_url); - - ~OSCEngineInterface(); - - string engine_url() { return _engine_url; } - - inline size_t next_id() - { if (_id != -1) { _id = (_id == -2) ? 0 : _id+1; } return _id; } - - void enable_responses() { _id = 0; } - void disable_responses() { _id = -1; } - - - /* *** EngineInterface implementation below here *** */ - - // Client registration - void register_client(ClientKey key, CountedPtr client); - void unregister_client(ClientKey key); - - - // Engine commands - void load_plugins(); - void activate(); - void deactivate(); - void quit(); - - - // Object commands - - void create_patch(const string& path, - uint32_t poly); - - void create_node(const string& path, - const string& plugin_type, - const string& plugin_uri, - bool polyphonic); - - void rename(const string& old_path, - const string& new_name); - - void destroy(const string& path); - - void clear_patch(const string& patch_path); - - void enable_patch(const string& patch_path); - - void disable_patch(const string& patch_path); - - void connect(const string& src_port_path, - const string& dst_port_path); - - void disconnect(const string& src_port_path, - const string& dst_port_path); - - void disconnect_all(const string& node_path); - - void set_port_value(const string& port_path, - float val); - - void set_port_value(const string& port_path, - uint32_t voice, - float val); - - void set_port_value_queued(const string& port_path, - float val); - - void set_program(const string& node_path, - uint32_t bank, - uint32_t program); - - void midi_learn(const string& node_path); - - void set_metadata(const string& obj_path, - const string& predicate, - const string& value); - - // Requests // - - void ping(); - - void request_port_value(const string& port_path); - - void request_plugins(); - - void request_all_objects(); - -protected: - string _engine_url; - lo_address _engine_addr; - int _client_port; - int32_t _id; -}; - - -} // namespace LibOmClient - -#endif // OSCENGINEINTERFACE_H - diff --git a/src/clients/OSCListener.cpp b/src/clients/OSCListener.cpp deleted file mode 100644 index 503be47d..00000000 --- a/src/clients/OSCListener.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* This file is part of Om. 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 "OSCListener.h" -//#include "NodeModel.h" -//#include "PluginModel.h" -#include -#include -#include -#include -using std::cerr; using std::cout; using std::endl; - -namespace LibOmClient { - - -/** Construct a OSCListener with a user-provided ModelClientInterface object for notification - * of engine events. - */ -OSCListener::OSCListener(int listen_port) -: _listen_port(listen_port), - _st(NULL)//, -// _receiving_node(false), -// _receiving_node_model(NULL), -// _receiving_node_num_ports(0), -// _num_received_ports(0) -{ - start(); -} - - -OSCListener::~OSCListener() -{ - stop(); -} - - -void -OSCListener::start() -{ - if (_st != NULL) - return; - - if (_listen_port == 0) { - _st = lo_server_thread_new(NULL, error_cb); - _listen_port = lo_server_thread_get_port(_st); - } else { - char port_str[8]; - snprintf(port_str, 8, "%d", _listen_port); - _st = lo_server_thread_new(port_str, error_cb); - } - - if (_st == NULL) { - cerr << "[OSCListener] Could not start OSC listener. Aborting." << endl; - exit(EXIT_FAILURE); - } else { - cout << "[OSCListener] Started OSC listener on port " << lo_server_thread_get_port(_st) << endl; - } - - // FIXME - lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL); - - //lo_server_thread_add_method(_st, "/om/response/ok", "i", om_response_ok_cb, this); - //lo_server_thread_add_method(_st, "/om/response/error", "is", om_responseerror_cb, this); - - setup_callbacks(); - - // Display any uncaught messages to the console - //lo_server_thread_add_method(_st, NULL, NULL, unknown_cb, NULL); - - lo_server_thread_start(_st); -} - - -void -OSCListener::stop() -{ - if (_st != NULL) { - //unregister_client(); - lo_server_thread_free(_st); - _st = NULL; - } -} - - -int -OSCListener::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) -{ - printf("[OSCMsg] %s (%s)\t", path, types); - - for (int i=0; i < argc; ++i) { - lo_arg_pp(lo_type(types[i]), argv[i]); - printf("\t"); - } - printf("\n"); - - /*for (int i=0; i < argc; ++i) { - printf(" '%c' ", types[i]); - lo_arg_pp(lo_type(types[i]), argv[i]); - printf("\n"); - } - printf("\n");*/ - - return 1; // not handled -} - - -void -OSCListener::error_cb(int num, const char* msg, const char* path) -{ - cerr << "Got error from server: " << msg << endl; -} - - - -int -OSCListener::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) -{ - string msg = "Received unknown OSC message: "; - msg += path; - - cerr << msg << endl; - - return 0; -} - - -void -OSCListener::setup_callbacks() -{ - lo_server_thread_add_method(_st, "/om/num_plugins", "i", num_plugins_cb, this); - lo_server_thread_add_method(_st, "/om/plugin", "sss", plugin_cb, this); - lo_server_thread_add_method(_st, "/om/new_patch", "si", new_patch_cb, this); - lo_server_thread_add_method(_st, "/om/destroyed", "s", destroyed_cb, this); - lo_server_thread_add_method(_st, "/om/patch_enabled", "s", patch_enabled_cb, this); - lo_server_thread_add_method(_st, "/om/patch_disabled", "s", patch_disabled_cb, this); - lo_server_thread_add_method(_st, "/om/patch_cleared", "s", patch_cleared_cb, this); - lo_server_thread_add_method(_st, "/om/object_renamed", "ss", object_renamed_cb, this); - lo_server_thread_add_method(_st, "/om/new_connection", "ss", connection_cb, this); - lo_server_thread_add_method(_st, "/om/disconnection", "ss", disconnection_cb, this); - lo_server_thread_add_method(_st, "/om/new_node", "sssii", new_node_cb, this); - lo_server_thread_add_method(_st, "/om/new_port", "ssi", new_port_cb, this); - lo_server_thread_add_method(_st, "/om/metadata/update", "sss", metadata_update_cb, this); - lo_server_thread_add_method(_st, "/om/control_change", "sf", control_change_cb, this); - lo_server_thread_add_method(_st, "/om/program_add", "siis", program_add_cb, this); - lo_server_thread_add_method(_st, "/om/program_remove", "sii", program_remove_cb, this); -} - - -/** Catches errors that aren't a direct result of a client request. - */ -int -OSCListener::m_error_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - cerr << "ERROR: " << argv[0]->s << endl; - // FIXME - //error((char*)argv[0]); - return 0; -} - - -int -OSCListener::m_new_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - new_patch(&argv[0]->s, argv[1]->i); // path, poly - return 0; -} - - -int -OSCListener::m_destroyed_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - object_destroyed((const char*)&argv[0]->s); - return 0; -} - - -int -OSCListener::m_patch_enabled_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - patch_enabled((const char*)&argv[0]->s); - return 0; -} - - -int -OSCListener::m_patch_disabled_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - patch_disabled((const char*)&argv[0]->s); - return 0; -} - - -int -OSCListener::m_patch_cleared_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - patch_cleared((const char*)&argv[0]->s); - return 0; -} - - -int -OSCListener::m_object_renamed_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - object_renamed((const char*)&argv[0]->s, (const char*)&argv[1]->s); - return 0; -} - - -int -OSCListener::m_connection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* const src_port_path = &argv[0]->s; - const char* const dst_port_path = &argv[1]->s; - - connection(src_port_path, dst_port_path); - - return 0; -} - - -int -OSCListener::m_disconnection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* src_port_path = &argv[0]->s; - const char* dst_port_path = &argv[1]->s; - - disconnection(src_port_path, dst_port_path); - - return 0; -} - - -/** Notification of a new node creation. - */ -int -OSCListener::m_new_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* type = &argv[0]->s; - const char* uri = &argv[1]->s; - const char* node_path = &argv[2]->s; - const int32_t poly = argv[3]->i; - const int32_t num_ports = argv[4]->i; - - new_node(type, uri, node_path, poly, num_ports); - - /*_receiving_node_model = new NodeModel(node_path); - _receiving_node_model->polyphonic((poly == 1)); - _receiving_node_num_ports = num_ports; - - PluginModel* pi = new PluginModel(type, uri); - _receiving_node_model->plugin(pi); - - _receiving_node = true; - _num_received_ports = 0; - */ - return 0; -} - - -/** Notification of a new port creation. - */ -int -OSCListener::m_new_port_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* port_path = &argv[0]->s; - const char* type = &argv[1]->s; - bool is_output = (argv[2]->i == 1); - /*const char* direction = &argv[2]->s; - const char* hint = &argv[3]->s; - float default_val = argv[4]->f; - float min_val = argv[5]->f; - float max_val = argv[6]->f;*/ - - new_port(port_path, type, is_output); -#if 0 - PortModel::Type ptype = PortModel::CONTROL; - if (!strcmp(type, "AUDIO")) ptype = PortModel::AUDIO; - else if (!strcmp(type, "CONTROL")) ptype = PortModel::CONTROL; - else if (!strcmp(type, "MIDI")) ptype = PortModel::MIDI; - else cerr << "[OSCListener] WARNING: Unknown port type received (" << type << ")" << endl; - -#if 0 - PortModel::Direction pdir = PortModel::INPUT; - if (!strcmp(direction, "INPUT")) pdir = PortModel::INPUT; - else if (!strcmp(direction, "OUTPUT")) pdir = PortModel::OUTPUT; - else cerr << "[OSCListener] WARNING: Unknown port direction received (" << direction << ")" << endl; -#endif - PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; - -/* - PortModel::Hint phint = PortModel::NONE; - if (!strcmp(hint, "LOGARITHMIC")) phint = PortModel::LOGARITHMIC; - else if (!strcmp(hint, "INTEGER")) phint = PortModel::INTEGER; - else if (!strcmp(hint, "TOGGLE")) phint = PortModel::TOGGLE; - - PortModel* port_model = new PortModel(port_path, ptype, pdir, phint, default_val, min_val, max_val); -*/ - PortModel* port_model = new PortModel(port_path, ptype, pdir); - if (m_receiving_node) { - assert(m_receiving_node_model); - m_receiving_node_model->add_port(port_model); - ++m_num_received_ports; - - // If transmission is done, send new node to client - if (m_num_received_ports == m_receiving_node_num_ports) { - new_node_model(m_receiving_node_model); - m_receiving_node = false; - m_receiving_node_model = NULL; - m_num_received_ports = 0; - } - } else { - new_port_model(port_model); - } - -#endif - return 0; -} - - -/** Notification of a new or updated piece of metadata. - */ -int -OSCListener::m_metadata_update_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* obj_path = &argv[0]->s; - const char* key = &argv[1]->s; - const char* value = &argv[2]->s; - - metadata_update(obj_path, key, value); - - return 0; -} - - -int -OSCListener::m_control_change_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* const port_path = &argv[0]->s; - const float value = argv[1]->f; - - control_change(port_path, value); - - return 0; -} - - -/** Number of plugins in engine, should precede /om/plugin messages in response - * to a /om/send_plugins - */ -int -OSCListener::m_num_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - /** Not worth it implementing a ModelClientInterface callback for this (?) - * Or I'm just lazy. FIXME? */ - num_plugins(argv[0]->i); - - return 0; -} - - -/** A plugin info response from the server, in response to a /send_plugins - */ -int -OSCListener::m_plugin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - assert(argc == 3 && !strcmp(types, "sss")); - new_plugin(&argv[0]->s, &argv[1]->s, &argv[2]->s); // type, uri - - return 0; -} - - -int -OSCListener::m_program_add_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* node_path = &argv[0]->s; - int32_t bank = argv[1]->i; - int32_t program = argv[2]->i; - const char* name = &argv[3]->s; - - program_add(node_path, bank, program, name); - - return 0; -} - - -int -OSCListener::m_program_remove_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) -{ - const char* node_path = &argv[0]->s; - int32_t bank = argv[1]->i; - int32_t program = argv[2]->i; - - program_remove(node_path, bank, program); - - return 0; -} - - -} // namespace LibOmClient diff --git a/src/clients/OSCListener.h b/src/clients/OSCListener.h deleted file mode 100644 index d0b9cc1c..00000000 --- a/src/clients/OSCListener.h +++ /dev/null @@ -1,116 +0,0 @@ -/* This file is part of Om. 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 OSCLISTENER_H -#define OSCLISTENER_H - -#include -#include -#include "interface/ClientInterface.h" - -namespace LibOmClient { - -//class NodeModel; -//class PresetModel; - -/* Some boilerplate killing macros... */ -#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg - -/* Defines a static handler to be passed to lo_add_method, which is a trivial - * wrapper around a non-static method that does the real work. Makes a whoole - * lot of ugly boiler plate go away */ -#define LO_HANDLER(name) \ -int m_##name##_cb (LO_HANDLER_ARGS);\ -inline static int name##_cb(LO_HANDLER_ARGS, void* osc_listener)\ -{ return ((OSCListener*)osc_listener)->m_##name##_cb(path, types, argv, argc, msg); } - - -/** Callbacks for "notification band" OSC messages. - * - * Receives all notification of engine state, but not replies on the "control - * band". See OSC namespace documentation for details. - * - * Right now this class and Comm share the same lo_server_thread and the barrier - * between them is a bit odd, but eventually this class will be able to listen - * on a completely different port (ie have it's own lo_server_thread) to allow - * things like listening to the notification band over TCP while sending commands - * on the control band over UDP. - * - * \ingroup libomclient - */ -class OSCListener : virtual public Om::Shared::ClientInterface -{ -public: - OSCListener(int listen_port); - ~OSCListener(); - - void start(); - void stop(); - - int listen_port() { return _listen_port; } - string listen_url() { return lo_server_thread_get_url(_st); } - -private: - // Prevent copies - OSCListener(const OSCListener& copy); - OSCListener& operator=(const OSCListener& copy); - - void setup_callbacks(); - - static void error_cb(int num, const char* msg, const char* path); - static int generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data); - static int unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* osc_receiver); - /* - inline static int om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm); - int m_om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data); - inline static int om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm); - int m_om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data); -*/ - int _listen_port; - lo_server_thread _st; - - // Used for receiving nodes - multiple messages are received before - // sending an event to the client (via ModelClientInterface) - //bool _receiving_node; - //NodeModel* _receiving_node_model; - //int32_t _receiving_node_num_ports; - //int32_t _num_received_ports; - - LO_HANDLER(error); - LO_HANDLER(num_plugins); - LO_HANDLER(plugin); - LO_HANDLER(plugin_list_end); - LO_HANDLER(new_patch); - LO_HANDLER(destroyed); - LO_HANDLER(patch_enabled); - LO_HANDLER(patch_disabled); - LO_HANDLER(patch_cleared); - LO_HANDLER(object_renamed); - LO_HANDLER(connection); - LO_HANDLER(disconnection); - LO_HANDLER(new_node); - LO_HANDLER(new_port); - LO_HANDLER(metadata_update); - LO_HANDLER(control_change); - LO_HANDLER(program_add); - LO_HANDLER(program_remove); -}; - - -} // namespace LibOmClient - -#endif // OSCLISTENER_H diff --git a/src/clients/OSCModelEngineInterface.cpp b/src/clients/OSCModelEngineInterface.cpp deleted file mode 100644 index 9e648141..00000000 --- a/src/clients/OSCModelEngineInterface.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* This file is part of Om. 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 "OSCModelEngineInterface.h" -#include -#include -#include -#include -#include -#include -#include "OSCListener.h" -#include "PatchModel.h" -#include "ConnectionModel.h" -#include "PresetModel.h" -#include "ControlModel.h" -#include "NodeModel.h" -#include "PluginModel.h" - -using std::cerr; using std::cout; using std::endl; - -namespace LibOmClient { - - -/** Construct a OSCModelEngineInterface with a user-provided ModelClientInterface object for notification - * of engine events. - */ -OSCModelEngineInterface::OSCModelEngineInterface(const string& engine_url) -: OSCEngineInterface(engine_url), - m_request_id(0), - m_is_attached(false), - m_is_registered(false) - /*m_blocking(false), - m_waiting_for_response(false), - m_wait_response_id(0), - m_response_received(false), - m_wait_response_was_affirmative(false), - m_response_semaphore(0)*/ -{ -} - - -OSCModelEngineInterface::~OSCModelEngineInterface() -{ - detach(); -} - - -/** Attempt to connect to the Om engine and notify it of our existance. - * - * Passing a client_port of 0 will automatically choose a free port. If the - * @a block parameter is true, this function will not return until a connection - * has successfully been made. - */ -void -OSCModelEngineInterface::attach(bool block) -{ - cerr << "FIXME: listen thread\n"; - //start_listen_thread(_client_port); - - /*if (engine_url == "") { - string local_url = m_osc_listener->listen_url().substr( - 0, m_osc_listener->listen_url().find_last_of(":")); - local_url.append(":16180"); - _engine_addr = lo_address_new_from_url(local_url.c_str()); - } else { - _engine_addr = lo_address_new_from_url(engine_url.c_str()); - } - */ - _engine_addr = lo_address_new_from_url(_engine_url.c_str()); - - if (_engine_addr == NULL) { - cerr << "Unable to connect, aborting." << endl; - exit(EXIT_FAILURE); - } - - char* lo_url = lo_address_get_url(_engine_addr); - cout << "[OSCModelEngineInterface] Attempting to contact engine at " << lo_url << " ..." << endl; - - this->ping(); - - m_is_attached = true; // FIXME - - /*if (block) { - set_wait_response_id(request_id); - - while (1) { - if (m_response_semaphore.try_wait() != 0) { - cout << "."; - cout.flush(); - ping(request_id); - usleep(100000); - } else { - cout << " connected." << endl; - m_waiting_for_response = false; - break; - } - } - } - */ - - free(lo_url); -} - -void -OSCModelEngineInterface::detach() -{ - m_is_attached = false; -} - -#if 0 -void -OSCModelEngineInterface::start_listen_thread(int client_port) -{ - if (m_st != NULL) - return; - - if (client_port == 0) { - m_st = lo_server_thread_new(NULL, error_cb); - } else { - char port_str[8]; - snprintf(port_str, 8, "%d", client_port); - m_st = lo_server_thread_new(port_str, error_cb); - } - - if (m_st == NULL) { - cerr << "[OSCModelEngineInterface] Could not start OSC listener. Aborting." << endl; - exit(EXIT_FAILURE); - } else { - cout << "[OSCModelEngineInterface] Started OSC listener on port " << lo_server_thread_get_port(m_st) << endl; - } - - lo_server_thread_add_method(m_st, NULL, NULL, generic_cb, NULL); - - lo_server_thread_add_method(m_st, "/om/response/ok", "i", om_response_ok_cb, this); - lo_server_thread_add_method(m_st, "/om/response/error", "is", om_response_error_cb, this); - - - m_osc_listener = new OSCListener(m_st, m_client_hooks); - m_osc_listener->setup_callbacks(); - - // Display any uncaught messages to the console - lo_server_thread_add_method(m_st, NULL, NULL, unknown_cb, NULL); - - lo_server_thread_start(m_st); -} -#endif - -///// OSC Commands ///// - - - -/** Load a node. - */ -void -OSCModelEngineInterface::create_node_from_model(const NodeModel* nm) -{ - assert(_engine_addr); - - // Load by URI - if (nm->plugin()->uri().length() > 0) { - lo_send(_engine_addr, "/om/synth/create_node", "isssi", next_id(), - nm->path().c_str(), - nm->plugin()->type_string(), - nm->plugin()->uri().c_str(), - (nm->polyphonic() ? 1 : 0)); - // Load by libname, label - } else { - //assert(nm->plugin()->lib_name().length() > 0); - assert(nm->plugin()->plug_label().length() > 0); - lo_send(_engine_addr, "/om/synth/create_node", "issssi", next_id(), - nm->path().c_str(), - nm->plugin()->type_string(), - nm->plugin()->lib_name().c_str(), - nm->plugin()->plug_label().c_str(), - (nm->polyphonic() ? 1 : 0)); - } -} - - -/** Create a patch. - */ -void -OSCModelEngineInterface::create_patch_from_model(const PatchModel* pm) -{ - assert(_engine_addr); - lo_send(_engine_addr, "/om/synth/create_patch", "isi", next_id(), pm->path().c_str(), pm->poly()); -} - - -/** Notify LASH restoring is finished */ -/* -void -OSCModelEngineInterface::lash_restore_finished() -{ - assert(_engine_addr != NULL); - int id = m_request_id++; - lo_send(_engine_addr, "/om/lash/restore_finished", "i", id); -} -*/ -#if 0 -/** Set/add a piece of metadata. - */ -void -OSCModelEngineInterface::set_metadata(const string& obj_path, - const string& key, const string& value) -{ - assert(_engine_addr != NULL); - int id = m_request_id++; - - // Deal with the "special" DSSI metadata strings - if (key.substr(0, 16) == "dssi-configure--") { - string path = "/dssi" + obj_path + "/configure"; - string dssi_key = key.substr(16); - lo_send(_engine_addr, path.c_str(), "ss", dssi_key.c_str(), value.c_str()); - } else if (key == "dssi-program") { - string path = "/dssi" + obj_path + "/program"; - string dssi_bank_str = value.substr(0, value.find("/")); - int dssi_bank = atoi(dssi_bank_str.c_str()); - string dssi_program_str = value.substr(value.find("/")+1); - int dssi_program = atoi(dssi_program_str.c_str()); - lo_send(_engine_addr, path.c_str(), "ii", dssi_bank, dssi_program); - } - - // Normal metadata - lo_send(_engine_addr, "/om/metadata/set", "isss", id, - obj_path.c_str(), key.c_str(), value.c_str()); -} -#endif - -/** Set all pieces of metadata in a NodeModel. - */ -void -OSCModelEngineInterface::set_all_metadata(const NodeModel* nm) -{ - assert(_engine_addr != NULL); - - for (map::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) - set_metadata(nm->path(), (*i).first, (*i).second.c_str()); -} - - -/** Set a preset by setting all relevant controls for a patch. - */ -void -OSCModelEngineInterface::set_preset(const string& patch_path, const PresetModel* const pm) -{ - assert(patch_path.find("//") == string::npos); - for (list::const_iterator i = pm->controls().begin(); i != pm->controls().end(); ++i) { - set_port_value_queued((*i).port_path(), (*i).value()); - usleep(1000); - } -} - - -///// Requests ///// - - -#if 0 -/** Sets the response ID to be waited for on the next call to wait_for_response() - */ - -void -OSCModelEngineInterface::set_wait_response_id(int id) -{ - assert(!m_waiting_for_response); - m_wait_response_id = id; - m_response_received = false; - m_waiting_for_response = true; -} - - -/** Waits for the response set by set_wait_response() from the server. - * - * Returns whether or not the response was positive (ie a success message) - * or negative (ie an error) - */ -bool -OSCModelEngineInterface::wait_for_response() -{ - cerr << "[OSCModelEngineInterface] Waiting for response " << m_wait_response_id << ": "; - bool ret = true; - - assert(m_waiting_for_response); - assert(!m_response_received); - - while (!m_response_received) - m_response_semaphore.wait(); - - cerr << " received." << endl; - - m_waiting_for_response = false; - ret = m_wait_response_was_affirmative; - - return ret; -} -#endif - -///// Static OSC callbacks ////// - - -//// End static callbacks, member callbacks below //// - -/* -int -OSCModelEngineInterface::m_om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data) -{ - assert(argc == 1 && !strcmp(types, "i")); - - // FIXME - if (!m_is_attached) - m_is_attached = true; - - if (m_waiting_for_response) { - const int request_id = argv[0]->i; - - if (request_id == m_wait_response_id) { - m_response_received = true; - m_wait_response_was_affirmative = true; - m_response_semaphore.post(); - } - } - - return 0; -} - - -int -OSCModelEngineInterface::m_om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data) -{ - assert(argc == 2 && !strcmp(types, "is")); - - const int request_id = argv[0]->i; - const char* msg = &argv[1]->s; - - if (m_waiting_for_response) { - if (request_id == m_wait_response_id) { - m_response_received = true; - m_wait_response_was_affirmative = false; - m_response_semaphore.post(); - } - } - - cerr << "ERROR: " << msg << endl; - //if (m_client_hooks != NULL) - // m_client_hooks->error(msg); - - return 0; -} -*/ - -} // namespace LibOmClient diff --git a/src/clients/OSCModelEngineInterface.h b/src/clients/OSCModelEngineInterface.h deleted file mode 100644 index 4400a1b4..00000000 --- a/src/clients/OSCModelEngineInterface.h +++ /dev/null @@ -1,117 +0,0 @@ -/* This file is part of Om. 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 OSCCONTROLLER_H -#define OSCCONTROLLER_H - -#include -#include -#include "util/Semaphore.h" -#include "interface/EngineInterface.h" -#include "OSCEngineInterface.h" -#include "ModelEngineInterface.h" -using std::string; - -/** \defgroup libomclient Client Library - */ - -namespace LibOmClient { - -class NodeModel; -class PresetModel; -class PatchModel; -class OSCListener; -class ModelClientInterface; - - -/** Old model-based OSC engine command interface. - * - * This is an old class from before when the well-defined interfaces between - * engine and client were defined. I've wrapped it around OSCEngineInterface - * so all the common functions are implemented there, and implemented the - * remaining functions using those, for compatibility. Hopefully something - * better gets figured out and this can go away completely, but for now this - * gets the existing clients working through EngineInterface in the easiest - * way possible. This class needs to die. - * - * Old comment: - * Handles all OSC communication on the "control band". For the time being, - * manages the OSCListener which handles the "notification band", but this - * will change in the future (for complete separation). See OSC namespace - * documentation for more details. - * - * \ingroup libomclient - */ -class OSCModelEngineInterface : public OSCEngineInterface, public ModelEngineInterface -{ -public: - //OSCModelEngineInterface(ModelClientInterface* const client_hooks, const string& engine_url); - OSCModelEngineInterface(const string& engine_url); - ~OSCModelEngineInterface(); - - void attach(bool block = true); - void detach(); - - bool is_attached() { return m_is_attached; } - - // FIXME: reimplement - void set_wait_response_id(int32_t id) {} - bool wait_for_response() { return false; } - int get_next_request_id() { return m_request_id++; } - - /* *** Model alternatives to EngineInterface functions below *** */ - - void create_patch_from_model(const PatchModel* pm); - void create_node_from_model(const NodeModel* nm); - - void set_all_metadata(const NodeModel* nm); - void set_preset(const string& patch_path, const PresetModel* const pm); - -protected: - void start_listen_thread(); - - int m_request_id; - - bool m_is_attached; - bool m_is_registered; - /* - bool m_blocking; - bool m_waiting_for_response; - int m_wait_response_id; - bool m_response_received; - bool m_wait_response_was_affirmative; - - Semaphore m_response_semaphore; - */ -private: - // Prevent copies - OSCModelEngineInterface(const OSCModelEngineInterface& copy); - OSCModelEngineInterface& operator=(const OSCModelEngineInterface& copy); -}; -/* -inline int -OSCModelEngineInterface::om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm) { - return ((OSCModelEngineInterface*)comm)->m_om_response_ok_cb(path, types, argv, argc, data); -} - -inline int -OSCModelEngineInterface::om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm) { - return ((OSCModelEngineInterface*)comm)->m_om_response_error_cb(path, types, argv, argc, data); -} -*/ -} // namespace LibOmClient - -#endif // OSCCONTROLLER_H diff --git a/src/clients/ObjectController.h b/src/clients/ObjectController.h deleted file mode 100644 index c79ac24d..00000000 --- a/src/clients/ObjectController.h +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of Om. 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 OBJECTCONTROLLER_H -#define OBJECTCONTROLLER_H - -namespace LibOmClient { - - -/** A trivial base class for controllers of an ObjectModel. - * - * This is so ObjectModels can have pointers to app-specified controllers, - * and the pointer relationships in models (ie PatchModel has pointers to - * all it's NodeModel children, etc) can be used to find controllers of - * Models, rather than having a parallel structure of pointers in the - * app's controllers. - * - * \ingroup libomclient - */ -class ObjectController -{ -public: - virtual ~ObjectController() {} -}; - - -} // namespace LibOmClient - - -#endif // OBJECTCONTROLLER_H diff --git a/src/clients/ObjectModel.cpp b/src/clients/ObjectModel.cpp deleted file mode 100644 index cb196f8a..00000000 --- a/src/clients/ObjectModel.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* This file is part of Om. 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 "ObjectModel.h" - -namespace LibOmClient { - - -ObjectModel::ObjectModel(const string& path) -: m_path(path), - m_parent(NULL), - m_controller(NULL) -{ -} - - -/** Get a piece of metadata for this objeect. - * - * @return Metadata value with key @a key, empty string otherwise. - */ -string -ObjectModel::get_metadata(const string& key) const -{ - map::const_iterator i = m_metadata.find(key); - if (i != m_metadata.end()) - return (*i).second; - else - return ""; -} - - -/** The base path for children of this Object. - * - * (This is here to avoid needing special cases for the root patch everywhere). - */ -string -ObjectModel::base_path() const -{ - return (path() == "/") ? "/" : path() + "/"; -} - - -void -ObjectModel::set_controller(ObjectController* c) -{ - assert(m_controller == NULL); - m_controller = c; -} - -} // namespace LibOmClient - diff --git a/src/clients/ObjectModel.h b/src/clients/ObjectModel.h deleted file mode 100644 index be58a00f..00000000 --- a/src/clients/ObjectModel.h +++ /dev/null @@ -1,84 +0,0 @@ -/* This file is part of Om. 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 OBJECTMODEL_H -#define OBJECTMODEL_H - -#include -#include -#include -#include -#include -#include -#include "util/Path.h" - -using std::string; using std::map; using std::find; -using std::cout; using std::cerr; using std::endl; -using Om::Path; - -namespace LibOmClient { - -class ObjectController; - - -/** Base class for all OmObject models (NodeModel, PatchModel, PortModel). - * - * \ingroup libomclient - */ -class ObjectModel -{ -public: - ObjectModel(const string& path); - ObjectModel() : m_path("/UNINITIALIZED"), m_parent(NULL) {} // FIXME: remove - - virtual ~ObjectModel() {} - - const map& metadata() const { return m_metadata; } - string get_metadata(const string& key) const; - void set_metadata(const string& key, const string& value) - { assert(value.length() > 0); m_metadata[key] = value; } - - inline const Path& path() const { return m_path; } - virtual void set_path(const Path& p) { m_path = p; } - - ObjectModel* parent() const { return m_parent; } - virtual void set_parent(ObjectModel* p) { m_parent = p; } - - ObjectController* controller() const { return m_controller; } - - void set_controller(ObjectController* c); - - // Convenience functions - string base_path() const; - const string name() const { return m_path.name(); } - -protected: - Path m_path; - ObjectModel* m_parent; - ObjectController* m_controller; - - map m_metadata; - -private: - // Prevent copies (undefined) - ObjectModel(const ObjectModel& copy); - ObjectModel& operator=(const ObjectModel& copy); -}; - - -} // namespace LibOmClient - -#endif // OBJECTMODEL_H diff --git a/src/clients/PatchLibrarian.cpp b/src/clients/PatchLibrarian.cpp deleted file mode 100644 index 65323435..00000000 --- a/src/clients/PatchLibrarian.cpp +++ /dev/null @@ -1,834 +0,0 @@ -/* This file is part of Om. 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 "PatchLibrarian.h" -#include -#include -#include -#include "PatchModel.h" -#include "NodeModel.h" -#include "ModelClientInterface.h" -#include "ConnectionModel.h" -#include "PortModel.h" -#include "PresetModel.h" -#include "OSCModelEngineInterface.h" -#include "PluginModel.h" -#include "util/Path.h" -#include -#include -#include -#include // for pair, make_pair -#include -#include -#include -#include // for usleep -#include // for atof -#include - -using std::string; using std::vector; using std::pair; -using std::cerr; using std::cout; using std::endl; - -namespace LibOmClient { - - -/** Searches for the filename passed in the path, returning the full - * path of the file, or the empty string if not found. - * - * This function tries to be as friendly a black box as possible - if the path - * passed is an absolute path and the file is found there, it will return - * that path, etc. - * - * additional_path is a list (colon delimeted as usual) of additional - * directories to look in. ie the directory the parent patch resides in would - * be a good idea to pass as additional_path, in the case of a subpatch. - */ -string -PatchLibrarian::find_file(const string& filename, const string& additional_path) -{ - string search_path = additional_path + ":" + m_patch_path; - - // Try to open the raw filename first - std::ifstream is(filename.c_str(), std::ios::in); - if (is.good()) { - is.close(); - return filename; - } - - string directory; - string full_patch_path = ""; - - while (search_path != "") { - directory = search_path.substr(0, search_path.find(':')); - if (search_path.find(':') != string::npos) - search_path = search_path.substr(search_path.find(':')+1); - else - search_path = ""; - - full_patch_path = directory +"/"+ filename; - - std::ifstream is; - is.open(full_patch_path.c_str(), std::ios::in); - - if (is.good()) { - is.close(); - return full_patch_path; - } else { - cerr << "[PatchLibrarian] Could not find patch file " << full_patch_path << endl; - } - } - - return ""; -} - - -/** Save a patch from a PatchModel to a filename. - * - * The filename passed is the true filename the patch will be saved to (with no prefixing or anything - * like that), and the patch_model's filename member will be set accordingly. - * - * This will break if: - * - The filename does not have an extension (ie contain a ".") - * - The patch_model has no (Om) path - */ -void -PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool recursive) -{ - assert(filename != ""); - assert(patch_model->path() != ""); - - cout << "Saving patch " << patch_model->path() << " to " << filename << endl; - - patch_model->filename(filename); - - string dir = filename.substr(0, filename.find_last_of("/")); - - NodeModel* nm = NULL; - PatchModel* spm = NULL; // subpatch model - - xmlDocPtr xml_doc = NULL; - xmlNodePtr xml_root_node = NULL; - xmlNodePtr xml_node = NULL; - xmlNodePtr xml_child_node = NULL; - xmlNodePtr xml_grandchild_node = NULL; - - xml_doc = xmlNewDoc((xmlChar*)"1.0"); - xml_root_node = xmlNewNode(NULL, (xmlChar*)"patch"); - xmlDocSetRootElement(xml_doc, xml_root_node); - - const size_t temp_buf_length = 255; - char temp_buf[temp_buf_length]; - - string patch_name; - if (patch_model->path() != "/") { - patch_name = patch_model->name(); - } else { - patch_name = filename; - if (patch_name.find("/") != string::npos) - patch_name = patch_name.substr(patch_name.find_last_of("/") + 1); - if (patch_name.find(".") != string::npos) - patch_name = patch_name.substr(0, patch_name.find_last_of(".")); - } - - assert(patch_name.length() > 0); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"name", - (xmlChar*)patch_name.c_str()); - - snprintf(temp_buf, temp_buf_length, "%zd", patch_model->poly()); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); - - // Write metadata - for (map::const_iterator i = patch_model->metadata().begin(); - i != patch_model->metadata().end(); ++i) { - // Dirty hack, don't save coordinates in patch file - if ((*i).first != "module-x" && (*i).first != "module-y" - && (*i).first != "filename") - xml_node = xmlNewChild(xml_root_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - - assert((*i).first != "node"); - assert((*i).first != "subpatch"); - assert((*i).first != "name"); - assert((*i).first != "polyphony"); - assert((*i).first != "preset"); - } - - // Save nodes and subpatches - for (NodeModelMap::const_iterator i = patch_model->nodes().begin(); i != patch_model->nodes().end(); ++i) { - nm = i->second; - - if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch - spm = (PatchModel*)i->second; - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->name().c_str()); - - string ref_filename; - // No path - if (spm->filename() == "") { - ref_filename = spm->name() + ".om"; - spm->filename(dir +"/"+ ref_filename); - // Absolute path - } else if (spm->filename().substr(0, 1) == "/") { - // Attempt to make it a relative path, if it's undernath this patch's dir - if (dir.substr(0, 1) == "/" && spm->filename().substr(0, dir.length()) == dir) { - ref_filename = spm->filename().substr(dir.length()+1); - } else { // FIXME: not good - ref_filename = spm->filename().substr(spm->filename().find_last_of("/")+1); - spm->filename(dir +"/"+ ref_filename); - } - } else { - ref_filename = spm->filename(); - } - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"filename", (xmlChar*)ref_filename.c_str()); - - snprintf(temp_buf, temp_buf_length, "%zd", spm->poly()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); - - // Write metadata - for (map::const_iterator i = nm->metadata().begin(); - i != nm->metadata().end(); ++i) { - // Dirty hack, don't save metadata that would be in patch file - if ((*i).first != "polyphony" && (*i).first != "filename" - && (*i).first != "author" && (*i).first != "description") - xml_child_node = xmlNewChild(xml_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - } - - if (recursive) - save_patch(spm, spm->filename(), true); - - } else { // Normal node - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"node", NULL); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)nm->name().c_str()); - - if (nm->plugin() == NULL) break; - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphonic", - (xmlChar*)((nm->polyphonic()) ? "true" : "false")); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"type", - (xmlChar*)nm->plugin()->type_string()); - /* - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-label", - (xmlChar*)(nm->plugin()->plug_label().c_str())); - - if (nm->plugin()->type() != PluginModel::Internal) { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"library-name", - (xmlChar*)(nm->plugin()->lib_name().c_str())); - }*/ - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-uri", - (xmlChar*)(nm->plugin()->uri().c_str())); - - // Write metadata - for (map::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) { - // DSSI _hack_ (FIXME: fix OSC to be more like this and not smash DSSI into metadata?) - if ((*i).first.substr(0, 16) == "dssi-configure--") { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-configure", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"key", (xmlChar*)(*i).first.substr(16).c_str()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"value", (xmlChar*)(*i).second.c_str()); - } else if ((*i).first == "dssi-program") { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-program", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"bank", (xmlChar*)(*i).second.substr(0, (*i).second.find("/")).c_str()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"program", (xmlChar*)(*i).second.substr((*i).second.find("/")+1).c_str()); - } else { - xml_child_node = xmlNewChild(xml_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - } - } - - PortModel* pm = NULL; - // Write port metadata, if necessary - for (list::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) { - pm = (*i); - if (pm->is_input() && pm->user_min() != pm->min_val() || pm->user_max() != pm->max_val()) { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", pm->user_min()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-min", (xmlChar*)temp_buf); - snprintf(temp_buf, temp_buf_length, "%f", pm->user_max()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-max", (xmlChar*)temp_buf); - } - } - } - } - - // Save connections - - const list& cl = patch_model->connections(); - const ConnectionModel* c = NULL; - - for (list::const_iterator i = cl.begin(); i != cl.end(); ++i) { - c = (*i); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"connection", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-node", - (xmlChar*)c->src_port_path().parent().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-port", - (xmlChar*)c->src_port_path().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-node", - (xmlChar*)c->dst_port_path().parent().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-port", - (xmlChar*)c->dst_port_path().name().c_str()); - } - - // Save control values (ie presets eventually, right now just current control vals) - - xmlNodePtr xml_preset_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"preset", NULL); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"name", (xmlChar*)"default"); - - PortModel* pm = NULL; - - // Save node port controls - for (NodeModelMap::const_iterator n = patch_model->nodes().begin(); n != patch_model->nodes().end(); ++n) { - nm = n->second; - for (PortModelList::const_iterator p = nm->ports().begin(); p != nm->ports().end(); ++p) { - pm = *p; - if (pm->is_input() && pm->is_control()) { - float val = pm->value(); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"node-name", - (xmlChar*)nm->name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", val); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", - (xmlChar*)temp_buf); - } - } - } - - // Save patch port controls - for (PortModelList::const_iterator p = patch_model->ports().begin(); - p != patch_model->ports().end(); ++p) { - pm = *p; - if (pm->is_input() && pm->is_control()) { - float val = pm->value(); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", val); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", - (xmlChar*)temp_buf); - } - } - - xmlSaveFormatFile(filename.c_str(), xml_doc, 1); // 1 == pretty print - - xmlFreeDoc(xml_doc); - xmlCleanupParser(); -} - - -/** Load a patch in to the engine (and client) from a patch file. - * - * The name and poly from the passed PatchModel are used. If the name is - * the empty string, the name will be loaded from the file. If the poly - * is 0, it will be loaded from file. Otherwise the given values will - * be used. - * - * If @a wait is set, the patch will be checked for existence before - * loading everything in to it (to prevent messing up existing patches - * that exist at the path this one should load as). - * - * If the @a existing parameter is true, the patch will be loaded into a - * currently existing patch (ie a merging will take place). Errors will - * result if Nodes of conflicting names exist. - * - * Returns the path of the newly created patch. - */ -string -PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) -{ - string filename = pm->filename(); - - string additional_path = (pm->parent() == NULL) - ? "" : ((PatchModel*)pm->parent())->filename(); - additional_path = additional_path.substr(0, additional_path.find_last_of("/")); - - filename = find_file(pm->filename(), additional_path); - - size_t poly = pm->poly(); - - //cerr << "[PatchLibrarian] Loading patch " << filename << "" << endl; - - const size_t temp_buf_length = 255; - char temp_buf[temp_buf_length]; - - bool load_name = (pm->path() == ""); - bool load_poly = (poly == 0); - - xmlDocPtr doc = xmlParseFile(filename.c_str()); - - if (doc == NULL ) { - cerr << "Unable to parse patch file." << endl; - return ""; - } - - xmlNodePtr cur = xmlDocGetRootElement(doc); - - if (cur == NULL) { - cerr << "Empty document." << endl; - xmlFreeDoc(doc); - return ""; - } - - if (xmlStrcmp(cur->name, (const xmlChar*) "patch")) { - cerr << "File is not an Om patch file, root node != patch" << endl; - xmlFreeDoc(doc); - return ""; - } - - xmlChar* key = NULL; - cur = cur->xmlChildrenNode; - string path; - - pm->filename(filename); - - // Load Patch attributes - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - if (load_name) { - assert(key != NULL); - if (pm->parent() != NULL) { - path = pm->parent()->base_path() + string((char*)key); - } else { - path = string("/") + string((char*)key); - } - assert(path.find("//") == string::npos); - assert(path.length() > 0); - pm->set_path(path); - } - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { - if (load_poly) { - poly = atoi((char*)key); - pm->poly(poly); - } - } else if (xmlStrcmp(cur->name, (const xmlChar*)"connection") - && xmlStrcmp(cur->name, (const xmlChar*)"node") - && xmlStrcmp(cur->name, (const xmlChar*)"subpatch") - && xmlStrcmp(cur->name, (const xmlChar*)"filename") - && xmlStrcmp(cur->name, (const xmlChar*)"preset")) { - // Don't know what this tag is, add it as metadata without overwriting - // (so caller can set arbitrary parameters which will be preserved) - if (key != NULL) - if (pm->get_metadata((const char*)cur->name) == "") - pm->set_metadata((const char*)cur->name, (const char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - cur = cur->next; - } - - if (poly == 0) poly = 1; - - if (!existing) { - // Wait until the patch is created or the node creations may fail - if (wait) { - //int id = m_osc_model_engine_interface->get_next_request_id(); - //m_osc_model_engine_interface->set_wait_response_id(id); - m_osc_model_engine_interface->create_patch_from_model(pm); - //bool succeeded = m_osc_model_engine_interface->wait_for_response(); - - // If creating the patch failed, bail out so we don't load all these nodes - // into an already existing patch - /*if (!succeeded) { - cerr << "[PatchLibrarian] Patch load failed (patch already exists)" << endl; - return ""; - }*/ // FIXME - } else { - m_osc_model_engine_interface->create_patch_from_model(pm); - } - } - - - // Set the filename metadata. (FIXME) - // This isn't so good, considering multiple clients on multiple machines, and - // absolute filesystem paths obviously aren't going to be correct. But for now - // this is all I can figure out to have Save/Save As work properly for subpatches - m_osc_model_engine_interface->set_metadata(pm->path(), "filename", pm->filename()); - - // Load nodes - NodeModel* nm = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"node"))) { - nm = parse_node(pm, doc, cur); - if (nm != NULL) { - m_osc_model_engine_interface->create_node_from_model(nm); - m_osc_model_engine_interface->set_all_metadata(nm); - for (list::const_iterator j = nm->ports().begin(); - j != nm->ports().end(); ++j) { - // FIXME: ew - snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min()); - m_osc_model_engine_interface->set_metadata((*j)->path(), "user-min", temp_buf); - snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max()); - m_osc_model_engine_interface->set_metadata((*j)->path(), "user-max", temp_buf); - } - nm = NULL; - usleep(10000); - } - } - cur = cur->next; - } - - // Load subpatches - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) { - load_subpatch(pm, doc, cur); - } - cur = cur->next; - } - - // Load connections - ConnectionModel* cm = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) { - cm = parse_connection(pm, doc, cur); - if (cm != NULL) { - m_osc_model_engine_interface->connect(cm->src_port_path(), cm->dst_port_path()); - usleep(1000); - } - } - cur = cur->next; - } - - - // Load presets (control values) - PresetModel* preset_model = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) { - preset_model = parse_preset(pm, doc, cur); - assert(preset_model != NULL); - if (preset_model->name() == "default") - m_osc_model_engine_interface->set_preset(pm->path(), preset_model); - } - cur = cur->next; - } - - xmlFreeDoc(doc); - xmlCleanupParser(); - - m_osc_model_engine_interface->set_all_metadata(pm); - - if (!existing) - m_osc_model_engine_interface->enable_patch(pm->path()); - - string ret = pm->path(); - return ret; -} - - -/** Build a NodeModel given a pointer to a Node in a patch file. - */ -NodeModel* -PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) -{ - NodeModel* nm = new NodeModel("/UNINITIALIZED"); // FIXME: ew - PluginModel* plugin = new PluginModel(); - - xmlChar* key; - xmlNodePtr cur = node->xmlChildrenNode; - - bool found_name = false; - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - nm->set_path(parent->base_path() + (char*)key); - found_name = true; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) { - nm->polyphonic(!strcmp((char*)key, "true")); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) { - plugin->set_type((const char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"library-name"))) { - plugin->lib_name((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-label"))) { - plugin->plug_label((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-uri"))) { - plugin->uri((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"port"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string path; - float user_min = 0.0; - float user_max = 0.0; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"name"))) { - path = nm->base_path() + (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-min"))) { - user_min = atof((char*)key); - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-max"))) { - user_max = atof((char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - - // FIXME: nasty assumptions - PortModel* pm = new PortModel(path, - PortModel::CONTROL, PortModel::INPUT, PortModel::NONE, - 0.0, user_min, user_max); - nm->add_port(pm); - - // DSSI hacks. Stored in the patch files as special elements, but sent to - // the engine as normal metadata with specially formatted key/values. Not - // sure if this is the best way to go about this, but it's the least damaging - // right now - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-program"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string bank; - string program; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"bank"))) { - bank = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"program"))) { - program = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - child = child->next; - } - nm->set_metadata("dssi-program", bank +"/"+ program); - - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-configure"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string dssi_key; - string dssi_value; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"key"))) { - dssi_key = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { - dssi_value = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - nm->set_metadata(string("dssi-configure--").append(dssi_key), dssi_value); - - } else { // Don't know what this tag is, add it as metadata - if (key != NULL) - nm->set_metadata((const char*)cur->name, (const char*)key); - } - xmlFree(key); - key = NULL; - - cur = cur->next; - } - - if (nm->path() == "") { - cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl; - cerr << "[PatchLibrarian] Node ignored." << endl; - delete nm; - return NULL; - } else { - nm->plugin(plugin); - return nm; - } -} - - -void -PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr subpatch) -{ - xmlChar *key; - xmlNodePtr cur = subpatch->xmlChildrenNode; - - PatchModel* pm = new PatchModel("/UNINITIALIZED", 1); // FIXME: ew - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - if (parent == NULL) - pm->set_path(string("/") + (const char*)key); - else - pm->set_path(parent->base_path() + (const char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { - pm->poly(atoi((const char*)key)); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"filename"))) { - pm->filename((const char*)key); - } else { // Don't know what this tag is, add it as metadata - if (key != NULL && strlen((const char*)key) > 0) - pm->set_metadata((const char*)cur->name, (const char*)key); - } - xmlFree(key); - key = NULL; - - cur = cur->next; - } - - // This needs to be done after setting the path above, to prevent - // NodeModel::set_path from calling it's parent's rename_node with - // an invalid (nonexistant) name - pm->set_parent(parent); - - load_patch(pm, false); -} - - -/** Build a ConnectionModel given a pointer to a connection in a patch file. - */ -ConnectionModel* -PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) -{ - //cerr << "[PatchLibrarian] Parsing connection..." << endl; - - xmlChar *key; - xmlNodePtr cur = node->xmlChildrenNode; - - string source_node, source_port, dest_node, dest_port; - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-node"))) { - source_node = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-port"))) { - source_port = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-node"))) { - dest_node = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-port"))) { - dest_port = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - cur = cur->next; - } - - if (source_node == "" || source_port == "" || dest_node == "" || dest_port == "") { - cerr << "[PatchLibrarian] Malformed patch file (connection tag has empty children)" << endl; - cerr << "[PatchLibrarian] Connection ignored." << endl; - return NULL; - } - - // FIXME: temporary compatibility, remove any slashes from port names - // remove this soon once patches have migrated - string::size_type slash_index; - while ((slash_index = source_port.find("/")) != string::npos) - source_port[slash_index] = '-'; - - while ((slash_index = dest_port.find("/")) != string::npos) - dest_port[slash_index] = '-'; - - ConnectionModel* cm = new ConnectionModel(parent->base_path() + source_node +"/"+ source_port, - parent->base_path() + dest_node +"/"+ dest_port); - - return cm; -} - - -/** Build a PresetModel given a pointer to a preset in a patch file. - */ -PresetModel* -PatchLibrarian::parse_preset(const PatchModel* patch, xmlDocPtr doc, const xmlNodePtr node) -{ - xmlNodePtr cur = node->xmlChildrenNode; - xmlChar* key; - - PresetModel* pm = new PresetModel(patch->base_path()); - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - assert(key != NULL); - pm->name((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"control"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string node_name = "", port_name = ""; - float val = 0.0; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"node-name"))) { - node_name = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"port-name"))) { - port_name = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { - val = atof((char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - - if (port_name == "") { - string msg = "Unable to parse control in patch file ( node = "; - msg.append(node_name).append(", port = ").append(port_name).append(")"); - cerr << "ERROR: " << msg << endl; - //m_client_hooks->error(msg); - } else { - // FIXME: temporary compatibility, remove any slashes from port name - // remove this soon once patches have migrated - string::size_type slash_index; - while ((slash_index = port_name.find("/")) != string::npos) - port_name[slash_index] = '-'; - pm->add_control(node_name, port_name, val); - } - } - xmlFree(key); - key = NULL; - cur = cur->next; - } - if (pm->name() == "") { - cerr << "Preset in patch file has no name." << endl; - //m_client_hooks->error("Preset in patch file has no name."); - pm->name("Unnamed"); - } - - return pm; -} - -} // namespace LibOmClient diff --git a/src/clients/PatchLibrarian.cpp.new b/src/clients/PatchLibrarian.cpp.new deleted file mode 100644 index dc05c9e3..00000000 --- a/src/clients/PatchLibrarian.cpp.new +++ /dev/null @@ -1,830 +0,0 @@ -/* This file is part of Om. 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 "PatchLibrarian.h" -#include -#include -#include -#include "PatchModel.h" -#include "NodeModel.h" -#include "ConnectionModel.h" -#include "PortModel.h" -#include "PresetModel.h" -#include "OSCController.h" -#include "PluginModel.h" -#include "Path.h" -#include -#include -#include -#include // for pair, make_pair -#include -#include -#include -#include // for usleep -#include // for atof -#include - -using std::string; using std::vector; using std::pair; -using std::cerr; using std::cout; using std::endl; - -namespace LibOmClient { - - -/** Searches for the filename passed in the path, returning the full - * path of the file, or the empty string if not found. - * - * This function tries to be as friendly a black box as possible - if the path - * passed is an absolute path and the file is found there, it will return - * that path, etc. - * - * additional_path is a list (colon delimeted as usual) of additional - * directories to look in. ie the directory the parent patch resides in would - * be a good idea to pass as additional_path, in the case of a subpatch. - */ -string -PatchLibrarian::find_file(const string& filename, const string& additional_path) -{ - string search_path = additional_path + ":" + m_patch_path; - - // Try to open the raw filename first - std::ifstream is(filename.c_str(), std::ios::in); - if (is.good()) { - is.close(); - return filename; - } - - string directory; - string full_patch_path = ""; - - while (search_path != "") { - directory = search_path.substr(0, search_path.find(':')); - if (search_path.find(':') != string::npos) - search_path = search_path.substr(search_path.find(':')+1); - else - search_path = ""; - - full_patch_path = directory +"/"+ filename; - - std::ifstream is; - is.open(full_patch_path.c_str(), std::ios::in); - - if (is.good()) { - is.close(); - return full_patch_path; - } else { - cerr << "[PatchLibrarian] Could not find patch file " << full_patch_path << endl; - } - } - - return ""; -} - - -/** Save a patch from a PatchModel to a filename. - * - * The filename passed is the true filename the patch will be saved to (with no prefixing or anything - * like that), and the patch_model's filename member will be set accordingly. - * - * This will break if: - * - The filename does not have an extension (ie contain a ".") - * - The patch_model has no (Om) path - */ -void -PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool recursive) -{ - assert(filename != ""); - assert(patch_model->path() != ""); - - cout << "Saving patch " << patch_model->path() << " to " << filename << endl; - - patch_model->filename(filename); - - string dir = filename.substr(0, filename.find_last_of("/")); - - NodeModel* nm = NULL; - PatchModel* spm = NULL; // subpatch model - - xmlDocPtr xml_doc = NULL; - xmlNodePtr xml_root_node = NULL; - xmlNodePtr xml_node = NULL; - xmlNodePtr xml_child_node = NULL; - xmlNodePtr xml_grandchild_node = NULL; - - xml_doc = xmlNewDoc((xmlChar*)"1.0"); - xml_root_node = xmlNewNode(NULL, (xmlChar*)"patch"); - xmlDocSetRootElement(xml_doc, xml_root_node); - - const size_t temp_buf_length = 255; - char temp_buf[temp_buf_length]; - - string patch_name; - if (patch_model->path() != "/") { - patch_name = patch_model->name(); - } else { - patch_name = filename; - if (patch_name.find("/") != string::npos) - patch_name = patch_name.substr(patch_name.find_last_of("/") + 1); - if (patch_name.find(".") != string::npos) - patch_name = patch_name.substr(0, patch_name.find_last_of(".")); - } - - assert(patch_name.length() > 0); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"name", - (xmlChar*)patch_name.c_str()); - - snprintf(temp_buf, temp_buf_length, "%zd", patch_model->poly()); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); - - // Write metadata - for (map::const_iterator i = patch_model->metadata().begin(); - i != patch_model->metadata().end(); ++i) { - // Dirty hack, don't save coordinates in patch file - if ((*i).first != "module-x" && (*i).first != "module-y" - && (*i).first != "filename") - xml_node = xmlNewChild(xml_root_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - assert((*i).first != "connection"); - assert((*i).first != "node"); - assert((*i).first != "subpatch"); - assert((*i).first != "name"); - assert((*i).first != "polyphony"); - assert((*i).first != "preset"); - } - - // Save nodes and subpatches - for (NodeModelMap::const_iterator i = patch_model->nodes().begin(); i != patch_model->nodes().end(); ++i) { - nm = i->second; - - if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch - spm = (PatchModel*)i->second; - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->name().c_str()); - - string ref_filename; - // No path - if (spm->filename() == "") { - ref_filename = spm->name() + ".om"; - spm->filename(dir +"/"+ ref_filename); - // Absolute path - } else if (spm->filename().substr(0, 1) == "/") { - // Attempt to make it a relative path, if it's undernath this patch's dir - if (dir.substr(0, 1) == "/" && spm->filename().substr(0, dir.length()) == dir) { - ref_filename = spm->filename().substr(dir.length()+1); - } else { // FIXME: not good - ref_filename = spm->filename().substr(spm->filename().find_last_of("/")+1); - spm->filename(dir +"/"+ ref_filename); - } - } else { - ref_filename = spm->filename(); - } - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"filename", (xmlChar*)ref_filename.c_str()); - - snprintf(temp_buf, temp_buf_length, "%zd", spm->poly()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); - - // Write metadata - for (map::const_iterator i = nm->metadata().begin(); - i != nm->metadata().end(); ++i) { - // Dirty hack, don't save metadata that would be in patch file - if ((*i).first != "polyphony" && (*i).first != "filename" - && (*i).first != "author" && (*i).first != "description") - xml_child_node = xmlNewChild(xml_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - } - - if (recursive) - save_patch(spm, spm->filename(), true); - - } else { // Normal node - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"node", NULL); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)nm->name().c_str()); - - if (nm->plugin() == NULL) break; - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphonic", - (xmlChar*)((nm->polyphonic()) ? "true" : "false")); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"type", - (xmlChar*)nm->plugin()->type_string()); - /* - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-label", - (xmlChar*)(nm->plugin()->plug_label().c_str())); - - if (nm->plugin()->type() != PluginModel::Internal) { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"library-name", - (xmlChar*)(nm->plugin()->lib_name().c_str())); - }*/ - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-uri", - (xmlChar*)(nm->plugin()->uri().c_str())); - - // Write metadata - for (map::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) { - // DSSI _hack_ (FIXME: fix OSC to be more like this and not smash DSSI into metadata?) - if ((*i).first.substr(0, 16) == "dssi-configure--") { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-configure", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"key", (xmlChar*)(*i).first.substr(16).c_str()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"value", (xmlChar*)(*i).second.c_str()); - } else if ((*i).first == "dssi-program") { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-program", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"bank", (xmlChar*)(*i).second.substr(0, (*i).second.find("/")).c_str()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"program", (xmlChar*)(*i).second.substr((*i).second.find("/")+1).c_str()); - } else { - xml_child_node = xmlNewChild(xml_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - } - } - - PortModel* pm = NULL; - // Write port metadata, if necessary - for (list::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) { - pm = (*i); - if (pm->is_input() && pm->user_min() != pm->min_val() || pm->user_max() != pm->max_val()) { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", pm->user_min()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-min", (xmlChar*)temp_buf); - snprintf(temp_buf, temp_buf_length, "%f", pm->user_max()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-max", (xmlChar*)temp_buf); - } - } - } - } - - // Save connections - - const list& cl = patch_model->connections(); - const ConnectionModel* c = NULL; - - for (list::const_iterator i = cl.begin(); i != cl.end(); ++i) { - c = (*i); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"connection", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-node", - (xmlChar*)c->src_port_path().parent().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-port", - (xmlChar*)c->src_port_path().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-node", - (xmlChar*)c->dst_port_path().parent().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-port", - (xmlChar*)c->dst_port_path().name().c_str()); - } - - // Save control values (ie presets eventually, right now just current control vals) - - xmlNodePtr xml_preset_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"preset", NULL); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"name", (xmlChar*)"default"); - - PortModel* pm = NULL; - - // Save node port controls - for (NodeModelMap::const_iterator n = patch_model->nodes().begin(); n != patch_model->nodes().end(); ++n) { - nm = n->second; - for (PortModelList::const_iterator p = nm->ports().begin(); p != nm->ports().end(); ++p) { - pm = *p; - if (pm->is_input() && pm->is_control()) { - float val = pm->value(); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"node-name", - (xmlChar*)nm->name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", val); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", - (xmlChar*)temp_buf); - } - } - } - - // Save patch port controls - for (PortModelList::const_iterator p = patch_model->ports().begin(); - p != patch_model->ports().end(); ++p) { - pm = *p; - if (pm->is_input() && pm->is_control()) { - float val = pm->value(); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", val); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", - (xmlChar*)temp_buf); - } - } - - xmlSaveFormatFile(filename.c_str(), xml_doc, 1); // 1 == pretty print - - xmlFreeDoc(xml_doc); - xmlCleanupParser(); -} - - -/** Load a patch in to the engine (and client) from a patch file. - * - * The name and poly from the passed PatchModel are used. If the name is - * the empty string, the name will be loaded from the file. If the poly - * is 0, it will be loaded from file. Otherwise the given values will - * be used. - * - * If @a wait is set, the patch will be checked for existence before - * loading everything in to it (to prevent messing up existing patches - * that exist at the path this one should load as). - * - * If the @a existing parameter is true, the patch will be loaded into a - * currently existing patch (ie a merging will take place). Errors will - * result if Nodes of conflicting names exist. - * - * Returns the path of the newly created patch. - */ -string -PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) -{ - string filename = pm->filename(); - - string additional_path = (pm->parent() == NULL) - ? "" : ((PatchModel*)pm->parent())->filename(); - additional_path = additional_path.substr(0, additional_path.find_last_of("/")); - - filename = find_file(pm->filename(), additional_path); - - size_t poly = pm->poly(); - - //cerr << "[PatchLibrarian] Loading patch " << filename << "" << endl; - - const size_t temp_buf_length = 255; - char temp_buf[temp_buf_length]; - - bool load_name = (pm->path() == ""); - bool load_poly = (poly == 0); - - xmlDocPtr doc = xmlParseFile(filename.c_str()); - - if (doc == NULL ) { - cerr << "Unable to parse patch file." << endl; - return ""; - } - - xmlNodePtr cur = xmlDocGetRootElement(doc); - - if (cur == NULL) { - cerr << "Empty document." << endl; - xmlFreeDoc(doc); - return ""; - } - - if (xmlStrcmp(cur->name, (const xmlChar*) "patch")) { - cerr << "File is not an Om patch file, root node != patch" << endl; - xmlFreeDoc(doc); - return ""; - } - - xmlChar* key = NULL; - cur = cur->xmlChildrenNode; - string path; - - pm->filename(filename); - - // Load Patch attributes - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - if (load_name) { - assert(key != NULL); - if (pm->parent() != NULL) { - path = pm->parent()->base_path() + string((char*)key); - } else { - path = string("/") + string((char*)key); - } - assert(path.find("//") == string::npos); - assert(path.length() > 0); - pm->set_path(path); - } - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { - if (load_poly) { - poly = atoi((char*)key); - pm->poly(poly); - } - } else if (xmlStrcmp(cur->name, (const xmlChar*)"connection") - && xmlStrcmp(cur->name, (const xmlChar*)"node") - && xmlStrcmp(cur->name, (const xmlChar*)"subpatch") - && xmlStrcmp(cur->name, (const xmlChar*)"preset")) { - // Don't know what this tag is, add it as metadata without overwriting - // (so caller can set arbitrary parameters which will be preserved) - if (key != NULL) - if (pm->get_metadata((const char*)cur->name) == "") - pm->set_metadata((const char*)cur->name, (const char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - cur = cur->next; - } - - if (poly == 0) poly = 1; - - if (!existing) { - // Wait until the patch is created or the node creations may fail - if (wait) { - int id = m_osc_controller->get_next_request_id(); - m_osc_controller->set_wait_response_id(id); - m_osc_controller->create_patch(pm, id); - bool succeeded = m_osc_controller->wait_for_response(); - - // If creating the patch failed, bail out so we don't load all these nodes - // into an already existing patch - if (!succeeded) { - cerr << "[PatchLibrarian] Patch load failed (patch already exists)" << endl; - return ""; - } - } else { - m_osc_controller->create_patch(pm); - } - } - - - // Set the filename metadata. (FIXME) - // This isn't so good, considering multiple clients on multiple machines, and - // absolute filesystem paths obviously aren't going to be correct. But for now - // this is all I can figure out to have Save/Save As work properly for subpatches - m_osc_controller->set_metadata(pm->path(), "filename", pm->filename()); - - // Load nodes - NodeModel* nm = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"node"))) { - nm = parse_node(pm, doc, cur); - if (nm != NULL) { - m_osc_controller->add_node(nm); - m_osc_controller->set_all_metadata(nm); - for (list::const_iterator j = nm->ports().begin(); - j != nm->ports().end(); ++j) { - // FIXME: ew - snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min()); - m_osc_controller->set_metadata((*j)->path(), "user-min", temp_buf); - snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max()); - m_osc_controller->set_metadata((*j)->path(), "user-max", temp_buf); - } - nm = NULL; - usleep(10000); - } - } - cur = cur->next; - } - - // Load subpatches - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) { - load_subpatch(pm, doc, cur); - } - cur = cur->next; - } - - // Load connections - ConnectionModel* cm = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) { - cm = parse_connection(pm, doc, cur); - if (cm != NULL) { - m_osc_controller->connect(cm->src_port_path(), cm->dst_port_path()); - usleep(1000); - } - } - cur = cur->next; - } - - - // Load presets (control values) - PresetModel* preset_model = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) { - preset_model = parse_preset(pm, doc, cur); - assert(preset_model != NULL); - if (preset_model->name() == "default") - m_osc_controller->set_preset(pm->path(), preset_model); - } - cur = cur->next; - } - - xmlFreeDoc(doc); - xmlCleanupParser(); - - m_osc_controller->set_all_metadata(pm); - - if (!existing) - m_osc_controller->enable_patch(pm->path()); - - string ret = pm->path(); - return ret; -} - - -/** Build a NodeModel given a pointer to a Node in a patch file. - */ -NodeModel* -PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) -{ - NodeModel* nm = new NodeModel("/UNINITIALIZED"); // FIXME: ew - PluginModel* plugin = new PluginModel(); - - xmlChar* key; - xmlNodePtr cur = node->xmlChildrenNode; - - bool found_name = false; - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - nm->set_path(parent->base_path() + (char*)key); - found_name = true; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) { - nm->polyphonic(!strcmp((char*)key, "true")); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) { - plugin->set_type((const char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"library-name"))) { - plugin->lib_name((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-label"))) { - plugin->plug_label((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-uri"))) { - plugin->uri((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"port"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string path; - float user_min = 0.0; - float user_max = 0.0; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"name"))) { - path = nm->base_path() + (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-min"))) { - user_min = atof((char*)key); - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-max"))) { - user_max = atof((char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - - // FIXME: nasty assumptions - PortModel* pm = new PortModel(path, - PortModel::CONTROL, PortModel::INPUT, PortModel::NONE, - 0.0, user_min, user_max); - nm->add_port(pm); - - // DSSI hacks. Stored in the patch files as special elements, but sent to - // the engine as normal metadata with specially formatted key/values. Not - // sure if this is the best way to go about this, but it's the least damaging - // right now - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-program"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string bank; - string program; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"bank"))) { - bank = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"program"))) { - program = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - child = child->next; - } - nm->set_metadata("dssi-program", bank +"/"+ program); - - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-configure"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string dssi_key; - string dssi_value; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"key"))) { - dssi_key = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { - dssi_value = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - nm->set_metadata(string("dssi-configure--").append(dssi_key), dssi_value); - - } else { // Don't know what this tag is, add it as metadata - if (key != NULL) - nm->set_metadata((const char*)cur->name, (const char*)key); - } - xmlFree(key); - key = NULL; - - cur = cur->next; - } - - if (nm->path() == "") { - cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl; - cerr << "[PatchLibrarian] Node ignored." << endl; - delete nm; - return NULL; - } else { - nm->plugin(plugin); - return nm; - } -} - - -void -PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr subpatch) -{ - xmlChar *key; - xmlNodePtr cur = subpatch->xmlChildrenNode; - - PatchModel* pm = new PatchModel("", 1); // FIXME: ew - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - if (parent == NULL) - pm->set_path(string("/") + (const char*)key); - else - pm->set_path(parent->base_path() + (const char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { - pm->poly(atoi((const char*)key)); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"filename"))) { - pm->filename((const char*)key); - } else { // Don't know what this tag is, add it as metadata - if (key != NULL && strlen((const char*)key) > 0) - pm->set_metadata((const char*)cur->name, (const char*)key); - } - xmlFree(key); - key = NULL; - - cur = cur->next; - } - - // This needs to be done after setting the path above, to prevent - // NodeModel::set_path from calling it's parent's rename_node with - // an invalid (nonexistant) name - pm->set_parent(parent); - - load_patch(pm, false); -} - - -/** Build a ConnectionModel given a pointer to a connection in a patch file. - */ -ConnectionModel* -PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) -{ - //cerr << "[PatchLibrarian] Parsing connection..." << endl; - - xmlChar *key; - xmlNodePtr cur = node->xmlChildrenNode; - - string source_node, source_port, dest_node, dest_port; - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-node"))) { - source_node = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-port"))) { - source_port = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-node"))) { - dest_node = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-port"))) { - dest_port = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - cur = cur->next; - } - - if (source_node == "" || source_port == "" || dest_node == "" || dest_port == "") { - cerr << "[PatchLibrarian] Malformed patch file (connection tag has empty children)" << endl; - cerr << "[PatchLibrarian] Connection ignored." << endl; - return NULL; - } - - // FIXME: temporary compatibility, remove any slashes from port names - // remove this soon once patches have migrated - string::size_type slash_index; - while ((slash_index = source_port.find("/")) != string::npos) - source_port[slash_index] = '-'; - - while ((slash_index = dest_port.find("/")) != string::npos) - dest_port[slash_index] = '-'; - - ConnectionModel* cm = new ConnectionModel(parent->base_path() + source_node +"/"+ source_port, - parent->base_path() + dest_node +"/"+ dest_port); - - return cm; -} - - -/** Build a PresetModel given a pointer to a preset in a patch file. - */ -PresetModel* -PatchLibrarian::parse_preset(const PatchModel* patch, xmlDocPtr doc, const xmlNodePtr node) -{ - xmlNodePtr cur = node->xmlChildrenNode; - xmlChar* key; - - PresetModel* pm = new PresetModel(patch->base_path()); - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - assert(key != NULL); - pm->name((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"control"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string node_name = "", port_name = ""; - float val = 0.0; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"node-name"))) { - node_name = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"port-name"))) { - port_name = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { - val = atof((char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - - if (port_name == "") { - string msg = "Unable to parse control in patch file ( node = "; - msg.append(node_name).append(", port = ").append(port_name).append(")"); - m_client_hooks->error(msg); - } else { - // FIXME: temporary compatibility, remove any slashes from port name - // remove this soon once patches have migrated - string::size_type slash_index; - while ((slash_index = port_name.find("/")) != string::npos) - port_name[slash_index] = '-'; - pm->add_control(node_name, port_name, val); - } - } - xmlFree(key); - key = NULL; - cur = cur->next; - } - if (pm->name() == "") { - m_client_hooks->error("Preset in patch file has no name."); - pm->name("Unnamed"); - } - - return pm; -} - -} // namespace LibOmClient diff --git a/src/clients/PatchLibrarian.h b/src/clients/PatchLibrarian.h deleted file mode 100644 index ace91f24..00000000 --- a/src/clients/PatchLibrarian.h +++ /dev/null @@ -1,78 +0,0 @@ -/* This file is part of Om. 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 PATCHLIBRARIAN_H -#define PATCHLIBRARIAN_H - -#include -#include -#include -//#include "DummyModelClientInterface.h" - -using std::string; - -namespace LibOmClient { - -class PatchModel; -class NodeModel; -class ConnectionModel; -class PresetModel; -class OSCModelEngineInterface; -class ModelClientInterface; - - -/** Handles all patch saving and loading. - * - * \ingroup libomclient - */ -class PatchLibrarian -{ -public: - // FIXME: return booleans and set an errstr that can be checked? - - PatchLibrarian(OSCModelEngineInterface* const osc_model_engine_interface/*,ModelClientInterface* const client_hooks*/) - : m_patch_path("."), m_osc_model_engine_interface(osc_model_engine_interface)//, m_client_hooks(client_hooks) - { - assert(m_osc_model_engine_interface); - //assert(m_client_hooks != NULL); - } - -// PatchLibrarian(OSCModelEngineInterface* osc_model_engine_interface) -// : m_osc_model_engine_interface(osc_model_engine_interface), m_client_hooks(new DummyModelClientInterface()) -// {} - - void path(const string& path) { m_patch_path = path; } - const string& path() { return m_patch_path; } - - string find_file(const string& filename, const string& additional_path = ""); - - void save_patch(PatchModel* patch_model, const string& filename, bool recursive); - string load_patch(PatchModel* pm, bool wait = true, bool existing = false); - -private: - string m_patch_path; - OSCModelEngineInterface* const m_osc_model_engine_interface; - - NodeModel* parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - ConnectionModel* parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - PresetModel* parse_preset(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - void load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); -}; - - -} // namespace LibOmClient - -#endif // PATCHLIBRARIAN_H diff --git a/src/clients/PatchModel.cpp b/src/clients/PatchModel.cpp deleted file mode 100644 index 829c9ca5..00000000 --- a/src/clients/PatchModel.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* This file is part of Om. 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 "PatchModel.h" -#include "NodeModel.h" -#include "ConnectionModel.h" -#include -#include - -using std::cerr; using std::cout; using std::endl; - -namespace LibOmClient { - - -void -PatchModel::set_path(const Path& new_path) -{ - // FIXME: haack - if (new_path == "") { - m_path = ""; - return; - } - - NodeModel::set_path(new_path); - for (NodeModelMap::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) - (*i).second->set_path(m_path +"/"+ (*i).second->name()); - -#ifdef DEBUG - // Be sure connection paths are updated and sane - for (list::iterator j = m_connections.begin(); - j != m_connections.end(); ++j) { - assert((*j)->src_port_path().parent().parent() == new_path); - assert((*j)->src_port_path().parent().parent() == new_path); - } -#endif -} - - -NodeModel* -PatchModel::get_node(const string& name) -{ - assert(name.find("/") == string::npos); - NodeModelMap::iterator i = m_nodes.find(name); - return ((i != m_nodes.end()) ? (*i).second : NULL); -} - - -void -PatchModel::add_node(NodeModel* nm) -{ - assert(nm != NULL); - assert(nm->name().find("/") == string::npos); - assert(nm->parent() == NULL); - - m_nodes[nm->name()] = nm; - nm->set_parent(this); -} - - -void -PatchModel::remove_node(const string& name) -{ - assert(name.find("/") == string::npos); - NodeModelMap::iterator i = m_nodes.find(name); - if (i != m_nodes.end()) { - delete i->second; - m_nodes.erase(i); - return; - } - - cerr << "[PatchModel::remove_node] " << m_path << ": failed to find node " << name << endl; -} - - -void -PatchModel::clear() -{ - for (list::iterator j = m_connections.begin(); j != m_connections.end(); ++j) - delete (*j); - - for (NodeModelMap::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) { - (*i).second->clear(); - delete (*i).second; - } - - m_nodes.clear(); - m_connections.clear(); - - NodeModel::clear(); - - assert(m_nodes.empty()); - assert(m_connections.empty()); - assert(m_ports.empty()); -} - - -/** Updated the map key of the given node. - * - * The NodeModel must already have it's new path set to @a new_path, or this will - * abort with a fatal error. - */ -void -PatchModel::rename_node(const Path& old_path, const Path& new_path) -{ - assert(old_path.parent() == path()); - assert(new_path.parent() == path()); - - NodeModelMap::iterator i = m_nodes.find(old_path.name()); - NodeModel* nm = NULL; - - if (i != m_nodes.end()) { - nm = (*i).second; - for (list::iterator j = m_connections.begin(); j != m_connections.end(); ++j) { - if ((*j)->src_port_path().parent() == old_path) - (*j)->src_port_path(new_path.base_path() + (*j)->src_port_path().name()); - if ((*j)->dst_port_path().parent() == old_path) - (*j)->dst_port_path(new_path.base_path() + (*j)->dst_port_path().name()); - } - m_nodes.erase(i); - assert(nm->path() == new_path); - m_nodes[new_path.name()] = nm; - return; - } - - cerr << "[PatchModel::rename_node] " << m_path << ": failed to find node " << old_path << endl; -} - - -ConnectionModel* -PatchModel::get_connection(const string& src_port_path, const string& dst_port_path) -{ - for (list::iterator i = m_connections.begin(); i != m_connections.end(); ++i) - if ((*i)->src_port_path() == src_port_path && (*i)->dst_port_path() == dst_port_path) - return (*i); - return NULL; -} - - -/** Add a connection to this patch. - * - * Ownership of @a cm is taken, it will be deleted along with this PatchModel. - * If @a cm only contains paths (not pointers to the actual ports), the ports - * will be found and set. The ports referred to not existing as children of - * this patch is a fatal error. - */ -void -PatchModel::add_connection(ConnectionModel* cm) -{ - assert(cm != NULL); - assert(cm->src_port_path().parent().parent() == m_path); - assert(cm->dst_port_path().parent().parent() == m_path); - assert(cm->patch_path() == path()); - - ConnectionModel* existing = get_connection(cm->src_port_path(), cm->dst_port_path()); - - if (existing != NULL) { - delete cm; - return; - } - - NodeModel* src_node = get_node(cm->src_port_path().parent().name()); - PortModel* src_port = (src_node == NULL) ? NULL : src_node->get_port(cm->src_port_path().name()); - NodeModel* dst_node = get_node(cm->dst_port_path().parent().name()); - PortModel* dst_port = (dst_node == NULL) ? NULL : dst_node->get_port(cm->dst_port_path().name()); - - assert(src_port != NULL); - assert(dst_port != NULL); - - // Find source port pointer to 'resolve' connection if necessary - if (cm->src_port() != NULL) - assert(cm->src_port() == src_port); - else - cm->set_src_port(src_port); - - // Find dest port pointer to 'resolve' connection if necessary - if (cm->dst_port() != NULL) - assert(cm->dst_port() == dst_port); - else - cm->set_dst_port(dst_port); - - assert(cm->src_port() != NULL); - assert(cm->dst_port() != NULL); - - m_connections.push_back(cm); -} - - -void -PatchModel::remove_connection(const string& src_port_path, const string& dst_port_path) -{ - ConnectionModel* cm = NULL; - for (list::iterator i = m_connections.begin(); i != m_connections.end(); ++i) { - cm = (*i); - if (cm->src_port_path() == src_port_path && cm->dst_port_path() == dst_port_path) { - delete cm; - m_connections.erase(i); - assert(get_connection(src_port_path, dst_port_path) == NULL); // no duplicates - return; - } - } - cerr << "[PatchModel::remove_connection] WARNING: Failed to find connection " << - src_port_path << " -> " << dst_port_path << endl; - return; -} - - -bool -PatchModel::polyphonic() const -{ - return (m_parent == NULL) - ? (m_poly > 1) - : (m_poly > 1) && m_poly == parent_patch()->poly() && m_poly > 1; -} - - -} // namespace LibOmClient diff --git a/src/clients/PatchModel.h b/src/clients/PatchModel.h deleted file mode 100644 index 12871933..00000000 --- a/src/clients/PatchModel.h +++ /dev/null @@ -1,88 +0,0 @@ -/* This file is part of Om. 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 PATCHMODEL_H -#define PATCHMODEL_H - -#include -#include -#include -#include -#include "NodeModel.h" - -using std::list; using std::string; using std::map; - -namespace LibOmClient { - -class ConnectionModel; - - -/** Client's model of a patch. - * - * \ingroup libomclient - */ -class PatchModel : public NodeModel -{ -public: - PatchModel(const string& patch_path, uint poly) - : NodeModel(patch_path), - m_enabled(false), - m_poly(poly) - {} - - const NodeModelMap& nodes() const { return m_nodes; } - const list& connections() const { return m_connections; } - - virtual void set_path(const Path& path); - - NodeModel* get_node(const string& node_name); - void add_node(NodeModel* nm); - void remove_node(const string& name); - - void rename_node(const Path& old_path, const Path& new_path); - void rename_node_port(const Path& old_path, const Path& new_path); - ConnectionModel* get_connection(const string& src_port_path, const string& dst_port_path); - void add_connection(ConnectionModel* cm); - void remove_connection(const string& src_port_path, const string& dst_port_path); - - virtual void clear(); - - size_t poly() const { return m_poly; } - void poly(size_t p) { m_poly = p; } - const string& filename() const { return m_filename; } - void filename(const string& f) { m_filename = f; } - bool enabled() const { return m_enabled; } - void enabled(bool b) { m_enabled = b; } - bool polyphonic() const; - -private: - // Prevent copies (undefined) - PatchModel(const PatchModel& copy); - PatchModel& operator=(const PatchModel& copy); - - NodeModelMap m_nodes; - list m_connections; - string m_filename; - bool m_enabled; - size_t m_poly; -}; - -typedef map PatchModelMap; - - -} // namespace LibOmClient - -#endif // PATCHMODEL_H diff --git a/src/clients/PluginModel.h b/src/clients/PluginModel.h deleted file mode 100644 index 85365d64..00000000 --- a/src/clients/PluginModel.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of Om. 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 PLUGINMODEL_H -#define PLUGINMODEL_H - -#include -using std::string; - -namespace LibOmClient { - - -/** Model for a plugin available for loading. - * - * \ingroup libomclient - */ -class PluginModel -{ -public: - enum Type { LV2, LADSPA, DSSI, Internal, Patch }; - - // FIXME: remove - PluginModel() {} - - PluginModel(const string& type_string, const string& uri) - : m_uri(uri) - { set_type(type_string); } - - PluginModel(Type type) - : m_type(type) - {} - - PluginModel(Type type, const string& uri, const string& name) - : m_type(type), - m_uri(uri), - m_name(name) - {} - - PluginModel(Type type, const string& lib_name, const string& plug_label, const string& name) - : m_type(type), - m_lib_name(lib_name), - m_plug_label(plug_label), - m_name(name) - {} - - //PluginModel() {} - - Type type() const { return m_type; } - void type(Type t) { m_type = t; } - const string& uri() const { return m_uri; } - void uri(const string& s) { m_uri = s; } - const string& lib_name() const { return m_lib_name; } - void lib_name(const string& s) { m_lib_name = s; } - const string& plug_label() const { return m_plug_label; } - void plug_label(const string& s) { m_plug_label = s; } - const string& name() const { return m_name; } - void name(const string& s) { m_name = s; } - - const char* const type_string() const { - if (m_type == LV2) return "LV2"; - else if (m_type == LADSPA) return "LADSPA"; - else if (m_type == DSSI) return "DSSI"; - else if (m_type == Internal) return "Internal"; - else if (m_type == Patch) return "Patch"; - else return ""; - } - - void set_type(const string& type_string) { - if (type_string == "LV2") m_type = LV2; - else if (type_string == "LADSPA") m_type = LADSPA; - else if (type_string == "DSSI") m_type = DSSI; - else if (type_string == "Internal") m_type = Internal; - else if (type_string == "Patch") m_type = Patch; - } - -private: - // Prevent copies - PluginModel(const PluginModel& copy); - PluginModel& operator=(const PluginModel& copy); - - Type m_type; - string m_uri; - string m_lib_name; - string m_plug_label; - string m_name; -}; - - -} // namespace Om - -#endif // PLUGINMODEL_H - diff --git a/src/clients/PortModel.h b/src/clients/PortModel.h deleted file mode 100644 index 6d0895cf..00000000 --- a/src/clients/PortModel.h +++ /dev/null @@ -1,118 +0,0 @@ -/* This file is part of Om. 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 PORTMODEL_H -#define PORTMODEL_H - -#include -#include -#include -#include "ObjectModel.h" -using std::string; using std::list; - -namespace LibOmClient { - -/* Model of a port. - * - * \ingroup libomclient. - */ -class PortModel : public ObjectModel -{ -public: - enum Type { CONTROL, AUDIO, MIDI }; - enum Direction { INPUT, OUTPUT }; - enum Hint { NONE, INTEGER, TOGGLE, LOGARITHMIC }; - - PortModel(const string& path, Type type, Direction dir, Hint hint, - float default_val, float min, float max) - : ObjectModel(path), - m_type(type), - m_direction(dir), - m_hint(hint), - m_default_val(default_val), - m_min_val(min), - m_user_min(min), - m_max_val(max), - m_user_max(max), - m_current_val(default_val), - m_connected(false) - { - } - - PortModel(const string& path, Type type, Direction dir) - : ObjectModel(path), - m_type(type), - m_direction(dir), - m_hint(NONE), - m_default_val(0.0f), - m_min_val(0.0f), - m_user_min(0.0f), - m_max_val(0.0f), - m_user_max(0.0f), - m_current_val(0.0f), - m_connected(false) - { - } - - inline float min_val() const { return m_min_val; } - inline float user_min() const { return m_user_min; } - inline void user_min(float f) { m_user_min = f; } - inline float default_val() const { return m_default_val; } - inline void default_val(float f) { m_default_val = f; } - inline float max_val() const { return m_max_val; } - inline float user_max() const { return m_user_max; } - inline void user_max(float f) { m_user_max = f; } - inline float value() const { return m_current_val; } - inline void value(float f) { m_current_val = f; } - inline bool connected() { return m_connected; } - inline void connected(bool b) { m_connected = b; } - inline Type type() { return m_type; } - - inline bool is_input() const { return (m_direction == INPUT); } - inline bool is_output() const { return (m_direction == OUTPUT); } - inline bool is_audio() const { return (m_type == AUDIO); } - inline bool is_control() const { return (m_type == CONTROL); } - inline bool is_midi() const { return (m_type == MIDI); } - inline bool is_logarithmic() const { return (m_hint == LOGARITHMIC); } - inline bool is_integer() const { return (m_hint == INTEGER); } - inline bool is_toggle() const { return (m_hint == TOGGLE); } - - inline bool operator==(const PortModel& pm) - { return (m_path == pm.m_path); } - -private: - // Prevent copies (undefined) - PortModel(const PortModel& copy); - PortModel& operator=(const PortModel& copy); - - Type m_type; - Direction m_direction; - Hint m_hint; - float m_default_val; - float m_min_val; - float m_user_min; - float m_max_val; - float m_user_max; - float m_current_val; - bool m_connected; -}; - -typedef list PortModelList; - - -} // namespace LibOmClient - -#endif // PORTMODEL_H diff --git a/src/clients/PresetModel.h b/src/clients/PresetModel.h deleted file mode 100644 index bd187dfc..00000000 --- a/src/clients/PresetModel.h +++ /dev/null @@ -1,66 +0,0 @@ -/* This file is part of Om. 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 alongCont - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef PRESETMODEL_H -#define PRESETMODEL_H - -#include -#include -#include "ControlModel.h" - -using std::string; using std::list; - -namespace LibOmClient { - - -/** Model of a preset (a collection of control settings). - * - * \ingroup libomclient - */ -class PresetModel -{ -public: - PresetModel(const string& base_path) - : m_base_path(base_path) - {} - - /** Add a control value to this preset. An empty string for a node_name - * means the port is on the patch itself (not a node in the patch). - */ - void add_control(const string& node_name, - const string& port_name, float value) - { - if (node_name != "") - m_controls.push_back(ControlModel(m_base_path + node_name +"/"+ port_name, value)); - else - m_controls.push_back(ControlModel(m_base_path + port_name, value)); - } - - const string& name() { return m_name; } - void name(const string& n) { m_name = n; } - - const list& controls() const { return m_controls; } - -private: - string m_name; - string m_base_path; - list m_controls; -}; - - -} // namespace LibOmClient - -#endif // PRESETMODEL diff --git a/src/clients/SigClientInterface.h b/src/clients/SigClientInterface.h deleted file mode 100644 index f384f239..00000000 --- a/src/clients/SigClientInterface.h +++ /dev/null @@ -1,120 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 SIGCLIENTINTERFACE_H -#define SIGCLIENTINTERFACE_H - -#include -#include -#include -#include "interface/ClientInterface.h" -using std::string; - -namespace LibOmClient { - - -/** A LibSigC++ signal emitting interface for clients to use. - * - * sed would have the copyright to this code if it was a legal person. - */ -class SigClientInterface : virtual public Om::Shared::ClientInterface, public sigc::trackable -{ -public: - sigc::signal bundle_begin_sig; - sigc::signal bundle_end_sig; - sigc::signal error_sig; - sigc::signal num_plugins_sig; - sigc::signal new_plugin_sig; - sigc::signal new_patch_sig; - sigc::signal new_node_sig; - sigc::signal new_port_sig; - sigc::signal patch_enabled_sig; - sigc::signal patch_disabled_sig; - sigc::signal patch_cleared_sig; - sigc::signal object_renamed_sig; - sigc::signal object_destroyed_sig; - sigc::signal connection_sig; - sigc::signal disconnection_sig; - sigc::signal metadata_update_sig; - sigc::signal control_change_sig; - sigc::signal program_add_sig; - sigc::signal program_remove_sig; - - inline void emit_bundle_begin() - { bundle_begin_sig.emit(); } - - inline void emit_bundle_end() - { bundle_end_sig.emit(); } - - inline void emit_error(const string& msg) - { error_sig.emit(msg); } - - inline void emit_num_plugins(uint32_t num) - { num_plugins_sig.emit(num); } - - inline void emit_new_plugin(const string& type, const string& uri, const string& name) - { new_plugin_sig.emit(type, uri, name); } - - inline void emit_new_patch(const string& path, uint32_t poly) - { new_patch_sig.emit(path, poly); } - - inline void emit_new_node(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports) - { new_node_sig.emit(plugin_type, plugin_uri, node_path, is_polyphonic, num_ports); } - - inline void emit_new_port(const string& path, const string& data_type, bool is_output) - { new_port_sig.emit(path, data_type, is_output); } - - inline void emit_patch_enabled(const string& path) - { patch_enabled_sig.emit(path); } - - inline void emit_patch_disabled(const string& path) - { patch_disabled_sig.emit(path); } - - inline void emit_patch_cleared(const string& path) - { patch_cleared_sig.emit(path); } - - inline void emit_object_renamed(const string& old_path, const string& new_path) - { object_renamed_sig.emit(old_path, new_path); } - - inline void emit_object_destroyed(const string& path) - { object_destroyed_sig.emit(path); } - - inline void emit_connection(const string& src_port_path, const string& dst_port_path) - { connection_sig.emit(src_port_path, dst_port_path); } - - inline void emit_disconnection(const string& src_port_path, const string& dst_port_path) - { disconnection_sig.emit(src_port_path, dst_port_path); } - - inline void emit_metadata_update(const string& subject_path, const string& predicate, const string& value) - { metadata_update_sig.emit(subject_path, predicate, value); } - - inline void emit_control_change(const string& port_path, float value) - { control_change_sig.emit(port_path, value); } - - inline void emit_program_add(const string& node_path, uint32_t bank, uint32_t program, const string& program_name) - { program_add_sig.emit(node_path, bank, program, program_name); } - - inline void emit_program_remove(const string& node_path, uint32_t bank, uint32_t program) - { program_remove_sig.emit(node_path, bank, program); } - -protected: - SigClientInterface() {} -}; - - -} // namespace LibOmClient - -#endif diff --git a/src/clients/ThreadedSigClientInterface.cpp b/src/clients/ThreadedSigClientInterface.cpp deleted file mode 100644 index 860d91f6..00000000 --- a/src/clients/ThreadedSigClientInterface.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "ThreadedSigClientInterface.h" -#include -using std::cerr; using std::endl; - -namespace LibOmClient { - - -/** Push an event (from the engine, ie 'new patch') on to the queue. - */ -void -ThreadedSigClientInterface::push_sig(Closure ev) -{ - cerr << "-- pushing event\n"; - - bool success = false; - bool first = true; - - // (Very) slow busy-wait if the queue is full - // FIXME: Make this wait on a signal from process_sigs iff this happens - while (!success) { - success = _sigs.push(ev); - if (!success) { - if (first) { - cerr << "[ThreadedSigClientInterface] WARNING: (Client) event queue full. Waiting to try again..." << endl; - first = false; - } - usleep(200000); // 100 milliseconds (2* rate process_sigs is called) - } - } -} - - -/** Process all queued events that came from the OSC thread. - * - * This function should be called from the Gtk thread to emit signals and cause - * the connected methods to execute. - */ -bool -ThreadedSigClientInterface::emit_signals() -{ - // Process a maximum of queue-size events, to prevent locking the GTK - // thread indefinitely while processing continually arriving events - size_t num_processed = 0; - while (!_sigs.is_empty() && num_processed++ < _sigs.capacity()/2) { - cerr << "-- emitting event\n"; - Closure& ev = _sigs.pop(); - ev(); - ev.disconnect(); - } - - return true; -} - - -} // namespace LibOmClient diff --git a/src/clients/ThreadedSigClientInterface.h b/src/clients/ThreadedSigClientInterface.h deleted file mode 100644 index 16259531..00000000 --- a/src/clients/ThreadedSigClientInterface.h +++ /dev/null @@ -1,177 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 THREADEDSIGCLIENTINTERFACE_H -#define THREADEDSIGCLIENTINTERFACE_H - -#include -#include -#include -#include "interface/ClientInterface.h" -#include "SigClientInterface.h" -#include "util/Queue.h" -using std::string; - -/** Returns nothing and takes no parameters (because they have all been bound) */ -typedef sigc::slot Closure; - -namespace LibOmClient { - - -/** A LibSigC++ signal emitting interface for clients to use. - * - * This emits signals (possibly) in a different thread than the ClientInterface - * functions are called. It must be explicitly driven with the emit_signals() - * function, which fires all enqueued signals up until the present. You can - * use this in a GTK idle callback for receiving thread safe engine signals. - */ -class ThreadedSigClientInterface : virtual public SigClientInterface -{ -public: - ThreadedSigClientInterface(uint32_t queue_size) - : _sigs(queue_size) - , error_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_error)) - //, new_plugin_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_plugin_model)) - //, new_patch_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_patch_model)) - //, new_node_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_node_model)) - //, new_port_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_port_model)) - //, connection_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_connection_model)) - , new_plugin_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_plugin)) - , new_patch_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_patch)) - , new_node_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_node)) - , new_port_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_port)) - , connection_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_connection)) - , patch_enabled_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_patch_enabled)) - , patch_disabled_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_patch_disabled)) - , patch_cleared_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_patch_cleared)) - , object_destroyed_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_object_destroyed)) - , object_renamed_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_object_renamed)) - , disconnection_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_disconnection)) - , metadata_update_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_metadata_update)) - , control_change_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_control_change)) - , program_add_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_program_add)) - , program_remove_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_program_remove)) - {} - - - // FIXME - void bundle_begin() {} - void bundle_end() {} - - void num_plugins(uint32_t num) { _num_plugins = num; } - - void error(const string& msg) - { push_sig(sigc::bind(error_slot, msg)); } - /* - void new_plugin_model(PluginModel* const pm) - { push_sig(sigc::bind(new_plugin_slot, pm)); } - - void new_patch_model(PatchModel* const pm) - { push_sig(sigc::bind(new_patch_slot, pm)); } - - void new_node_model(NodeModel* const nm) - { assert(nm); push_sig(sigc::bind(new_node_slot, nm)); } - - void new_port_model(PortModel* const pm) - { push_sig(sigc::bind(new_port_slot, pm)); } - - void connection_model(ConnectionModel* const cm) - { push_sig(sigc::bind(connection_slot, cm)); } - */ - void new_plugin(const string& type, const string& uri, const string& name) - { push_sig(sigc::bind(new_plugin_slot, type, uri, name)); } - - void new_patch(const string& path, uint32_t poly) - { push_sig(sigc::bind(new_patch_slot, path, poly)); } - - void new_node(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports) - { push_sig(sigc::bind(new_node_slot, plugin_type, plugin_uri, node_path, is_polyphonic, num_ports)); } - - void new_port(const string& path, const string& data_type, bool is_output) - { push_sig(sigc::bind(new_port_slot, path, data_type, is_output)); } - - void connection(const string& src_port_path, const string& dst_port_path) - { push_sig(sigc::bind(connection_slot, src_port_path, dst_port_path)); } - - void object_destroyed(const string& path) - { push_sig(sigc::bind(object_destroyed_slot, path)); } - - void patch_enabled(const string& path) - { push_sig(sigc::bind(patch_enabled_slot, path)); } - - void patch_disabled(const string& path) - { push_sig(sigc::bind(patch_disabled_slot, path)); } - - void patch_cleared(const string& path) - { push_sig(sigc::bind(patch_cleared_slot, path)); } - - void object_renamed(const string& old_path, const string& new_path) - { push_sig(sigc::bind(object_renamed_slot, old_path, new_path)); } - - void disconnection(const string& src_port_path, const string& dst_port_path) - { push_sig(sigc::bind(disconnection_slot, src_port_path, dst_port_path)); } - - void metadata_update(const string& path, const string& key, const string& value) - { push_sig(sigc::bind(metadata_update_slot, path, key, value)); } - - void control_change(const string& port_path, float value) - { push_sig(sigc::bind(control_change_slot, port_path, value)); } - - void program_add(const string& path, uint32_t bank, uint32_t program, const string& name) - { push_sig(sigc::bind(program_add_slot, path, bank, program, name)); } - - void program_remove(const string& path, uint32_t bank, uint32_t program) - { push_sig(sigc::bind(program_remove_slot, path, bank, program)); } - - /** Process all queued events - Called from GTK thread to emit signals. */ - bool emit_signals(); - -private: - void push_sig(Closure ev); - - Queue _sigs; - uint32_t _num_plugins; - - sigc::slot bundle_begin_slot; - sigc::slot bundle_end_slot; - sigc::slot num_plugins_slot; - sigc::slot error_slot; - /*sigc::slot new_plugin_slot; - sigc::slot new_patch_slot; - sigc::slot new_node_slot; - sigc::slot new_port_slot; - sigc::slot connection_slot; */ - sigc::slot new_plugin_slot; - sigc::slot new_patch_slot; - sigc::slot new_node_slot; - sigc::slot new_port_slot; - sigc::slot connection_slot; - sigc::slot patch_enabled_slot; - sigc::slot patch_disabled_slot; - sigc::slot patch_cleared_slot; - sigc::slot object_destroyed_slot; - sigc::slot object_renamed_slot; - sigc::slot disconnection_slot; - sigc::slot metadata_update_slot; - sigc::slot control_change_slot; - sigc::slot program_add_slot; - sigc::slot program_remove_slot; -}; - - -} // namespace LibOmClient - -#endif diff --git a/src/clients/console/ConsoleClientHooks.cpp b/src/clients/console/ConsoleClientHooks.cpp deleted file mode 100644 index 1a911c6a..00000000 --- a/src/clients/console/ConsoleClientHooks.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* This file is part of Om. 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 "ConsoleClientHooks.h" - -#include - - -void -ConsoleClientHooks::new_node(NodeModel* nm) -{ - std::cerr << "[ConsoleClient] New node notification" << std::endl; -} - -void -ConsoleClientHooks::error(std::string msg) -{ - std::cerr << "Server returned an error: " << msg << std::endl; -} diff --git a/src/clients/console/ConsoleClientHooks.h b/src/clients/console/ConsoleClientHooks.h deleted file mode 100644 index ceb6cd5a..00000000 --- a/src/clients/console/ConsoleClientHooks.h +++ /dev/null @@ -1,66 +0,0 @@ -/* This file is part of Om. 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 CONSOLECLIENTHOOKS_H -#define CONSOLECLIENTHOOKS_H - -#include "ClientHooks.h" - -#include -using std::string; - -namespace LibOmClient { - -class PatchModel; -class NodeModel; -class ConnectionModel; -class PortModel; -class MetadataModel; -class PluginModel; - -class ConsoleClientHooks : public ClientHooks -{ -public: - ConsoleClientHooks() - ~ConsoleClientHooks(); - - void error(const string& msg); - void new_node(NodeModel* nm); - - void engine_enabled() {} - void engine_disabled() {} - void new_patch(PatchModel* pm) {} - void new_port(PortModel* port_info) {} - void port_removal(const string& path) {} - void patch_destruction(const string& path) {} - void patch_enabled(const string& path) {} - void patch_disabled(const string& path) {} - void node_removal(const string& path) {} - void object_renamed(const string& old_path, const string& new_path) {} - void connection(ConnectionModel* cm) {} - void disconnection(const string& src_port_path, const string& dst_port_path) {} - void metadata_update(MetadataModel* mm) {} - void control_change(const string& port_path, float value) {} - void new_plugin(PluginModel* pi) {} - void program_add(const string& path, int bank, int program, const string& name) {} - void program_remove(const string& path, int bank, int program) {} -}; - - -} // namespace LibOmClient - - -#endif // CONSOLECLIENTHOOKS_H diff --git a/src/clients/console/Makefile.am b/src/clients/console/Makefile.am deleted file mode 100644 index f46bdbad..00000000 --- a/src/clients/console/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -om_console_client_CXXFLAGS = -I$(top_srcdir)/src/clients -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) -om_console_client_LDADD = ../libomclient.a $(LOSC_LIBS) $(LXML2_LIBS) - -bin_PROGRAMS = console_client -EXTRA_DIST = README - -console_client_CXXFLAGS = "-I../../common" -console_client_LDADD = @LOSC_LIBS@ ../Comm.o -console_client_SOURCES = \ - console_client.cpp \ - ConsoleClientHooks.h \ - ConsoleClientHooks.cpp diff --git a/src/clients/console/README b/src/clients/console/README deleted file mode 100644 index 79c629a5..00000000 --- a/src/clients/console/README +++ /dev/null @@ -1,4 +0,0 @@ -Everything in and under this directory is very, very, very old. It remains -on the off chance that I actually make it work again - and for history's -sake :) - diff --git a/src/clients/console/console_client.cpp b/src/clients/console/console_client.cpp deleted file mode 100644 index 4e5586ce..00000000 --- a/src/clients/console/console_client.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* This file is part of Om. 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 -#include -#include -#include -#include "OSCModelEngineInterface.h" -#include "ConsoleClientHooks.h" - - -OSCModelEngineInterface* comm; -ConsoleClientHooks* client_hooks; - -int -main() -{ - std::string input; - std::string s; - std::string path; - std::string types; - lo_message m; - - client_hooks = new ConsoleClientHooks(); - comm = new OSCModelEngineInterface(client_hooks); - comm->attach("1234"); - - while (input != "q") { - std::cout << "> "; - std::getline(std::cin, input); - std::istringstream stream(input); - - if (std::cin.eof()) break; - - if (input == "") continue; - - //std::cout << "INPUT = " << input << std::endl; - - m = lo_message_new(); - stream >> path; - - char cs[256]; - - stream >> types; - - for (uint i=0; stream >> s && i < types.length(); ++i) { - // Take care of quoted strings - if (s[0] == '\"') { - s = s.substr(1); // hack off begin quote - - if (s[s.length()-1] == '\"') { // single quoted word - s = s.substr(0, s.length()-1); - } else { - std::string temp; - do { - stream >> temp; - if (temp.find('\n') != std::string::npos) { - std::cerr << "Mismatched quotes.\n" << std::endl; - break; - } - s += ' '; - s += temp; - } while (temp[temp.length()-1] != '\"'); - s = s.substr(0, s.length() - 1); // hack off end quote - } - } - - switch (types[i]) { - case 'f': - //std::cerr << "float" << std::endl; - lo_message_add_float(m, atof(s.c_str())); - break; - case 's': - strncpy(cs, s.c_str(), 256); - //std::cerr << "string" << std::endl; - lo_message_add_string(m, cs); - break; - case 'i': - //std::cerr << "integer" << std::endl; - lo_message_add_int32(m, atoi(s.c_str())); - break; - default: - std::cerr << "Unknown type \'" << types[i] << "\'" << std::endl; - exit(1); - } - } - - //std::cout << "Sending message..." << std::endl; - //lo_message_pp(m); - //usleep(500); - lo_send_message(comm->addr(), path.c_str(), m); - lo_message_free(m); - //std::cout << "Input = " << input << std::endl; - input = ""; - } - return 0; -} diff --git a/src/clients/console/patches/COPYING b/src/clients/console/patches/COPYING deleted file mode 100644 index e265c4a3..00000000 --- a/src/clients/console/patches/COPYING +++ /dev/null @@ -1,2 +0,0 @@ -The files in this directory are temporary and not considered code; thus are -released into the public domain. You may do with them as you please. diff --git a/src/clients/console/patches/dssi_test.omp b/src/clients/console/patches/dssi_test.omp deleted file mode 100644 index 0613a57b..00000000 --- a/src/clients/console/patches/dssi_test.omp +++ /dev/null @@ -1,19 +0,0 @@ -/create_patch si patch1 1 -/patches/patch1/add_output s out_1 -/patches/patch1/add_output s out_2 - -/patches/patch1/add_midi_input - -/patches/patch1/load_dssi_plugin sss trivial_synth.so trivial_synth synth - -/patches/patch1/connect ssss midi_in Frequency synth Frequency -/patches/patch1/connect ssss synth Output output out_1 -/patches/patch1/connect ssss synth Output output out_2 - -/patches/patch1/set_control ssf midi_in Frequency 440 - -/patches/patch1/set_control ssf osc Slope 0.5 - -/patches/patch1/activate -/engine/set_master_patch s patch1 -/engine/start diff --git a/src/clients/console/patches/filter_patch.omp b/src/clients/console/patches/filter_patch.omp deleted file mode 100644 index acaad0c8..00000000 --- a/src/clients/console/patches/filter_patch.omp +++ /dev/null @@ -1,54 +0,0 @@ -/create_patch si patch1 1 -/patches/patch1/add_output s out_1 -/patches/patch1/add_output s out_2 - -/patches/patch1/add_midi_input - -/patches/patch1/load_ladspa_plugin isss 1 triangle_1649.so triangle_fcsc_oa osc -/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control aenv -/patches/patch1/load_ladspa_plugin isss 1 amp_1654.so amp_gaia_oa amp -/patches/patch1/load_ladspa_plugin isss 1 lp4pole_1671.so lp4pole_fcrcia_oa filt -/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control fenv -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa fscale -/patches/patch1/load_ladspa_plugin isss 1 sum_1665.so sum_iaic_oa sum - -/patches/patch1/connect ssss midi_in Frequency osc Frequency -/patches/patch1/connect ssss midi_in Gate aenv "Gate" -/patches/patch1/connect ssss midi_in Gate fenv "Gate" -/patches/patch1/connect ssss osc Output filt Input -/patches/patch1/connect ssss fenv "Envelope Out" fscale "First Input" -/patches/patch1/connect ssss fscale "Product Output" sum "First Input" -/patches/patch1/connect ssss midi_in Frequency sum "Second Input" -/patches/patch1/connect ssss sum "Summed Output" filt "Cutoff Frequency" - -/patches/patch1/connect ssss filt Output amp "Input" -/patches/patch1/connect ssss aenv "Envelope Out" amp "Gain (dB)" -/patches/patch1/connect ssss amp "Output" output out_1 -/patches/patch1/connect ssss amp "Output" output out_2 - - -/patches/patch1/set_control ssf midi_in Frequency 200.0 -/patches/patch1/set_control ssf midi_in Gate 0.0 -/patches/patch1/set_control ssf filt Resonance 3.0 -/patches/patch1/set_control ssf osc Slope 0.9 -/patches/patch1/set_control ssf fscale "Second Input" 800 - -/patches/patch1/set_control ssf aenv "Trigger" 0 -/patches/patch1/set_control ssf aenv "Delay Time (s)" 0.0 -/patches/patch1/set_control ssf aenv "Attack Time (s)" 0.01 -/patches/patch1/set_control ssf aenv "Hold Time (s)" 0.0 -/patches/patch1/set_control ssf aenv "Decay Time (s)" 0.3 -/patches/patch1/set_control ssf aenv "Sustain Level" 0.7 -/patches/patch1/set_control ssf aenv "Release Time (s)" 1.5 - -/patches/patch1/set_control ssf fenv "Trigger" 0 -/patches/patch1/set_control ssf fenv "Delay Time (s)" 0.0 -/patches/patch1/set_control ssf fenv "Attack Time (s)" 0.0 -/patches/patch1/set_control ssf fenv "Hold Time (s)" 0.0 -/patches/patch1/set_control ssf fenv "Decay Time (s)" 0.1 -/patches/patch1/set_control ssf fenv "Sustain Level" 0.0 -/patches/patch1/set_control ssf fenv "Release Time (s)" 0.0 - -/patches/patch1/activate -/engine/set_master_patch s patch1 -/engine/start diff --git a/src/clients/console/patches/old_super_simple_patch.omp b/src/clients/console/patches/old_super_simple_patch.omp deleted file mode 100644 index 1abd3c23..00000000 --- a/src/clients/console/patches/old_super_simple_patch.omp +++ /dev/null @@ -1,36 +0,0 @@ -/create_patch si patch1 4 -/patches/patch1/add_output s out_1 -/patches/patch1/add_output s out_2 - -/patches/patch1/add_midi_input - -/patches/patch1/load_ladspa_plugin isss 1 triangle_1649.so triangle_fcsc_oa osc -/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control aenv -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaia_oa amp -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa endamp - -/patches/patch1/connect ssss midi_in Frequency osc Frequency -/patches/patch1/connect ssss midi_in Gate aenv "Gate" -/patches/patch1/connect ssss osc Output amp "First Input" -/patches/patch1/connect ssss aenv "Envelope Out" amp "Second Input" -/patches/patch1/connect ssss amp "Product Output" endamp "First Input" -/patches/patch1/connect ssss endamp "Product Output" output out_1 -/patches/patch1/connect ssss endamp "Product Output" output out_2 - - -/patches/patch1/set_control ssf midi_in Frequency 200 -/patches/patch1/set_control ssf midi_in Gate 0 -/patches/patch1/set_control ssf osc Slope 0.5 -/patches/patch1/set_control ssf endamp "Second Input" 0.5 - -/patches/patch1/set_control ssf aenv "Trigger" 0 -/patches/patch1/set_control ssf aenv "Delay Time (s)" 0.0 -/patches/patch1/set_control ssf aenv "Attack Time (s)" 0.001 -/patches/patch1/set_control ssf aenv "Hold Time (s)" 0.0 -/patches/patch1/set_control ssf aenv "Decay Time (s)" 0.3 -/patches/patch1/set_control ssf aenv "Sustain Level" 0.5 -/patches/patch1/set_control ssf aenv "Release Time (s)" 0.5 - -/patches/patch1/activate -/engine/set_master_patch s patch1 -/engine/start diff --git a/src/clients/console/patches/send_test.omp b/src/clients/console/patches/send_test.omp deleted file mode 100644 index 579a3b80..00000000 --- a/src/clients/console/patches/send_test.omp +++ /dev/null @@ -1,2 +0,0 @@ -/load_plugins -/send_plugins diff --git a/src/clients/console/patches/simple_patch.omp b/src/clients/console/patches/simple_patch.omp deleted file mode 100644 index aaa38827..00000000 --- a/src/clients/console/patches/simple_patch.omp +++ /dev/null @@ -1,54 +0,0 @@ -/load_plugins -/create_patch si patch1 1 -/patches/patch1/add_output s out_1 -/patches/patch1/add_output s out_2 - -/patches/patch1/add_midi_input - -/patches/patch1/load_ladspa_plugin isss 1 triangle_1649.so triangle_fcsc_oa osc -/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control aenv -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaia_oa amp -/patches/patch1/load_ladspa_plugin isss 1 lp4pole_1671.so lp4pole_fcrcia_oa filt -/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control fenv -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa fscale -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa endamp - -/patches/patch1/connect ssss midi_in Frequency osc Frequency -/patches/patch1/connect ssss midi_in Gate aenv "Gate" -/patches/patch1/connect ssss midi_in Gate fenv "Gate" -/patches/patch1/connect ssss osc Output filt Input -/patches/patch1/connect ssss fenv "Envelope Out" fscale "First Input" -/patches/patch1/connect ssss fscale "Product Output" filt "Cutoff Frequency" -/patches/patch1/connect ssss filt Output amp "First Input" -/patches/patch1/connect ssss aenv "Envelope Out" amp "Second Input" -/patches/patch1/connect ssss amp "Product Output" endamp "First Input" -/patches/patch1/connect ssss endamp "Product Output" output out_1 -/patches/patch1/connect ssss endamp "Product Output" output out_2 - - -/patches/patch1/set_control ssf midi_in Frequency 200.0 -/patches/patch1/set_control ssf midi_in Gate 0.0 -/patches/patch1/set_control ssf filt Resonance 2.0 -/patches/patch1/set_control ssf osc Slope 1.0 -/patches/patch1/set_control ssf fscale "Second Input" 900 -/patches/patch1/set_control ssf endamp "Second Input" 0.5 - -/patches/patch1/set_control ssf aenv "Trigger" 0 -/patches/patch1/set_control ssf aenv "Delay Time (s)" 0.0 -/patches/patch1/set_control ssf aenv "Attack Time (s)" 0.01 -/patches/patch1/set_control ssf aenv "Hold Time (s)" 0.0 -/patches/patch1/set_control ssf aenv "Decay Time (s)" 0.3 -/patches/patch1/set_control ssf aenv "Sustain Level" 0.6 -/patches/patch1/set_control ssf aenv "Release Time (s)" 0.6 - -/patches/patch1/set_control ssf fenv "Trigger" 0 -/patches/patch1/set_control ssf fenv "Delay Time (s)" 0.0 -/patches/patch1/set_control ssf fenv "Attack Time (s)" 0.0 -/patches/patch1/set_control ssf fenv "Hold Time (s)" 0.0 -/patches/patch1/set_control ssf fenv "Decay Time (s)" 0.2 -/patches/patch1/set_control ssf fenv "Sustain Level" 0.5 -/patches/patch1/set_control ssf fenv "Release Time (s)" 0.5 - -/patches/patch1/activate -/engine/set_master_patch s patch1 -/engine/start diff --git a/src/clients/console/patches/super_simple_patch.omp b/src/clients/console/patches/super_simple_patch.omp deleted file mode 100644 index 02dc63a2..00000000 --- a/src/clients/console/patches/super_simple_patch.omp +++ /dev/null @@ -1,36 +0,0 @@ -/load_plugins - -/create_patch si patch1 1 - -/patches/patch1/load_internal_plugin iss 0 midi_in midi_in -/patches/patch1/load_internal_plugin iss 0 output output - -/patches/patch1/load_ladspa_plugin isss 0 triangle_1649.so triangle_fcsc_oa osc -/patches/patch1/load_ladspa_plugin isss 0 dahdsr_2021.so dahdsr_cg+t_control aenv -/patches/patch1/load_ladspa_plugin isss 0 product_1668.so product_iaia_oa amp -/patches/patch1/load_ladspa_plugin isss 0 product_1668.so product_iaic_oa endamp - -/patches/patch1/connect sisi midi_in 0 osc 0 -/patches/patch1/connect sisi midi_in 1 aenv 0 -/patches/patch1/connect sisi osc 2 amp 0 -/patches/patch1/connect sisi aenv 8 amp 1 -/patches/patch1/connect sisi amp 2 endamp 0 -/patches/patch1/connect sisi endamp 2 output 0 -/patches/patch1/connect sisi endamp 2 output 1 - - -/patches/patch1/set_control sif midi_in 0 200 -/patches/patch1/set_control sif midi_in 1 1.0 -/patches/patch1/set_control sif osc 1 0.5 -/patches/patch1/set_control sif endamp 1 0.5 - -/patches/patch1/set_control sif aenv 1 0 -/patches/patch1/set_control sif aenv 2 0.0 -/patches/patch1/set_control sif aenv 3 0.001 -/patches/patch1/set_control sif aenv 4 0.0 -/patches/patch1/set_control sif aenv 5 0.3 -/patches/patch1/set_control sif aenv 6 0.5 -/patches/patch1/set_control sif aenv 7 0.5 - -/engine/set_master_patch i 0 -/engine/start diff --git a/src/clients/console/patches/test_patch.omp b/src/clients/console/patches/test_patch.omp deleted file mode 100644 index 04c0487b..00000000 --- a/src/clients/console/patches/test_patch.omp +++ /dev/null @@ -1,48 +0,0 @@ -/create_patch si patch1 1 -/patches/patch1/add_output s out_1 -/patches/patch1/add_output s out_2 - -/patches/patch1/add_midi_input - -/patches/patch1/load_ladspa_plugin isss 1 triangle_1649.so triangle_fcsc_oa osc -/patches/patch1/load_ladspa_plugin isss 1 adsr_1653.so adsr aenv -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaia_oa amp -/patches/patch1/load_ladspa_plugin isss 1 lp4pole_1671.so lp4pole_fcrcia_oa filt -/patches/patch1/load_ladspa_plugin isss 1 adsr_1653.so adsr fenv -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa fscale -/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa endamp - -/patches/patch1/connect ssss midi_in Frequency osc Frequency -/patches/patch1/connect ssss midi_in Gate aenv "Driving Signal" -/patches/patch1/connect ssss midi_in Gate fenv "Driving Signal" -/patches/patch1/connect ssss osc Output filt Input -/patches/patch1/connect ssss fenv "Envelope Out" output out_1 -/patches/patch1/connect ssss fscale "Product Output" filt "Cutoff Frequency" -/patches/patch1/connect ssss filt Output amp "First Input" -/patches/patch1/connect ssss aenv "Envelope Out" output out_2 -/patches/patch1/connect ssss amp "Product Output" endamp "First Input" -/patches/patch1/connect ssss endamp "Product Output" output out_1 -/patches/patch1/connect ssss endamp "Product Output" output out_2 - - -/patches/patch1/set_control ssf midi_in Frequency 200 -/patches/patch1/set_control ssf filt Resonance 3.0 -/patches/patch1/set_control ssf osc Slope 1.0 -/patches/patch1/set_control ssf fscale "Second Input" 900 -/patches/patch1/set_control ssf endamp "Second Input" 0.5 - -/patches/patch1/set_control ssf aenv "Trigger Threshold" 0 -/patches/patch1/set_control ssf aenv "Attack Time (s)" 0.1 -/patches/patch1/set_control ssf aenv "Decay Time (s)" 0.3 -/patches/patch1/set_control ssf aenv "Sustain Level" 0.5 -/patches/patch1/set_control ssf aenv "Release Time (s)" 0.5 - -/patches/patch1/set_control ssf fenv "Trigger Threshold" 0 -/patches/patch1/set_control ssf fenv "Attack Time (s)" 0.1 -/patches/patch1/set_control ssf fenv "Decay Time (s)" 0.2 -/patches/patch1/set_control ssf fenv "Sustain Level" 0.6 -/patches/patch1/set_control ssf fenv "Release Time (s)" 0.4 - -/patches/patch1/activate -/engine/set_master_patch s patch1 -/engine/start diff --git a/src/clients/demolition/DemolitionClientInterface.cpp b/src/clients/demolition/DemolitionClientInterface.cpp deleted file mode 100644 index e58371d4..00000000 --- a/src/clients/demolition/DemolitionClientInterface.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* This file is part of Om. 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 "DemolitionClientInterface.h" -#include "DemolitionModel.h" - - -DemolitionClientInterface::DemolitionClientInterface(DemolitionModel* model) -: m_model(model) -{ -} - - -DemolitionClientInterface::~DemolitionClientInterface() -{ -} - - -void -DemolitionClientInterface::error(const string& msg) -{ -} - - -void -DemolitionClientInterface::new_patch_model(PatchModel* pm) -{ - m_model->add_patch(pm); -} - - -void -DemolitionClientInterface::new_port_model(PortModel* port_model) -{ - m_model->add_port(port_model); -} - - -void -DemolitionClientInterface::object_destroyed(const string& path) -{ - m_model->remove_object(path); -} - -void -DemolitionClientInterface::patch_enabled(const string& path) -{ -} - - -void -DemolitionClientInterface::patch_disabled(const string& path) -{ -} - - -void -DemolitionClientInterface::new_node_model(NodeModel* nm) -{ - m_model->add_node(nm); -} - - -void -DemolitionClientInterface::object_renamed(const string& old_path, const string& new_path) -{ - m_model->object_renamed(old_path, new_path); -} - - -void -DemolitionClientInterface::connection_model(ConnectionModel* cm) -{ - m_model->add_connection(cm); -} - - -void -DemolitionClientInterface::disconnection(const string& src_port_path, const string& dst_port_path) -{ - m_model->remove_connection(src_port_path, dst_port_path); -} - - -void -DemolitionClientInterface::control_change(const string& port_path, float value) -{ -} - - -void -DemolitionClientInterface::new_plugin_model(PluginModel* pi) -{ - m_model->add_plugin(pi); -} - diff --git a/src/clients/demolition/DemolitionClientInterface.h b/src/clients/demolition/DemolitionClientInterface.h deleted file mode 100644 index 374008b5..00000000 --- a/src/clients/demolition/DemolitionClientInterface.h +++ /dev/null @@ -1,75 +0,0 @@ -/* This file is part of Om. 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 DEMOLITIONCLIENTHOOKS_H -#define DEMOLITIONCLIENTHOOKS_H - -#include -#include -#include "ModelClientInterface.h" -#include "DemolitionModel.h" -#include "PluginModel.h" -using std::string; - -using namespace LibOmClient; - - -/** ModelClientInterface implementation for the Gtk client. - * - * These are the hooks into the GUI for the Comm class. - * - * \ingroup OmGtk - */ -class DemolitionClientInterface : public ModelClientInterface -{ -public: - DemolitionClientInterface(DemolitionModel* model); - virtual ~DemolitionClientInterface(); - - void bundle_begin() {} - void bundle_end() {} - - void num_plugins(size_t num) {} - - // OSC thread functions - void error(const string& msg); - - void new_plugin(const string& type, - const string& uri, - const string& name) {} - void new_patch_model(PatchModel* const pm); - void new_port_model(PortModel* const port_model); - void object_destroyed(const string& path); - void patch_enabled(const string& path); - void patch_disabled(const string& path); - void patch_cleared(const string& path) { throw; } - void new_node_model(NodeModel* const nm); - void object_renamed(const string& old_path, const string& new_path); - void connection_model(ConnectionModel* const cm); - void disconnection(const string& src_port_path, const string& dst_port_path); - void metadata_update(const string& path, const string& key, const string& value) {} - void control_change(const string& port_path, float value); - void new_plugin_model(PluginModel* const pi); - void program_add(const string& path, uint32_t bank, uint32_t program, const string& name) {}; - void program_remove(const string& path, uint32_t bank, uint32_t program) {}; - -private: - DemolitionModel* m_model; -}; - - -#endif // DEMOLITIONCLIENTHOOKS_H diff --git a/src/clients/demolition/DemolitionModel.cpp b/src/clients/demolition/DemolitionModel.cpp deleted file mode 100644 index 786c08cd..00000000 --- a/src/clients/demolition/DemolitionModel.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* This file is part of Om. 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 "DemolitionModel.h" -#include "util/Path.h" -#include "PluginModel.h" -#include -#include -using std::cout; using std::cerr; using std::endl; - - -DemolitionModel::~DemolitionModel() -{ - for (vector::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) - delete *i; - - for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) - delete *i; -} - - -PatchModel* -DemolitionModel::random_patch() -{ - if (m_patches.size() == 0) - return NULL; - else - return m_patches.at(rand() % m_patches.size()); -} - - -NodeModel* -DemolitionModel::random_node() -{ - int max_attempts = m_patches.size()*4; - int attempts = 0; - - while (attempts++ < max_attempts) { - PatchModel* pm = random_patch(); - - if (pm == NULL) { - return NULL; - } else { - int size = pm->nodes().size(); - if (size == 0) - continue; - int index = rand() % size; - NodeModelMap::const_iterator i = pm->nodes().begin(); - for (int j=0; j < index; ++j) { - ++i; - if (i == pm->nodes().end()) - return NULL; - } - return (*i).second; - } - } - //cout << "***************************** Not returning node *********" << endl; - return NULL; -} - - -NodeModel* -DemolitionModel::random_node_in_patch(PatchModel* pm) -{ - if (pm == NULL) - return NULL; - - int size = pm->nodes().size(); - if (size == 0) - return NULL; - - int index = rand() % size; - NodeModelMap::const_iterator i = pm->nodes().begin(); - for (int j=0; j < index; ++j) { - ++i; - if (i == pm->nodes().end()) - return NULL; - } - return (*i).second; -} - - -PortModel* -DemolitionModel::random_port() -{ - NodeModel* node = random_node(); - - if (node == NULL) return NULL; - - PortModelList ports = node->ports(); - - int num_ports = ports.size(); - int index = rand() % num_ports; - int i = 0; - - for (PortModelList::iterator p = ports.begin(); p != ports.end(); ++p, ++i) - if (i == index) - return (*p); - - return NULL; // shouldn't happen -} - - -PortModel* -DemolitionModel::random_port_in_node(NodeModel* node) -{ - if (node == NULL) - return NULL; - - PortModelList ports = node->ports(); - - int num_ports = ports.size(); - int index = rand() % num_ports; - int i = 0; - - for (PortModelList::iterator p = ports.begin(); p != ports.end(); ++p, ++i) - if (i == index) - return (*p); - - return NULL; // shouldn't happen -} - - -PluginModel* -DemolitionModel::random_plugin() -{ - if (m_plugins.size() == 0) - return NULL; - else - return m_plugins.at(rand() % m_plugins.size()); -} - - -PatchModel* -DemolitionModel::patch(const Path& path) -{ - for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) { - if ((*i)->path() == path) - return (*i); - } - return NULL; -} - - -NodeModel* -DemolitionModel::node(const Path& path) -{ - NodeModel* ret = NULL; - - for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) { - ret = (*i)->get_node(path.name()); - if (ret != NULL) - break; - } - return ret; -} - - -void -DemolitionModel::remove_object(const Path& path) -{ - // Patch - for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) { - if ((*i)->path() == path) { - delete (*i); - m_patches.erase(i); - break; - } - } - - // Node - PatchModel* parent = patch(path.parent()); - if (parent != NULL) - parent->remove_node(path.name()); -} - - -void -DemolitionModel::add_node(NodeModel* nm) -{ - PatchModel* parent = patch(nm->path().parent()); - if (parent == NULL) { - cout << "**** ERROR: Parent for new Node does not exist." << endl; - } else { - parent->add_node(nm); - } -} - - -void -DemolitionModel::add_port(PortModel* pm) -{ -} - - -void -DemolitionModel::add_connection(ConnectionModel* cm) -{ -} - - -void -DemolitionModel::remove_connection(const Path& src_port_path, const Path& dst_port_path) -{ -} - -void -DemolitionModel::object_renamed(const Path& old_path, const Path& new_path) -{ - /* FIXME: broken, does not rename children - assert(OmPath::parent(old_path) == OmPath::parent(new_path)); - - // Rename node - NodeModel* nm = get_node(old_path); - if (nm != NULL) { - if (nm->parent() != NULL) { - nm->parent()->remove_node(OmPath::name(old_path)); - nm->path(new_path); - nm->parent()->add_node(OmPath::name(new_path)); - } - } - - // Rename patch - for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) { - if ((*i)->path() == path) { - delete (*i); - m_patches.erase(i); - return; - } - } - */ -} - diff --git a/src/clients/demolition/DemolitionModel.h b/src/clients/demolition/DemolitionModel.h deleted file mode 100644 index 64e0cc61..00000000 --- a/src/clients/demolition/DemolitionModel.h +++ /dev/null @@ -1,60 +0,0 @@ -/* This file is part of Om. 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 DEMOLITIONMODEL_H -#define DEMOLITIONMODEL_H - -#include -#include "PatchModel.h" -#include "util/Path.h" -using Om::Path; -using std::vector; - -using namespace LibOmClient; - -class DemolitionModel { -public: - ~DemolitionModel(); - - PatchModel* random_patch(); - NodeModel* random_node(); - NodeModel* random_node_in_patch(PatchModel* patch); - PortModel* random_port(); - PortModel* random_port_in_node(NodeModel* node); - PluginModel* random_plugin(); - - PatchModel* patch(const Path& path); - NodeModel* node(const Path& path); - - void add_patch(PatchModel* pm) { m_patches.push_back(pm); } - void add_node(NodeModel* nm); - void add_port(PortModel* pm); - void remove_object(const Path& path); - void add_connection(ConnectionModel* cm); - void remove_connection(const Path& src_port_path, const Path& dst_port_path); - void add_plugin(PluginModel* pi) { m_plugins.push_back(pi); } - - void object_renamed(const Path& old_path, const Path& new_path); - - int num_patches() { return m_patches.size(); } - -private: - vector m_plugins; - vector m_patches; -}; - - -#endif // DEMOLITIONMODEL_H diff --git a/src/clients/demolition/Makefile.am b/src/clients/demolition/Makefile.am deleted file mode 100644 index 4854f045..00000000 --- a/src/clients/demolition/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -EXTRA_DIST = README - -om_demolition_CXXFLAGS = -I$(top_srcdir)/src/clients -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) -om_demolition_LDADD = ../libomclient.a $(LOSC_LIBS) $(LXML2_LIBS) - -bin_PROGRAMS = om_demolition - -om_demolition_DEPENDENCIES = ../libomclient.a - -om_demolition_SOURCES = \ - DemolitionClientInterface.h \ - DemolitionClientInterface.cpp \ - DemolitionModel.h \ - DemolitionModel.cpp \ - demolition.cpp \ - cmdline.h \ - cmdline.c diff --git a/src/clients/demolition/README b/src/clients/demolition/README deleted file mode 100644 index 536d3481..00000000 --- a/src/clients/demolition/README +++ /dev/null @@ -1,7 +0,0 @@ -This is a stress tester for the Om engine. - -It constantly sends random events (with a bias towards sane events) to the -engine, to test for potential segfaults (or assertion failures, etc). - -It's not very clever at the moment, and doesn't hit all test cases. Renaming -is also not supported yet. diff --git a/src/clients/demolition/cmdline.c b/src/clients/demolition/cmdline.c deleted file mode 100644 index 11fcd108..00000000 --- a/src/clients/demolition/cmdline.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - File autogenerated by gengetopt version 2.10 - generated with the following command: - gengetopt - - The developers of gengetopt consider the fixed text that goes in all - gengetopt output files to be in the public domain: - we make no copyright claims on it. -*/ - - -#include -#include -#include - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "getopt.h" - -#include "cmdline.h" - -void -cmdline_parser_print_version (void) -{ - printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); -} - -void -cmdline_parser_print_help (void) -{ - cmdline_parser_print_version (); - printf("\n" - "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); - printf(" -h --help Print help and exit\n"); - printf(" -V --version Print version and exit\n"); - printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n"); - printf(" -pINT --client-port=INT Client port to listen on\n"); -} - - -static char *gengetopt_strdup (const char *s); - -/* gengetopt_strdup() */ -/* strdup.c replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) -{ - char *result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; -} - -int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) -{ - int c; /* Character of the parsed option. */ - int missing_required_options = 0; - - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->engine_url_given = 0 ; - args_info->client_port_given = 0 ; -#define clear_args() { \ - args_info->engine_url_arg = NULL; \ -} - - clear_args(); - - optarg = 0; - optind = 1; - opterr = 1; - optopt = '?'; - - while (1) - { - int option_index = 0; - char *stop_char; - - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "engine-url", 1, NULL, 'u' }, - { "client-port", 1, NULL, 'p' }, - { NULL, 0, NULL, 0 } - }; - - stop_char = 0; - c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index); - - if (c == -1) break; /* Exit from `while (1)' loop. */ - - switch (c) - { - case 'h': /* Print help and exit. */ - clear_args (); - cmdline_parser_print_help (); - exit (EXIT_SUCCESS); - - case 'V': /* Print version and exit. */ - clear_args (); - cmdline_parser_print_version (); - exit (EXIT_SUCCESS); - - case 'u': /* Om engine URL to connect to. */ - if (args_info->engine_url_given) - { - fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->engine_url_given = 1; - args_info->engine_url_arg = gengetopt_strdup (optarg); - break; - - case 'p': /* Client port to listen on. */ - if (args_info->client_port_given) - { - fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->client_port_given = 1; - args_info->client_port_arg = strtol (optarg,&stop_char,0); - break; - - - case 0: /* Long option with no short option */ - - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - exit (EXIT_FAILURE); - - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); - abort (); - } /* switch */ - } /* while */ - - - if ( missing_required_options ) - exit (EXIT_FAILURE); - - return 0; -} diff --git a/src/clients/demolition/cmdline.ggo b/src/clients/demolition/cmdline.ggo deleted file mode 100644 index 8fb68170..00000000 --- a/src/clients/demolition/cmdline.ggo +++ /dev/null @@ -1,7 +0,0 @@ -# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) - -package "om_demolition - A stress testing client for Om" - -option "engine-url" u "Om engine URL to connect to" string no -option "client-port" p "Client port to listen on" int no - diff --git a/src/clients/demolition/cmdline.h b/src/clients/demolition/cmdline.h deleted file mode 100644 index be56aafe..00000000 --- a/src/clients/demolition/cmdline.h +++ /dev/null @@ -1,45 +0,0 @@ -/* cmdline.h */ - -/* File autogenerated by gengetopt version 2.10 */ - -#ifndef CMDLINE_H -#define CMDLINE_H - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef CMDLINE_PARSER_PACKAGE -#define CMDLINE_PARSER_PACKAGE "om_demolotion - A stress testing client for Om" -#endif - -#ifndef CMDLINE_PARSER_VERSION -#define CMDLINE_PARSER_VERSION VERSION -#endif - -struct gengetopt_args_info -{ - char * engine_url_arg; /* Om engine URL to connect to. */ - int client_port_arg; /* Client port to listen on. */ - - int help_given ; /* Whether help was given. */ - int version_given ; /* Whether version was given. */ - int engine_url_given ; /* Whether engine-url was given. */ - int client_port_given ; /* Whether client-port was given. */ - -} ; - -int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); - -void cmdline_parser_print_help(void); -void cmdline_parser_print_version(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CMDLINE_H */ diff --git a/src/clients/demolition/demolition.cpp b/src/clients/demolition/demolition.cpp deleted file mode 100644 index 84a08c84..00000000 --- a/src/clients/demolition/demolition.cpp +++ /dev/null @@ -1,334 +0,0 @@ -/* This file is part of Om. 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 "OSCModelEngineInterface.h" -#include "OSCModelEngineInterface.h" // FIXME: make conditional -#include "PatchLibrarian.h" -#include "DemolitionClientInterface.h" -#include "interface/ClientInterface.h" -#include "interface/ClientKey.h" -#include "util/CountedPtr.h" -#include -#include -#include -#include "cmdline.h" // generated by gengetopt - -using std::cout; -using std::endl; - -using namespace LibOmClient; - -void do_something(); - -string random_name(); - -void create_patch(); -void destroy(); -void add_node(); -void connect(); -void disconnect(); -void disconnect_all(); -void set_port_value(); -void set_port_value_queued(); -void rename_object(); - - -// Yay globals! -DemolitionModel* model; -OSCModelEngineInterface* engine; - - -int -main(int argc, char** argv) -{ - const char* engine_url = NULL; - int client_port = 0; - - /* Parse command line options */ - gengetopt_args_info args_info; - if (cmdline_parser (argc, argv, &args_info) != 0) - return 1; - - if (args_info.engine_url_given) { - engine_url = args_info.engine_url_arg; - } else { - cout << "[Main] No engine URL specified. Attempting to use osc.udp://localhost:16180" << endl; - engine_url = "osc.udp://localhost:16180"; - } - - if (args_info.client_port_given) - client_port = args_info.client_port_arg; - else - client_port = 0; // will choose a free port automatically - - model = new DemolitionModel(); - - // Create this first so engine interface (liblo) uses the port - CountedPtr client - = CountedPtr(new DemolitionClientInterface(model)); - - engine = new OSCModelEngineInterface(engine_url); - engine->activate(); - - /* Connect to engine */ - //engine->attach(engine_url); - engine->register_client(ClientKey(), (CountedPtr)client); - - engine->load_plugins(); - engine->request_plugins(); - - //int id = engine->get_next_request_id(); - engine->request_all_objects(/*id*/); - //engine->set_wait_response_id(id); - //engine->wait_for_response(); - - // Disable DSP for stress testing - engine->disable_patch("/"); - - while (true) { - do_something(); - usleep(100000); - } - - sleep(2); - engine->unregister_client(ClientKey()); - //engine->detach(); - - delete engine; - delete model; - - return 0; -} - -/** Does some random action - */ -void -do_something() -{ - int action = rand() % 10; - - switch(action) { - case 0: - create_patch(); break; - case 1: - destroy(); break; - case 2: - add_node(); break; - case 3: - connect(); break; - case 4: - disconnect(); break; - case 5: - disconnect_all(); break; - case 6: - set_port_value(); break; - case 7: - set_port_value_queued(); break; - case 8: - rename_object(); break; - default: - break; - } -} - - -string -random_name() -{ - int length = (rand()%10)+1; - string name(length, '-'); - - for (int i=0; i < length; ++i) - name[i] = 'a' + rand()%26; - - return name; -} - - -void -create_patch() -{ - // Make the probability of this happening inversely proportionate to the number - // of patches to keep the # in a sane range - //if (model->num_patches() > 0 && (rand() % model->num_patches())) - // return; - - bool subpatch = rand()%2; - PatchModel* parent = NULL; - string name = random_name(); - PatchModel* pm = NULL; - - if (subpatch) - parent = model->random_patch(); - - if (parent != NULL) - pm = new PatchModel(parent->path() +"/"+ name, (rand()%8)+1); - else - pm = new PatchModel(string("/") + name, (rand()%8)+1); - - cout << "Creating patch " << pm->path() << endl; - - engine->create_patch_from_model(pm); - - // Spread them out a bit for easier monitoring with om_gtk - char tmp_buf[8]; - snprintf(tmp_buf, 8, "%d", 1600 + rand()%800 - 400); - engine->set_metadata(pm->path(), "module-x", string(tmp_buf)); - snprintf(tmp_buf, 8, "%d", 1200 + rand()%700 - 350); - engine->set_metadata(pm->path(), "module-y", string(tmp_buf)); - - delete pm; -} - - -void -destroy() -{ - // Make the probability of this happening proportionate to the number - // of patches to keep the # in a sane range - if (model->num_patches() == 0 || !(rand() % model->num_patches())) - return; - - NodeModel* nm = NULL; - - if (rand()%2) - nm = model->random_patch(); - else - nm = model->random_node(); - - if (nm != NULL) { - cout << "Destroying " << nm->path() << endl; - engine->destroy(nm->path()); - } -} - - -void -add_node() -{ - PatchModel* parent = model->random_patch(); - PluginModel* plugin = model->random_plugin(); - - if (parent != NULL && plugin != NULL) { - NodeModel* nm = new NodeModel(parent->path() +"/"+ random_name()); - nm->plugin(plugin); - cout << "Adding node " << nm->path() << endl; - engine->create_node_from_model(nm); - // Spread them out a bit for easier monitoring with om_gtk - char tmp_buf[8]; - snprintf(tmp_buf, 8, "%d", 1600 + rand()%800 - 400); - engine->set_metadata(nm->path(), "module-x", tmp_buf); - snprintf(tmp_buf, 8, "%d", 1200 + rand()%700 - 350); - engine->set_metadata(nm->path(), "module-y", tmp_buf); - } -} - - -void -connect() -{ - if (!(rand() % 10)) { // Attempt a connection between two nodes in the same patch - PatchModel* parent = model->random_patch(); - NodeModel* n1 = model->random_node_in_patch(parent); - NodeModel* n2 = model->random_node_in_patch(parent); - PortModel* p1 = model->random_port_in_node(n1); - PortModel* p2 = model->random_port_in_node(n2); - - if (p1 != NULL && p2 != NULL) { - cout << "Connecting " << p1->path() << " -> " << p2->path() << endl; - engine->connect(p1->path(), p2->path()); - } - - } else { // Attempt a connection between two truly random nodes - PortModel* p1 = model->random_port(); - PortModel* p2 = model->random_port(); - - if (p1 != NULL && p2 != NULL) { - cout << "Connecting " << p1->path() << " -> " << p2->path() << endl; - engine->connect(p1->path(), p2->path()); - } - } -} - - -void -disconnect() -{ - PortModel* p1 = model->random_port(); - PortModel* p2 = model->random_port(); - - if (p1 != NULL && p2 != NULL) { - cout << "Disconnecting " << p1->path() << " -> " << p2->path() << endl; - engine->disconnect(p1->path(), p2->path()); - } -} - - -void -disconnect_all() -{ - PortModel* p = model->random_port(); - - if (p != NULL) { - cout << "Disconnecting all from" << p->path() << endl; - engine->disconnect_all(p->path()); - } -} - - -void -set_port_value() -{ - PortModel* pm = model->random_port(); - float val = (float)rand() / (float)RAND_MAX; - - if (pm != NULL) { - cout << "Setting control for port " << pm->path() << " to " << val << endl; - engine->set_port_value(pm->path(), val); - } -} - - -void -set_port_value_queued() -{ - PortModel* pm = model->random_port(); - float val = (float)rand() / (float)RAND_MAX; - - if (pm != NULL) { - cout << "Setting control (slow) for port " << pm->path() << " to " << val << endl; - engine->set_port_value_queued(pm->path(), val); - } -} - - -void -rename_object() -{ - // 1/6th chance of it being a patch - /*int type = rand()%6; - - if (type == 0) { - NodeModel* n = model->random_node(); - if (n != NULL) - engine->rename(n->path(), random_name()); - } else { - PatchModel* p = model->random_patch(); - if (p != NULL) - engine->rename(p->path(), random_name()); - }*/ -} - diff --git a/src/clients/gtk/App.cpp b/src/clients/gtk/App.cpp deleted file mode 100644 index 6b71b4ec..00000000 --- a/src/clients/gtk/App.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "App.h" -#include -#include -#include -#include -#include -#include -#include "ControlInterface.h" -#include "PatchView.h" -#include "OmModule.h" -#include "ControlPanel.h" -#include "SubpatchModule.h" -#include "OmFlowCanvas.h" -#include "GtkObjectController.h" -#include "PatchController.h" -#include "NodeController.h" -#include "PortController.h" -#include "LoadPluginWindow.h" -#include "PatchWindow.h" -#include "MessagesWindow.h" -#include "ConfigWindow.h" -#include "Controller.h" -#include "GladeFactory.h" -#include "util/Path.h" -#include "ObjectModel.h" -#include "PatchModel.h" -#include "PatchTreeWindow.h" -#include "Configuration.h" -#include "ConnectWindow.h" -#ifdef HAVE_LASH -#include "LashController.h" -#endif -using std::cerr; using std::cout; using std::endl; -using std::string; -namespace LibOmClient { class PluginModel; } -using namespace LibOmClient; - -namespace OmGtk { - -class OmPort; - -App::App() -: m_control_interface(new ControlInterface(this)), - m_configuration(new Configuration()), - m_about_dialog(NULL), - m_enable_signal(true) -{ - Glib::RefPtr glade_xml = GladeFactory::new_glade_reference(); - - glade_xml->get_widget_derived("connect_win", m_connect_window); - //glade_xml->get_widget_derived("new_patch_win", m_new_patch_window); - //glade_xml->get_widget_derived("load_patch_win", m_load_patch_window); - glade_xml->get_widget_derived("config_win", m_config_window); - glade_xml->get_widget_derived("patch_tree_win", m_patch_tree_window); -// glade_xml->get_widget_derived("main_patches_treeview", m_objects_treeview); - glade_xml->get_widget("about_win", m_about_dialog); - - m_config_window->configuration(m_configuration); - - glade_xml->get_widget_derived("messages_win", m_messages_window); -} - - -App::~App() -{ - delete m_control_interface; -} - - -void -App::error_message(const string& str) -{ - m_messages_window->post(str); - m_messages_window->show(); - m_messages_window->raise(); -} - - -/* -bool -App::idle_callback() -{ - m_client_hooks->process_events(); - -#ifdef HAVE_LASH - //if (lash_controller->enabled()) - // lash_controller->process_events(); -#endif - - return true; -} -*/ - - -/******** Event Handlers ************/ - - -#if 0 -App::event_load_session() -{ - Gtk::FileChooserDialog* dialog - = new Gtk::FileChooserDialog(*m_main_window, "Load Session", Gtk::FILE_CHOOSER_ACTION_OPEN); - - dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); - int result = dialog->run(); - string filename = dialog->get_filename(); - delete dialog; - - cout << result << endl; - - assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); - - if (result == Gtk::RESPONSE_OK) - //configuration->load_session(filename); - _controller->load_session(filename); -} - - -void -App::event_save_session_as() -{ - Gtk::FileChooserDialog dialog(*m_main_window, "Save Session", Gtk::FILE_CHOOSER_ACTION_SAVE); - - /* - Gtk::VBox* box = dialog.get_vbox(); - Gtk::Label warning("Warning: Recursively saving will overwrite any subpatch files \ - without confirmation."); - box->pack_start(warning, false, false, 2); - Gtk::CheckButton recursive_checkbutton("Recursively save all subpatches"); - box->pack_start(recursive_checkbutton, false, false, 0); - recursive_checkbutton.show(); - */ - dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); - - int result = dialog.run(); - //bool recursive = recursive_checkbutton.get_active(); - - assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); - - if (result == Gtk::RESPONSE_OK) { - string filename = dialog.get_filename(); - if (filename.length() < 11 || filename.substr(filename.length()-10) != ".omsession") - filename += ".omsession"; - - bool confirm = false; - std::fstream fin; - fin.open(filename.c_str(), std::ios::in); - if (fin.is_open()) { // File exists - string msg = "File already exists! Are you sure you want to overwrite "; - msg += filename + "?"; - Gtk::MessageDialog confirm_dialog(*m_main_window, - msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); - if (confirm_dialog.run() == Gtk::RESPONSE_YES) - confirm = true; - else - confirm = false; - } else { // File doesn't exist - confirm = true; - } - fin.close(); - - if (confirm) { - _controller->save_session(filename); - } - } -} -#endif - -void -App::add_patch_window(PatchWindow* pw) -{ - m_windows.push_back(pw); -} - - -void -App::remove_patch_window(PatchWindow* pw) -{ - m_windows.erase(find(m_windows.begin(), m_windows.end(), pw)); -} - - -/** Returns the number of Patch windows currently visible. - */ -int -App::num_open_patch_windows() -{ - int ret = 0; - for (list::iterator i = m_windows.begin(); i != m_windows.end(); ++i) - if ((*i)->is_visible()) - ++ret; - - return ret; -} - -void -App::quit() -{ - Gtk::Main::quit(); -} - -void -App::quit_and_kill() -{ - Controller::instance().quit(); - Gtk::Main::quit(); -} - - -} // namespace OmGtk - diff --git a/src/clients/gtk/App.h b/src/clients/gtk/App.h deleted file mode 100644 index 1ba18962..00000000 --- a/src/clients/gtk/App.h +++ /dev/null @@ -1,123 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 OMGTKAPP_H -#define OMGTKAPP_H - -#include -#include -#include -#include -#include -#include -#include -#include -using std::string; using std::map; using std::list; -using std::cerr; using std::endl; - -namespace LibOmClient { class PatchModel; class PluginModel; } -using namespace LibOmClient; - -/** \defgroup OmGtk GTK Client - */ - -namespace OmGtk { - -class PatchWindow; -class GtkObjectController; -class PatchController; -class NodeController; -class PortController; -class LoadPatchWindow; -class MessagesWindow; -class ConfigWindow; -class OmGtkObject; -class OmModule; -class OmPort; -class OmFlowCanvas; -class PatchTreeView; -class PatchTreeWindow; -class ControlInterface; -class ConnectWindow; -class Configuration; - - -/** Singleton master class most everything is contained within. - * - * This is a horrible god-object, but it's shrinking in size as things are - * moved out. Hopefully it will go away entirely some day.. - * - * \ingroup OmGtk - */ -class App -{ -public: - ~App(); - - void error_message(const string& msg); - - void quit(); - void quit_and_kill(); - - void add_patch_window(PatchWindow* pw); - void remove_patch_window(PatchWindow* pw); - - int num_open_patch_windows(); - - ConnectWindow* connect_window() const { return m_connect_window; } - Gtk::Dialog* about_dialog() const { return m_about_dialog; } - ConfigWindow* configuration_dialog() const { return m_config_window; } - MessagesWindow* messages_dialog() const { return m_messages_window; } - PatchTreeWindow* patch_tree() const { return m_patch_tree_window; } - Configuration* configuration() const { return m_configuration; } - - ControlInterface* control_interface() { return m_control_interface; } - - static void instantiate() { if (!_instance) _instance = new App(); } - static inline App& instance() { assert(_instance); return *_instance; } - -protected: - App(); - static App* _instance; - - //bool connect_callback(); - //bool idle_callback(); - - ControlInterface* m_control_interface; - Configuration* m_configuration; - - list m_windows; - - ConnectWindow* m_connect_window; - MessagesWindow* m_messages_window; - PatchTreeWindow* m_patch_tree_window; - ConfigWindow* m_config_window; - Gtk::Dialog* m_about_dialog; - Gtk::Button* m_engine_error_close_button; - - /** Used to avoid feedback loops with (eg) process checkbutton - * FIXME: Maybe this should be globally implemented at the Controller level, - * disable all command sending while handling events to avoid feedback - * issues with widget event callbacks? This same pattern is duplicated - * too much... */ - bool m_enable_signal; -}; - - -} // namespace OmGtk - -#endif // OMGTKAPP_H - diff --git a/src/clients/gtk/BreadCrumb.h b/src/clients/gtk/BreadCrumb.h deleted file mode 100644 index f79ad363..00000000 --- a/src/clients/gtk/BreadCrumb.h +++ /dev/null @@ -1,66 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 BREADCRUMB_H -#define BREADCRUMB_H - -#include -#include "PatchWindow.h" -#include "PatchController.h" -#include "PatchModel.h" - -namespace OmGtk { - - -/** Breadcrumb button in a PatchWindow. - * - * \ingroup OmGtk - */ -class BreadCrumb : public Gtk::ToggleButton -{ -public: - BreadCrumb(PatchWindow* window, PatchController* patch) - : m_window(window), - m_patch(patch) - { - assert(patch != NULL); - set_border_width(0); - path(m_patch->path()); - signal_clicked().connect(sigc::bind(sigc::mem_fun( - m_window, &PatchWindow::breadcrumb_clicked), this)); - show_all(); - } - - PatchController* patch() { return m_patch; } - - void path(const Path& path) - { - remove(); - const string text = (path == "/") ? "/" : path.name(); - Gtk::Label* lab = manage(new Gtk::Label(text)); - lab->set_padding(0, 0); - lab->show(); - add(*lab); - } - -private: - PatchWindow* m_window; - PatchController* m_patch; -}; - -} // namespace OmGtk - -#endif // BREADCRUMB_H diff --git a/src/clients/gtk/ConfigWindow.cpp b/src/clients/gtk/ConfigWindow.cpp deleted file mode 100644 index db3bce18..00000000 --- a/src/clients/gtk/ConfigWindow.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "ConfigWindow.h" -#include -#include -#include -#include -#include "PatchController.h" -#include "NodeModel.h" -#include "OmFlowCanvas.h" -using std::cout; using std::cerr; using std::endl; - - -namespace OmGtk { - -ConfigWindow::ConfigWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::Window(cobject), - m_configuration(NULL) -{ - xml->get_widget("config_path_entry", m_path_entry); - xml->get_widget("config_save_button", m_save_button); - xml->get_widget("config_cancel_button", m_cancel_button); - xml->get_widget("config_ok_button", m_ok_button); - - m_save_button->signal_clicked().connect( sigc::mem_fun(this, &ConfigWindow::save_clicked)); - m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &ConfigWindow::cancel_clicked)); - m_ok_button->signal_clicked().connect( sigc::mem_fun(this, &ConfigWindow::ok_clicked)); -} - - -/** Sets the state manager for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -ConfigWindow::configuration(Configuration* sm) -{ - m_configuration = sm; - m_path_entry->set_text(sm->patch_path()); -} - - - -///// Event Handlers ////// - - -void -ConfigWindow::save_clicked() -{ - m_configuration->patch_path(m_path_entry->get_text()); - m_configuration->apply_settings(); - m_configuration->save_settings(); -} - - -void -ConfigWindow::cancel_clicked() -{ - hide(); -} - - -void -ConfigWindow::ok_clicked() -{ - m_configuration->patch_path(m_path_entry->get_text()); - m_configuration->apply_settings(); - hide(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/ConfigWindow.h b/src/clients/gtk/ConfigWindow.h deleted file mode 100644 index caf1531f..00000000 --- a/src/clients/gtk/ConfigWindow.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 CONFIGWINDOW_H -#define CONFIGWINDOW_H - -#include "PluginModel.h" -#include "Configuration.h" -#include -#include -#include -#include - -using std::list; -using LibOmClient::PluginModel; - -namespace OmGtk { - - -/** 'Configuration' window. - * - * Loaded by glade as a derived object. - * - * \ingroup OmGtk - */ -class ConfigWindow : public Gtk::Window -{ -public: - ConfigWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); - - void configuration(Configuration* sm); - -private: - void save_clicked(); - void cancel_clicked(); - void ok_clicked(); - - Configuration* m_configuration; - - Gtk::Entry* m_path_entry; - Gtk::Button* m_save_button; - Gtk::Button* m_cancel_button; - Gtk::Button* m_ok_button; -}; - - -} // namespace OmGtk - -#endif // CONFIGWINDOW_H diff --git a/src/clients/gtk/Configuration.cpp b/src/clients/gtk/Configuration.cpp deleted file mode 100644 index e4882cc3..00000000 --- a/src/clients/gtk/Configuration.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "Configuration.h" -#include -#include -#include -#include -#include -#include "PortModel.h" -#include "PluginModel.h" -#include "PatchController.h" -#include "PatchModel.h" -#include "OmFlowCanvas.h" -#include "Controller.h" - -using std::cerr; using std::cout; using std::endl; -using std::map; using std::string; -using LibOmClient::PatchModel; - -namespace OmGtk { - -using namespace LibOmClient; - - -Configuration::Configuration() -: m_patch_path("/usr/share/om/patches:/usr/local/share/om/patches"), - m_audio_port_color( 0x394f66FF), - m_control_port_color(0x396639FF), - m_midi_port_color( 0x663939FF) -{ -} - - -Configuration::~Configuration() -{ -} - - -/** Loads settings from the rc file. Passing no parameter will load from - * the default location. - */ -void -Configuration::load_settings(string filename) -{ - if (filename == "") - filename = string(getenv("HOME")).append("/.omgtkrc"); - - std::ifstream is; - is.open(filename.c_str(), std::ios::in); - - if ( ! is.good()) { - cout << "[Configuration] Unable to open settings file " << filename << endl; - return; - } else { - cout << "[Configuration] Loading settings from " << filename << endl; - } - - string s; - - is >> s; - if (s != "file_version") { - cerr << "[Configuration] Corrupt settings file, load aborted." << endl; - is.close(); - return; - } - - is >> s; - if (s != "1") { - cerr << "[Configuration] Unknown settings file version number, load aborted." << endl; - is.close(); - return; - } - - is >> s; - if (s != "patch_path") { - cerr << "[Configuration] Corrupt settings file, load aborted." << endl; - is.close(); - return; - } - - is >> s; - m_patch_path = s; - - is.close(); -} - - -/** Saves settings to rc file. Passing no parameter will save to the - * default location. - */ -void -Configuration::save_settings(string filename) -{ - if (filename == "") - filename = string(getenv("HOME")).append("/.omgtkrc"); - - std::ofstream os; - os.open(filename.c_str(), std::ios::out); - - if ( ! os.good()) { - cout << "[Configuration] Unable to write to setting file " << filename << endl; - return; - } else { - cout << "[Configuration] Saving settings to " << filename << endl; - } - - os << "file_version 1" << endl; - os << "patch_path " << m_patch_path << endl; - - os.close(); -} - - -/** Applies the current loaded settings to whichever parts of the app - * need updating. - */ -void -Configuration::apply_settings() -{ - Controller::instance().set_patch_path(m_patch_path); -} - - -int -Configuration::get_port_color(const PortModel* pi) -{ - assert(pi != NULL); - - if (pi->is_control()) { - return m_control_port_color; - } else if (pi->is_audio()) { - return m_audio_port_color; - } else if (pi->is_midi()) { - return m_midi_port_color; - } - - cerr << "[Configuration] Unknown port type! Port will be bright red, this is an error." << endl; - return 0xFF0000FF; -} - -/* -Coord -Configuration::get_window_location(const string& id) -{ - return m_window_locations[id]; -} - - -void -Configuration::set_window_location(const string& id, Coord loc) -{ - m_window_locations[id] = loc; -} - - -Coord -Configuration::get_window_size(const string& id) -{ - return m_window_sizes[id]; -} - - -void -Configuration::set_window_size(const string& id, Coord size) -{ - m_window_sizes[id] = size; -}*/ - - -} // namespace OmGtk diff --git a/src/clients/gtk/Configuration.h b/src/clients/gtk/Configuration.h deleted file mode 100644 index f0f9bef9..00000000 --- a/src/clients/gtk/Configuration.h +++ /dev/null @@ -1,76 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 CONFIG_H -#define CONFIG_H - -#include - -namespace LibOmClient { class PortModel; } -using LibOmClient::PortModel; -using std::string; - -struct Coord { double x; double y; }; - -namespace OmGtk { - -class Controller; - - -/** Singleton state manager for the entire app. - * - * Stores settings like color preferences, search paths, etc. - * (ie any user-defined preferences to be stoed in the rc file). - * - * \ingroup OmGtk - */ -class Configuration -{ -public: - Configuration(); - ~Configuration(); - - void load_settings(string filename = ""); - void save_settings(string filename = ""); - - void apply_settings(); - - string patch_path() { return m_patch_path; } - void patch_path(const string& path) { m_patch_path = path; } - - const string& patch_folder() { return m_patch_folder; } - void set_patch_folder(const string& f) { m_patch_folder = f; } - - int get_port_color(const PortModel* pi); - -private: - /** Search path for patch files. Colon delimited, as usual. */ - string m_patch_path; - - /** Most recent patch folder shown in open dialog */ - string m_patch_folder; - - int m_audio_port_color; - int m_control_port_color; - int m_midi_port_color; -}; - - -} // namespace OmGtk - -#endif // CONFIG_H - - diff --git a/src/clients/gtk/ConnectWindow.cpp b/src/clients/gtk/ConnectWindow.cpp deleted file mode 100644 index 15bab62c..00000000 --- a/src/clients/gtk/ConnectWindow.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "ConnectWindow.h" -#include -#include -#include -#include "interface/ClientKey.h" -#include "interface/ClientInterface.h" -#include "ThreadedSigClientInterface.h" -#include "Controller.h" -#include "OSCListener.h" -#include "Store.h" - -namespace OmGtk { - - -ConnectWindow::ConnectWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::Dialog(cobject) -, _client(NULL) -{ - xml->get_widget("connect_progress_bar", _progress_bar); - xml->get_widget("connect_label", _label); - xml->get_widget("connect_launch_button", _launch_button); - xml->get_widget("connect_cancel_button", _cancel_button); - - assert(_progress_bar); - assert(_label); - assert(_launch_button); - assert(_cancel_button); - - _launch_button->signal_clicked().connect(sigc::mem_fun(this, &ConnectWindow::launch_engine)); - _cancel_button->signal_clicked().connect(sigc::ptr_fun(&Gtk::Main::quit)); -} - - -void -ConnectWindow::start(CountedPtr client) -{ - _client = client; - - Glib::signal_timeout().connect( - sigc::mem_fun(this, &ConnectWindow::gtk_callback), 100); - - resize(100, 100); -} - - -void -ConnectWindow::launch_engine() -{ - if (fork() == 0) { - //cerr << "Launching engine.."; - execlp("om", NULL); - } -} - - -bool -ConnectWindow::gtk_callback() -{ - /* This isn't very nice (isn't threaded), but better than no dialog at - * all like before :) - */ - - // Timing stuff for repeated attach attempts - timeval now; - gettimeofday(&now, NULL); - static timeval last = now; - - static int stage = 0; - - /* Connecting to engine */ - if (stage == 0) { - // FIXME - //assert(!Controller::instance().is_attached()); - _label->set_text(string("Connecting to engine at ").append( - Controller::instance().engine_url()).append("...")); - present(); - Controller::instance().attach(); - ++stage; - } else if (stage == 1) { - if (Controller::instance().is_attached()) { - Controller::instance().activate(); - ++stage; - } else { - const float ms_since_last = (now.tv_sec - last.tv_sec) * 1000.0f + - (now.tv_usec - last.tv_usec) * 0.001f; - if (ms_since_last > 1000) { - Controller::instance().attach(); - last = now; - } - } - } else if (stage == 2) { - _label->set_text(string("Registering as client...")); - //Controller::instance().register_client(Controller::instance().client_hooks()); - // FIXME - //auto_ptr client(new ThreadedSigClientInterface(); - Controller::instance().register_client(ClientKey(), _client); - Controller::instance().load_plugins(); - ++stage; - } else if (stage == 3) { - // Register idle callback to process events and whatnot - // (Gtk refreshes at priority G_PRIORITY_HIGH_IDLE+20) - /*Glib::signal_timeout().connect( - sigc::mem_fun(this, &App::idle_callback), 100, G_PRIORITY_HIGH_IDLE);*/ - //Glib::signal_idle().connect(sigc::mem_fun(this, &App::idle_callback)); - /* Glib::signal_timeout().connect( - sigc::mem_fun((ThreadedSigClientInterface*)_client, &ThreadedSigClientInterface::emit_signals), - 5, G_PRIORITY_DEFAULT_IDLE);*/ - - _label->set_text(string("Requesting plugins...")); - Controller::instance().request_plugins(); - ++stage; - } else if (stage == 4) { - // Wait for first plugins message - if (Store::instance().plugins().size() > 0) { - _label->set_text(string("Receiving plugins...")); - ++stage; - } - } else if (stage == 5) { - // FIXME - /*if (Store::instance().plugins().size() < _client->num_plugins()) { - static char buf[32]; - snprintf(buf, 32, "%zu/%zu", Store::instance().plugins().size(), - ThreadedSigClientInterface::instance()->num_plugins()); - _progress_bar->set_text(Glib::ustring(buf)); - _progress_bar->set_fraction( - Store::instance().plugins().size() / (double)_client->num_plugins()); - } else {*/ - _progress_bar->set_text(""); - ++stage; - //} - } else if (stage == 6) { - _label->set_text(string("Waiting for root patch...")); - Controller::instance().request_all_objects(); - ++stage; - } else if (stage == 7) { - if (Store::instance().num_objects() > 0) - ++stage; - } else if (stage == 8) { - stage = -1; - hide(); // FIXME: actually destroy window to save mem? - } - - if (stage != 5) // yeah, ew - _progress_bar->pulse(); - - if (stage == -1) { // finished connecting - return false; // deregister this callback - } else { - return true; - } -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/ConnectWindow.h b/src/clients/gtk/ConnectWindow.h deleted file mode 100644 index 8c0c7390..00000000 --- a/src/clients/gtk/ConnectWindow.h +++ /dev/null @@ -1,61 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 CONNECT_WINDOW_H -#define CONNECT_WINDOW_H - -#include -#include -#include -#include "util/CountedPtr.h" -#include "interface/ClientInterface.h" - -namespace OmGtk { - -class App; -class Controller; - - -/** The initially visible "Connect to engine" window. - * - * This handles actually connecting to the engine and making sure everything - * is ready before really launching the app (eg wait for the root patch). - * - * \ingroup OmGtk - */ -class ConnectWindow : public Gtk::Dialog -{ -public: - ConnectWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); - - void start(CountedPtr client); - -private: - void launch_engine(); - - bool gtk_callback(); - - CountedPtr _client; - Gtk::ProgressBar* _progress_bar; - Gtk::Label* _label; - Gtk::Button* _launch_button; - Gtk::Button* _cancel_button; -}; - - -} // namespace OmGtk - -#endif // CONNECT_WINDOW_H diff --git a/src/clients/gtk/ControlGroups.cpp b/src/clients/gtk/ControlGroups.cpp deleted file mode 100644 index de87be05..00000000 --- a/src/clients/gtk/ControlGroups.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "ControlGroups.h" -#include "ControlPanel.h" -#include "PortModel.h" -#include "Controller.h" -//#include "GtkClientInterface.h" -#include -#include -using std::cerr; using std::cout; using std::endl; - -using namespace LibOmClient; - -namespace OmGtk { - -//////////////////// SliderControlGroup //////////////////////// - - -SliderControlGroup::SliderControlGroup(ControlPanel* panel, PortModel* pm, bool separator) -: ControlGroup(panel, pm, separator), - m_enabled(true), - m_enable_signal(false), - m_name_label(pm->name(), 0.0, 0.0), - m_range_box(false, 0), - m_range_label("Range: "), - m_min_spinner(1.0, (pm->is_integer() ? 0 : 4)), // climb rate, digits - m_hyphen_label(" - "), - m_max_spinner(1.0, (pm->is_integer() ? 0 : 4)), - m_slider_box(false, 0), - m_value_spinner(1.0, (pm->is_integer() ? 0 : 4)), - m_slider(pm->user_min(), pm->user_max(), (pm->is_integer() ? 1.0 : 0.0001)) -{ - m_slider.set_increments(1.0, 10.0); - - // Compensate for crazy plugins - if (m_port_model->user_max() <= m_port_model->user_min()) { - m_port_model->user_max(m_port_model->user_min() + 1.0); - m_slider.set_range(m_port_model->user_min(), m_port_model->user_max()); - } - m_slider.property_draw_value() = false; - - set_name(pm->name()); - - m_name_label.property_use_markup() = true; - m_range_label.property_use_markup() = true; - - m_value_spinner.set_range(-99999, 99999); - m_value_spinner.set_update_policy(Gtk::UPDATE_ALWAYS); // allow entered values outside range - m_value_spinner.set_value(m_port_model->value()); - m_value_spinner.set_increments(1.0, 10.0); - m_value_spinner.set_digits(5); - m_value_spinner.signal_value_changed().connect( - sigc::mem_fun(*this, &SliderControlGroup::update_value_from_spinner)); - m_min_spinner.set_range(-99999, 99999); - m_min_spinner.set_value(m_port_model->user_min()); - m_min_spinner.set_increments(1.0, 10.0); - m_min_spinner.set_digits(5); - m_min_spinner.signal_value_changed().connect(sigc::mem_fun(*this, &SliderControlGroup::min_changed)); - m_max_spinner.set_range(-99999, 99999); - m_max_spinner.set_value(m_port_model->user_max()); - m_max_spinner.set_increments(1.0, 10.0); - m_max_spinner.set_digits(5); - m_max_spinner.signal_value_changed().connect(sigc::mem_fun(*this, &SliderControlGroup::max_changed)); - - m_slider.set_value(m_port_model->value()); - - m_slider.signal_event().connect( - sigc::mem_fun(*this, &SliderControlGroup::slider_pressed)); - - m_slider.signal_value_changed().connect( - sigc::mem_fun(*this, &SliderControlGroup::update_value_from_slider)); - - m_range_box.pack_start(m_range_label, false, false, 2); - m_range_box.pack_start(m_min_spinner, false, false, 1); - m_range_box.pack_start(m_hyphen_label, false, false, 1); - m_range_box.pack_start(m_max_spinner, false, false, 1); - - m_header_box.pack_start(m_name_label, true, true, 0); - m_header_box.pack_start(m_range_box, true, true, 2); - - m_slider_box.pack_start(m_value_spinner, false, false, 1); - m_slider_box.pack_start(m_slider, true, true, 5); - - pack_start(m_header_box, false, false, 0); - pack_start(m_slider_box, false, false, 0); - - update_range(); - - m_enable_signal = true; - - show_all(); -} - - -void -SliderControlGroup::set_name(const string& name) -{ - string name_label = ""; - name_label += name + ""; - m_name_label.set_markup(name_label); -} - - -void -SliderControlGroup::set_min(float val) -{ - m_enable_signal = false; - m_min_spinner.set_value(val); - m_enable_signal = true; -} - - -void -SliderControlGroup::set_max(float val) -{ - m_enable_signal = false; - m_max_spinner.set_value(val); - m_enable_signal = true; -} - - -void -SliderControlGroup::enable() -{ - m_slider.property_sensitive() = true; - m_min_spinner.property_sensitive() = true; - m_max_spinner.property_sensitive() = true; - m_value_spinner.property_sensitive() = true; - m_name_label.property_sensitive() = true; - m_range_label.property_sensitive() = true; -} - - -void -SliderControlGroup::disable() -{ - m_slider.property_sensitive() = false; - m_min_spinner.property_sensitive() = false; - m_max_spinner.property_sensitive() = false; - m_value_spinner.property_sensitive() = false; - m_name_label.property_sensitive() = false; - m_range_label.property_sensitive() = false; -} - - -void -SliderControlGroup::min_changed() -{ - double min = m_min_spinner.get_value(); - const double max = m_max_spinner.get_value(); - - if (min >= max) { - min = max - 1.0; - m_min_spinner.set_value(min); - } - - update_range(); -} - - -void -SliderControlGroup::max_changed() -{ - const double min = m_min_spinner.get_value(); - double max = m_max_spinner.get_value(); - - if (max <= min) { - max = min + 1.0; - m_max_spinner.set_value(max); - } - - update_range(); -} - - -void -SliderControlGroup::update_range() -{ - const double min = m_min_spinner.get_value(); - const double max = m_max_spinner.get_value(); - - assert(min < max); - m_slider.set_range(min, max); - - m_port_model->user_min(min); - m_port_model->user_max(max); - - if (m_enable_signal) { - char temp_buf[16]; - snprintf(temp_buf, 16, "%f", m_port_model->user_min()); - Controller::instance().set_metadata(m_port_model->path(), "user-min", temp_buf); - snprintf(temp_buf, 16, "%f", m_port_model->user_max()); - Controller::instance().set_metadata(m_port_model->path(), "user-max", temp_buf); - } -} - - -void -SliderControlGroup::update_value_from_slider() -{ - if (m_enable_signal) { - const float value = m_slider.get_value(); - // Prevent spinner signal from doing all this over again (slow) - m_enable_signal = false; - m_value_spinner.set_value(value); - m_control_panel->value_changed(m_port_model->path(), value); - m_port_model->value(value); - m_enable_signal = true; - } -} - - -void -SliderControlGroup::update_value_from_spinner() -{ - if (m_enable_signal) { - m_enable_signal = false; - const float value = m_value_spinner.get_value(); - if (value < m_min_spinner.get_value()) - m_min_spinner.set_value(value); - if (value > m_max_spinner.get_value()) - m_max_spinner.set_value(value); - - m_enable_signal = false; - update_range(); - m_slider.set_value(m_value_spinner.get_value()); - m_enable_signal = true; - - m_control_panel->value_changed(m_port_model->path(), value); - - m_port_model->value(value); - m_enable_signal = true; - } -} - - -/** Callback for when slider is grabbed so we can ignore set_control - * events for this port (and avoid nasty feedback issues). - */ -bool -SliderControlGroup::slider_pressed(GdkEvent* ev) -{ - //cerr << "Pressed: " << ev->type << endl; - if (ev->type == GDK_BUTTON_PRESS) { - m_enabled = false; - cerr << "SLIDER FIXME\n"; - //GtkClientInterface::instance()->set_ignore_port(m_port_model->path()); - } else if (ev->type == GDK_BUTTON_RELEASE) { - m_enabled = true; - cerr << "SLIDER FIXME\n"; - //GtkClientInterface::instance()->clear_ignore_port(); - } - - return false; -} - - -/////////////// IntegerControlGroup //////////////// - - -IntegerControlGroup::IntegerControlGroup(ControlPanel* panel, PortModel* pm, bool separator) -: ControlGroup(panel, pm, separator), - m_enable_signal(false), - m_alignment(0.5, 0.5, 0.0, 0.0), - m_name_label(pm->name()), - m_spinner(1.0, 0) -{ - set_name(pm->name()); - - m_spinner.set_range(-99999, 99999); - m_spinner.set_value(m_port_model->value()); - m_spinner.signal_value_changed().connect( - sigc::mem_fun(*this, &IntegerControlGroup::update_value)); - m_spinner.set_increments(1, 10); - - m_alignment.add(m_spinner); - pack_start(m_name_label); - pack_start(m_alignment); - - m_enable_signal = true; - - show_all(); -} - - -void -IntegerControlGroup::set_name(const string& name) -{ - string name_label = ""; - name_label += name + ""; - m_name_label.set_markup(name_label); -} - - -void -IntegerControlGroup::set_value(float val) -{ - //cerr << "[IntegerControlGroup] Setting value to " << val << endl; - m_enable_signal = false; - m_spinner.set_value(val); - m_port_model->value(val); - m_enable_signal = true; -} - - -void -IntegerControlGroup::enable() -{ - m_spinner.property_sensitive() = true; - m_name_label.property_sensitive() = true; -} - - -void -IntegerControlGroup::disable() -{ - m_spinner.property_sensitive() = false; - m_name_label.property_sensitive() = false; -} - - -void -IntegerControlGroup::update_value() -{ - if (m_enable_signal) { - float value = m_spinner.get_value(); - m_control_panel->value_changed(m_port_model->path(), value); - m_port_model->value(value); - } -} - - -/////////////// ToggleControlGroup //////////////// - - -ToggleControlGroup::ToggleControlGroup(ControlPanel* panel, PortModel* pm, bool separator) -: ControlGroup(panel, pm, separator), - m_enable_signal(false), - m_alignment(0.5, 0.5, 0.0, 0.0), - m_name_label(pm->name()) -{ - set_name(pm->name()); - - set_value(m_port_model->value()); - m_checkbutton.signal_toggled().connect( - sigc::mem_fun(*this, &ToggleControlGroup::update_value)); - - m_alignment.add(m_checkbutton); - pack_start(m_name_label); - pack_start(m_alignment); - - m_enable_signal = true; - - show_all(); -} - - -void -ToggleControlGroup::set_name(const string& name) -{ - string name_label = ""; - name_label += name + ""; - m_name_label.set_markup(name_label); -} - - -void -ToggleControlGroup::set_value(float val) -{ - //cerr << "[ToggleControlGroup] Setting value to " << val << endl; - m_enable_signal = false; - m_checkbutton.set_active( (val > 0.0f) ); - m_port_model->value(val); - m_enable_signal = true; -} - - -void -ToggleControlGroup::enable() -{ - m_checkbutton.property_sensitive() = true; - m_name_label.property_sensitive() = true; -} - - -void -ToggleControlGroup::disable() -{ - m_checkbutton.property_sensitive() = false; - m_name_label.property_sensitive() = false; -} - - -void -ToggleControlGroup::update_value() -{ - if (m_enable_signal) { - float value = m_checkbutton.get_active() ? 1.0f : 0.0f; - m_control_panel->value_changed(m_port_model->path(), value); - m_port_model->value(value); - } -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/ControlGroups.h b/src/clients/gtk/ControlGroups.h deleted file mode 100644 index ab1e3413..00000000 --- a/src/clients/gtk/ControlGroups.h +++ /dev/null @@ -1,196 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 CONTROLGROUPS_H -#define CONTROLGROUPS_H - -#include -#include -#include -#include -#include "PortModel.h" - - -namespace LibOmClient { class PortModel; } -using namespace LibOmClient; - -namespace OmGtk { - -class ControlPanel; - - -/** A group of controls in a NodeControlWindow. - * - * \ingroup OmGtk - */ -class ControlGroup : public Gtk::VBox -{ -public: - ControlGroup(ControlPanel* panel, PortModel* pm, bool separator) - : Gtk::VBox(false, 0), - m_control_panel(panel), - m_port_model(pm), - m_has_separator(separator) - { - assert(m_port_model != NULL); - assert(panel != NULL); - - if (separator) { - m_separator = new Gtk::HSeparator(); - pack_start(*m_separator, false, false, 4); - } else { - m_separator = NULL; - } - } - - ~ControlGroup() { delete m_separator; } - - virtual void set_name(const string& name) {} - - virtual void set_value(float val) = 0; - - inline const PortModel* const port_model() { return m_port_model; } - - virtual void set_min(float val) {} - virtual void set_max(float val) {} - - void remove_separator() { assert(m_has_separator); - remove(*m_separator); delete m_separator; } - - virtual void enable() {} - virtual void disable() {} - -protected: - ControlPanel* m_control_panel; - PortModel* m_port_model; - bool m_has_separator; - Gtk::HSeparator* m_separator; -}; - - -/** A slider for a continuous control. - * - * \ingroup OmGtk - */ -class SliderControlGroup : public ControlGroup -{ -public: - SliderControlGroup(ControlPanel* panel, PortModel* pm, bool separator); - - void set_name(const string& name); - - inline void set_value(const float val); - void set_min(float val); - void set_max(float val); - - void enable(); - void disable(); - -private: - void min_changed(); - void max_changed(); - void update_range(); - void update_value_from_slider(); - void update_value_from_spinner(); - - //void slider_grabbed(bool b); - - bool slider_pressed(GdkEvent* ev); - - bool m_enabled; - bool m_enable_signal; - - Gtk::HBox m_header_box; - Gtk::Label m_name_label; - Gtk::HBox m_range_box; - Gtk::Label m_range_label; - Gtk::SpinButton m_min_spinner; - Gtk::Label m_hyphen_label; - Gtk::SpinButton m_max_spinner; - Gtk::HBox m_slider_box; - Gtk::SpinButton m_value_spinner; - Gtk::HScale m_slider; -}; - - -inline void -SliderControlGroup::set_value(const float val) -{ - m_enable_signal = false; - if (m_enabled) { - m_slider.set_value(val); - m_value_spinner.set_value(val); - } - m_port_model->value(val); - m_enable_signal = true; -} - - - - -/** A spinbutton for integer controls. - * - * \ingroup OmGtk - */ -class IntegerControlGroup : public ControlGroup -{ -public: - IntegerControlGroup(ControlPanel* panel, PortModel* pm, bool separator); - - void set_name(const string& name); - void set_value(float val); - - void enable(); - void disable(); - -private: - void update_value(); - - bool m_enable_signal; - Gtk::Alignment m_alignment; - Gtk::Label m_name_label; - Gtk::SpinButton m_spinner; -}; - - -/** A radio button for toggle controls. - * - * \ingroup OmGtk - */ -class ToggleControlGroup : public ControlGroup -{ -public: - ToggleControlGroup(ControlPanel* panel, PortModel* pm, bool separator); - - void set_name(const string& name); - void set_value(float val); - - void enable(); - void disable(); - -private: - void update_value(); - - bool m_enable_signal; - Gtk::Alignment m_alignment; - Gtk::Label m_name_label; - Gtk::CheckButton m_checkbutton; -}; - - -} // namespace OmGtk - -#endif // CONTROLGROUPS_H diff --git a/src/clients/gtk/ControlInterface.cpp b/src/clients/gtk/ControlInterface.cpp deleted file mode 100644 index 9ac6e07e..00000000 --- a/src/clients/gtk/ControlInterface.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 - -#include "ControlInterface.h" -#include "App.h" - -#include "PluginModel.h" -#include "PatchModel.h" -#include "NodeModel.h" -#include "PortModel.h" -#include "ConnectionModel.h" - -#include "PatchController.h" -#include "PortController.h" -#include "PatchTreeWindow.h" -#include "Store.h" - -namespace OmGtk -{ - - -void -ControlInterface::error(const string& msg) -{ - _app->error_message(msg); -} - - -void -ControlInterface::new_plugin_model(PluginModel* pm) -{ - cerr << "NEW PLUGIN\n"; - Store::instance().add_plugin(pm); -} - - -void -ControlInterface::new_patch_model(PatchModel* const pm) -{ - assert(pm); - - //cout << "[ControlInterface] New patch." << endl; - - if (Store::instance().patch(pm->path()) != NULL) { - delete pm; - } else { - - // See if we cached this patch model to store its location (to avoid the - // module "jumping") and filename (which isn't sent to engine) - /*PatchModel* pm = _controller->yank_added_patch(pm->path()); - if (pm != NULL) { - assert(pm->path() == pm->path()); - // FIXME: ew - if (pm->parent() != NULL) - pm->set_parent(NULL); - const PluginModel* plugin = pm->plugin(); - *pm = *pm; - pm->plugin(plugin); - }*/ - - assert(pm->parent() == NULL); - PatchController* patch = new PatchController(pm); - Store::instance().add_object(patch); - _app->patch_tree()->add_patch(patch); - - if (pm->path() == "/") - patch->show_patch_window(); - - //_app->add_patch(pm, show); - } -} - - -void -ControlInterface::new_node_model(NodeModel* const nm) -{ - assert(nm); - - //cerr << "[ControlInterface] New node: " << nm->name() << endl; - - PatchController* const pc = Store::instance().patch(nm->path().parent()); - - if (pc != NULL) { - /* FIXME: this is crazy slow, and slows down patch loading too much. Define some - * kind of unified string to describe all plugins (ie ladspa:amp.so:amp_gaia) and - * just store that in node models, and look it up when needed */ - - /* Bit of a hack, throw away the placeholder PluginModel in the NodeModel - * and set it to the nice complete one we have stored */ - - for (map::const_iterator i = Store::instance().plugins().begin(); - i != Store::instance().plugins().end(); ++i) { - if ((*i).second->uri() == nm->plugin()->uri()) { - // FIXME: EVIL - delete (PluginModel*)(nm->plugin()); - nm->plugin((*i).second); - break; - } - } - - pc->add_node(nm); - - } else { - cerr << "[NewNode] Can not find parent of " << nm->path() - << ". Module will not appear." << endl; - } -} - - -void -ControlInterface::new_port_model(PortModel* const pm) -{ - assert(pm); - - //cout << "[ControlInterface] New port." << endl; - - NodeController* node = Store::instance().node(pm->path().parent()); - if (node != NULL) - node->add_port(pm); - else - cerr << "[NewPort] Could not find parent for " - << pm->path() << endl; -} - - -void -ControlInterface::patch_enabled(const string& path) -{ - //cout << "[ControlInterface] Patch enabled." << endl; - - PatchController* patch = Store::instance().patch(path); - if (patch != NULL) - patch->enable(); - else - cerr << "[PatchEnabled] Cannot find patch " << path << endl; -} - - -void -ControlInterface::patch_disabled(const string& path) -{ - //cout << "[ControlInterface] Patch disabled." << endl; - - PatchController* patch = Store::instance().patch(path); - if (patch != NULL) - patch->disable(); - else - cerr << "[PatchDisabled] Cannot find patch " << path << endl; -} - - -void -ControlInterface::patch_cleared(const string& path) -{ - //cout << "[ControlInterface] Patch cleared." << endl; - - PatchController* patch = Store::instance().patch(path); - if (patch != NULL) - patch->clear(); - else - cerr << "[PatchCleared] Cannot find patch " << path << endl; -} - - -void -ControlInterface::object_destroyed(const string& path) -{ - //cout << "[ControlInterface] Destroying." << endl; - - GtkObjectController* object = Store::instance().object(path); - if (object != NULL) { - object->destroy(); - delete object; - } else { - cerr << "[Destroy] Cannot find object " << path << endl; - } -} - - -void -ControlInterface::object_renamed(const string& old_path, const string& new_path) -{ - //cout << "[ControlInterface] Renaming." << endl; - - GtkObjectController* object = Store::instance().object(old_path); - if (object != NULL) - object->set_path(new_path); - else - cerr << "[ObjectRenamed] Can not find object " << old_path - << " to rename." << endl; -} - - -void -ControlInterface::connection_model(ConnectionModel* connection) -{ - assert(connection); - - //cout << "[ControlInterface] Connection" << endl; - - assert(connection->src_port_path().parent().parent() - == connection->dst_port_path().parent().parent()); - - PatchController* pc = Store::instance().patch(connection->patch_path()); - - if (pc != NULL) - pc->connection(connection); - else - cerr << "[Connection] Can not find patch " << connection->patch_path() - << ". Connection will not be made." << endl; -} - - -void -ControlInterface::disconnection(const string& src_port_path, const string& dst_port_path) -{ - //cerr << "[ControlInterface] Disconnection." << endl; - string patch_path = src_port_path; - patch_path = patch_path.substr(0, patch_path.find_last_of("/")); - patch_path = patch_path.substr(0, patch_path.find_last_of("/")); - - if (patch_path == "") - patch_path = "/"; - - PatchController* pc = Store::instance().patch(patch_path); - - if (pc != NULL) - pc->disconnection(src_port_path, dst_port_path); - else - cerr << "[Disconnection] Can not find window for patch " << patch_path - << ". Connection will not be removed." << endl; -} - - -void -ControlInterface::metadata_update(const string& path, const string& key, const string& value) -{ - //cerr << "[ControlInterface] Metadata." << endl; - - GtkObjectController* object = Store::instance().object(path); - if (object != NULL) - object->metadata_update(key, value); - else - cerr << "[MetadataUpdate] Could not find object " << path << endl; -} - - -void -ControlInterface::control_change(const string& port_path, float value) -{ - //cerr << "[ControlInterface] Control change." << endl; - - PortController* port = Store::instance().port(port_path); - if (port != NULL) - port->control_change(value); - else - cerr << "[ControlChange] Can not find port " << port_path << endl; -} - - -void -ControlInterface::program_add(const string& path, uint32_t bank, uint32_t program, const string& name) -{ - NodeController* node = Store::instance().node(path); - if (node != NULL) { - node->program_add(bank, program, name); - return; - } else { - cerr << "[ProgramAdd] Can not find node " << path << endl; - } -} - - -void -ControlInterface::program_remove(const string& path, uint32_t bank, uint32_t program) -{ - NodeController* node = Store::instance().node(path); - if (node != NULL) { - node->program_remove(bank, program); - return; - } else { - cerr << "[ProgramRemove] Can not find node " << path << endl; - } -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/ControlInterface.h b/src/clients/gtk/ControlInterface.h deleted file mode 100644 index 8cba6a79..00000000 --- a/src/clients/gtk/ControlInterface.h +++ /dev/null @@ -1,129 +0,0 @@ -/* This file is part of Om. Copyright(C) 2006 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 CONTROLINTERFACE_H -#define CONTROLINTERFACE_H - -#include -#include "ModelClientInterface.h" -#include -#include -using std::string; - -namespace LibOmClient -{ -class PluginModel; -class PatchModel; -class NodeModel; -class PortModel; -class ConnectionModel; -} -using namespace LibOmClient; - -namespace OmGtk -{ - -class App; - - -/** Provides the public interface for controlling OmGtk(via engine events). - * - * All control of OmGtk from the engine happens through this interface. - * - * All of these functions must be called in the GTK thread. This is a unified - * interface for controlling OmGtk(eg from the engine) but it doesn't take - * care of any threading issues. - * - * \ingroup OmGtk - */ -class ControlInterface : public sigc::trackable//, public ModelClientInterface -{ -public: - - ControlInterface(App* app) - : error_slot(sigc::mem_fun(this, &ControlInterface::error)) - , new_plugin_slot(sigc::mem_fun(this, &ControlInterface::new_plugin_model)) - , new_patch_slot(sigc::mem_fun(this, &ControlInterface::new_patch_model)) - , new_node_slot(sigc::mem_fun(this, &ControlInterface::new_node_model)) - , new_port_slot(sigc::mem_fun(this, &ControlInterface::new_port_model)) - , patch_enabled_slot(sigc::mem_fun(this, &ControlInterface::patch_enabled)) - , patch_disabled_slot(sigc::mem_fun(this, &ControlInterface::patch_disabled)) - , patch_cleared_slot(sigc::mem_fun(this, &ControlInterface::patch_cleared)) - , object_destroyed_slot(sigc::mem_fun(this, &ControlInterface::object_destroyed)) - , object_renamed_slot(sigc::mem_fun(this, &ControlInterface::object_renamed)) - , connection_slot(sigc::mem_fun(this, &ControlInterface::connection_model)) - , disconnection_slot(sigc::mem_fun(this, &ControlInterface::disconnection)) - , metadata_update_slot(sigc::mem_fun(this, &ControlInterface::metadata_update)) - , control_change_slot(sigc::mem_fun(this, &ControlInterface::control_change)) - , program_add_slot(sigc::mem_fun(this, &ControlInterface::program_add)) - , program_remove_slot(sigc::mem_fun(this, &ControlInterface::program_remove)) - , _app(app) - { - assert(_app); - } - - virtual ~ControlInterface() {} - - sigc::slot bundle_begin_slot; - sigc::slot bundle_end_slot; - sigc::slot num_plugins_slot; - sigc::slot error_slot; - sigc::slot new_plugin_slot; - sigc::slot new_patch_slot; - sigc::slot new_node_slot; - sigc::slot new_port_slot; - sigc::slot patch_enabled_slot; - sigc::slot patch_disabled_slot; - sigc::slot patch_cleared_slot; - sigc::slot object_destroyed_slot; - sigc::slot object_renamed_slot; - sigc::slot connection_slot; - sigc::slot disconnection_slot; - sigc::slot metadata_update_slot; - sigc::slot control_change_slot; - sigc::slot program_add_slot; - sigc::slot program_remove_slot; - -private: - - void bundle_begin(); - void bundle_end(); - void num_plugins(uint32_t); - void error(const string&); - void new_plugin_model(PluginModel*); - void new_patch_model(PatchModel*); - void new_node_model(NodeModel*); - void new_port_model(PortModel*); - void patch_enabled(const string&); - void patch_disabled(const string&); - void patch_cleared(const string&); - void object_destroyed(const string&); - void object_renamed(const string&, const string&); - void connection_model(ConnectionModel*); - void disconnection(const string&, const string&); - void metadata_update(const string&, const string&, const string&); - void control_change(const string&, float); - void program_add(const string&, uint32_t, uint32_t, const string&); - void program_remove(const string&, uint32_t, uint32_t); - - App* _app; -}; - - -} // namespace OmGtk - -#endif // CONTROLINTERFACE_H - diff --git a/src/clients/gtk/ControlPanel.cpp b/src/clients/gtk/ControlPanel.cpp deleted file mode 100644 index f344e2c3..00000000 --- a/src/clients/gtk/ControlPanel.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 alongCont - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ControlPanel.h" -#include "PatchModel.h" -#include "NodeModel.h" -#include "PortModel.h" -#include "ControlGroups.h" -#include "PatchController.h" -#include "Controller.h" - -namespace OmGtk { - - -ControlPanel::ControlPanel(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::VBox(cobject), - m_callback_enabled(true) -{ - xml->get_widget("control_panel_controls_box", m_control_box); - xml->get_widget("control_panel_voice_controls_box", m_voice_control_box); - xml->get_widget("control_panel_all_voices_radio", m_all_voices_radio); - xml->get_widget("control_panel_specific_voice_radio", m_specific_voice_radio); - xml->get_widget("control_panel_voice_spinbutton", m_voice_spinbutton); - - m_all_voices_radio->signal_toggled().connect(sigc::mem_fun(this, &ControlPanel::all_voices_selected)); - m_specific_voice_radio->signal_toggled().connect(sigc::mem_fun(this, &ControlPanel::specific_voice_selected)); - m_voice_spinbutton->signal_value_changed().connect(sigc::mem_fun(this, &ControlPanel::voice_selected)); - - show_all(); -} - - -ControlPanel::~ControlPanel() -{ - for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) - delete (*i); -} - - -void -ControlPanel::init(NodeController* node, size_t poly) -{ - assert(node != NULL); - assert(poly > 0); - - NodeModel* const node_model = node->node_model(); - - if (poly > 1) { - m_voice_spinbutton->set_range(0, poly - 1); - } else { - remove(*m_voice_control_box); - } - - for (PortModelList::const_iterator i = node_model->ports().begin(); - i != node_model->ports().end(); ++i) { - PortController* pc = (PortController*)(*i)->controller(); - assert(pc != NULL); - add_port(pc); - } - - m_callback_enabled = true; -} - - -ControlGroup* -ControlPanel::find_port(const Path& path) const -{ - for (vector::const_iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) - if ((*cg)->port_model()->path() == path) - return (*cg); - - return NULL; -} - - -/** Add a control to the panel for the given port. - */ -void -ControlPanel::add_port(PortController* port) -{ - assert(port != NULL); - assert(port->model() != NULL); - assert(port->control_panel() == NULL); - - PortModel* const pm = port->port_model(); - - // Already have port, don't add another - if (find_port(pm->path()) != NULL) - return; - - // Add port - if (pm->is_control() && pm->is_input()) { - bool separator = (m_controls.size() > 0); - ControlGroup* cg = NULL; - if (pm->is_integer()) - cg = new IntegerControlGroup(this, pm, separator); - else if (pm->is_toggle()) - cg = new ToggleControlGroup(this, pm, separator); - else - cg = new SliderControlGroup(this, pm, separator); - - m_controls.push_back(cg); - m_control_box->pack_start(*cg, false, false, 0); - - if (pm->connected()) - cg->disable(); - else - cg->enable(); - } - - port->set_control_panel(this); - - Gtk::Requisition controls_size; - m_control_box->size_request(controls_size); - m_ideal_size.first = controls_size.width; - m_ideal_size.second = controls_size.height; - - Gtk::Requisition voice_size; - m_voice_control_box->size_request(voice_size); - m_ideal_size.first += voice_size.width; - m_ideal_size.second += voice_size.height; - - //cerr << "Setting ideal size to " << m_ideal_size.first - // << " x " << m_ideal_size.second << endl; -} - - -/** Remove the control for the given port. - */ -void -ControlPanel::remove_port(const Path& path) -{ - bool was_first = false; - for (vector::iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) { - if ((*cg)->port_model()->path() == path) { - m_control_box->remove(**cg); - if (cg == m_controls.begin()) - was_first = true; - m_controls.erase(cg); - break; - } - } - - if (was_first && m_controls.size() > 0) - (*m_controls.begin())->remove_separator(); -} - - -/** Rename the control for the given port. - */ -void -ControlPanel::rename_port(const Path& old_path, const Path& new_path) -{ - for (vector::iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) { - if ((*cg)->port_model()->path() == old_path) { - (*cg)->set_name(new_path.name()); - return; - } - } -} - - -/** Enable the control for the given port. - * - * Used when all connections to port are un-made. - */ -void -ControlPanel::enable_port(const Path& path) -{ - for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { - if ((*i)->port_model()->path() == path) { - (*i)->enable(); - return; - } - } -} - - -/** Disable the control for the given port. - * - * Used when port is connected. - */ -void -ControlPanel::disable_port(const Path& path) -{ - for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { - if ((*i)->port_model()->path() == path) { - (*i)->disable(); - return; - } - } -} - - -/** Callback for ControlGroups to notify this of a change. - */ -void -ControlPanel::value_changed(const Path& port_path, float val) -{ - if (m_callback_enabled) { - // Update patch control slider, if this is a control panel for a patch - // (or vice versa) - //if (m_mirror != NULL) - // m_mirror->set_port_value(port_path, val); - - if (m_all_voices_radio->get_active()) { - Controller::instance().set_port_value(port_path, val); - } else { - int voice = m_voice_spinbutton->get_value_as_int(); - Controller::instance().set_port_value(port_path, voice, val); - } - } -} - - -void -ControlPanel::set_range_min(const Path& port_path, float val) -{ - bool found = false; - for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { - if ((*i)->port_model()->path() == port_path) { - found = true; - (*i)->set_min(val); - } - } - if (found == false) - cerr << "[ControlPanel::set_range_min] Unable to find control " << port_path << endl; -} - - -void -ControlPanel::set_range_max(const Path& port_path, float val) -{ - bool found = false; - for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { - if ((*i)->port_model()->path() == port_path) { - found = true; - (*i)->set_max(val); - } - } - if (found == false) - cerr << "[ControlPanel::set_range_max] Unable to find control " << port_path << endl; -} - - -void -ControlPanel::all_voices_selected() -{ - m_voice_spinbutton->property_sensitive() = false; -} - - -void -ControlPanel::specific_voice_selected() -{ - m_voice_spinbutton->property_sensitive() = true; -} - - -void -ControlPanel::voice_selected() -{ -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/ControlPanel.h b/src/clients/gtk/ControlPanel.h deleted file mode 100644 index 1f24344f..00000000 --- a/src/clients/gtk/ControlPanel.h +++ /dev/null @@ -1,129 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 CONTROLPANEL_H -#define CONTROLPANEL_H - -#include -#include -#include -#include -#include -#include -#include -#include // for pair<> -#include "ControlGroups.h" -#include "util/Path.h" -#include "PortController.h" - -using std::vector; using std::string; using std::pair; -using std::cerr; using std::cout; using std::endl; - -namespace LibOmClient { -class PortModel; -class NodeModel; -} -using namespace LibOmClient; -using Om::Path; - -namespace OmGtk { - -class NodeController; -class PortController; - - -/** A group of controls for a node (or patch). - * - * Used by both NodeControlWindow and the main window (for patch controls). - * - * \ingroup OmGtk - */ -class ControlPanel : public Gtk::VBox { -public: - ControlPanel(BaseObjectType* cobject, const Glib::RefPtr& glade_xml); - virtual ~ControlPanel(); - - void init(NodeController* node, size_t poly); - - ControlGroup* find_port(const Path& path) const; - - void add_port(PortController* port); - void remove_port(const Path& path); - - void rename_port(const Path& old_path, const Path& new_path); - - void enable_port(const Path& path); - void disable_port(const Path& path); - - size_t num_controls() const { return m_controls.size(); } - pair ideal_size() const { return m_ideal_size; } - - // Callback for ControlGroup - void value_changed(const Path& port_path, float val); - - inline void set_control(const Path& port_path, float value); - void set_range_min(const Path& port_path, float value); - void set_range_max(const Path& port_path, float value); - -private: - void all_voices_selected(); - void specific_voice_selected(); - void voice_selected(); - - bool m_callback_enabled; - - pair m_ideal_size; - - vector m_controls; - Gtk::VBox* m_control_box; - Gtk::Box* m_voice_control_box; - Gtk::RadioButton* m_all_voices_radio; - Gtk::RadioButton* m_specific_voice_radio; - Gtk::SpinButton* m_voice_spinbutton; -}; - - -/** Set a port on this panel to a certain value. - * - * Profiling has shown this is performance critical. Needs to be made - * faster. - */ -inline void -ControlPanel::set_control(const Path& port_path, const float val) -{ - // FIXME: double lookup, ports should just have a pointer directly to - // their control group - - m_callback_enabled = false; - ControlGroup* cg = NULL; - - for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { - cg = (*i); - if (cg->port_model()->path() == port_path) { - cg->set_value(val); - m_callback_enabled = true; - return; - } - } - - cerr << "[ControlPanel::set_control] Unable to find control " << port_path << endl; - m_callback_enabled = true; -} - - -} // namespace OmGtk - -#endif // CONTROLPANEL_H diff --git a/src/clients/gtk/Controller.cpp b/src/clients/gtk/Controller.cpp deleted file mode 100644 index 05ebe84a..00000000 --- a/src/clients/gtk/Controller.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "PatchModel.h" -#include "PatchController.h" -#include "ControlInterface.h" -#include "OSCModelEngineInterface.h" -#include "OSCListener.h" -//#include "GtkClientInterface.h" -#include "PatchLibrarian.h" -#include "Controller.h" -#include "Loader.h" -#include "interface/ClientKey.h" - -namespace OmGtk { - - -Controller::Controller(const string& engine_url) -: OSCModelEngineInterface(engine_url), - m_patch_librarian(new PatchLibrarian(this)), - m_loader(new Loader(m_patch_librarian)) -{ - m_loader->launch(); -} - - -Controller::~Controller() -{ - if (is_attached()) { - unregister_client(ClientKey()); // FIXME - detach(); - } - - delete m_loader; - delete m_patch_librarian; -} - - -/** "Attach" to the Om engine. - * See documentation OSCModelEngineInterface::attach. - */ -void -Controller::attach() -{ - OSCModelEngineInterface::attach(false); -} - -/* -void -Controller::register_client_and_wait() -{ -// int id = get_next_request_id(); -// set_wait_response_id(id); - OSCModelEngineInterface::register_client(); -// wait_for_response(); - cout << "[Controller] Registered with engine. maybe. fixme." << endl; -} -*/ -void Controller::set_engine_url(const string& url) { _engine_url = url; } - -void -Controller::create_node_from_model(const NodeModel* nm) -{ - //push_added_node(nm); - OSCModelEngineInterface::create_node_from_model(nm); - char temp_buf[16]; - snprintf(temp_buf, 16, "%f", nm->x()); - set_metadata(nm->path(), "module-x", temp_buf); - snprintf(temp_buf, 16, "%f", nm->y()); - set_metadata(nm->path(), "module-y", temp_buf); -} - -void -Controller::create_patch_from_model(const PatchModel* pm) -{ - //push_added_patch(pm); - - //int id = get_next_request_id(); - //set_wait_response_id(id); - create_patch_from_model(pm); - if (pm->parent() != NULL) { - // wait_for_response(); - char temp_buf[16]; - snprintf(temp_buf, 16, "%f", pm->x()); - set_metadata(pm->path(), "module-x", temp_buf); - snprintf(temp_buf, 16, "%f", pm->y()); - set_metadata(pm->path(), "module-y", temp_buf); - } - enable_patch(pm->path()); -} - - -void -Controller::set_patch_path(const string& path) -{ - m_patch_librarian->path(path); -} - - -/** Load patch in a seperate thread. - * This will return immediately and the patch will be loaded in the background. - * FIXME: merge parameter makes no sense, always true */ -void -Controller::load_patch(PatchModel* model, bool wait, bool merge) -{ - //push_added_patch(model); - m_loader->load_patch(model, wait, merge); -} - - -/** Load patch in a seperate thread. - * This will return immediately and the patch will be saved in the background. */ -void -Controller::save_patch(PatchModel* model, const string& filename, bool recursive) -{ - m_loader->save_patch(model, filename, recursive); -} - - -#if 0 -/** Returns the added node with the given path and removes it from the cache. - */ -NodeModel* -Controller::yank_added_node(const string& path) -{ - NodeModel* nm = NULL; - - for (list::iterator i = m_added_nodes.begin(); i != m_added_nodes.end(); ++i) { - if ((*i)->path() == path) { - nm = *i; - m_added_nodes.erase(i); - break; - } - } - - return nm; -} - - -/** Returns the added patch with the given path and removes it from the cache. - */ -PatchModel* -Controller::yank_added_patch(const string& path) -{ - PatchModel* pm = NULL; - - for (list::iterator i = m_added_patches.begin(); i != m_added_patches.end(); ++i) { - if ((*i)->path() == path) { - pm = *i; - m_added_patches.erase(i); - break; - } - } - - return pm; -} -#endif - -} // namespace OmGtk - diff --git a/src/clients/gtk/Controller.h b/src/clients/gtk/Controller.h deleted file mode 100644 index fd516992..00000000 --- a/src/clients/gtk/Controller.h +++ /dev/null @@ -1,112 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 CONTROLLER_H -#define CONTROLLER_H - -#include -#include -#include -#include -#include "PluginModel.h" -#include "OSCModelEngineInterface.h" - -namespace LibOmClient { -class PatchModel; -class NodeModel; -class PatchLibrarian; -} - -using std::string; using std::list; -using namespace LibOmClient; - -namespace OmGtk { - -class PatchController; -//class GtkClientInterface; -class Loader; - - -/** Singleton engine controller for the entire app. - * - * This is hardly more than a trivial wrapper for OSCModelEngineInterface, suggesting something - * needs a rethink around here.. - * - * This needs to be either eliminated or the name changed to OmController. Probably - * best to keep around in case multiple engine control support comes around? - * - * \ingroup OmGtk - */ -class Controller : public OSCModelEngineInterface -{ -public: - ~Controller(); - - void attach(); - - //void register_client_and_wait(); - - void set_engine_url(const string& url); - - void create_node_from_model(const NodeModel* nm); - - void load_patch(PatchModel* model, bool wait = true, bool merge = false); - void save_patch(PatchModel* model, const string& filename, bool recursive); - - void create_patch_from_model(const PatchModel* pm); - - //void lash_restore_finished(); - - void set_patch_path(const string& path); - - /* - void push_added_node(NodeModel* nm) { m_added_nodes.push_back(nm); } - NodeModel* yank_added_node(const string& path); - - void push_added_patch(PatchModel* pm) { m_added_patches.push_back(pm); } - PatchModel* yank_added_patch(const string& path); - */ - //GtkClientInterface* client_hooks() { return (GtkClientInterface*)m_client_hooks; } - - static void instantiate(const string& engine_url) - { if (!_instance) _instance = new Controller(engine_url); } - - inline static Controller& instance() { assert(_instance); return *_instance; } - -private: - Controller(const string& engine_url); - static Controller* _instance; - - PatchLibrarian* m_patch_librarian; - Loader* m_loader; - - /** Used to cache added nodes so client can remember some values when the - * new node notification comes (location, etc). Used to prevent the node - * jumping locations during the delay between new node and the module-x/y - * metadata notifications */ - //list m_added_nodes; - - /** Used to cache added patches in the same was as m_added_nodes. Used to - * rember filename so File->Save can work without prompting (filename can't - * be sent to the server as metadata, because a client on another machine - * doesn't want that information) */ - //list m_added_patches; -}; - - -} // namespace OmGtk - -#endif // CONTROLLER_H diff --git a/src/clients/gtk/DSSIController.cpp b/src/clients/gtk/DSSIController.cpp deleted file mode 100644 index 570211c7..00000000 --- a/src/clients/gtk/DSSIController.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "DSSIController.h" -#include -#include -#include -#include -#include -#include "NodeModel.h" -#include "DSSIModule.h" -#include "Controller.h" - -namespace OmGtk { - - -DSSIController::DSSIController(NodeModel* model) -: NodeController(model), - m_banks_dirty(true) -{ - assert(model->plugin()->type() == PluginModel::DSSI); - Gtk::Menu::MenuList& items = m_menu.items(); - items[0].property_sensitive() = true; // "Show Control Window" item - - Gtk::Menu_Helpers::MenuElem program_elem("Select Program", m_program_menu); - items.push_front(program_elem); - m_program_menu_item = program_elem.get_child(); - m_program_menu_item->set_sensitive(false); - - items.push_front(Gtk::Menu_Helpers::MenuElem("Show Plugin GUI", - sigc::mem_fun(this, &DSSIController::show_gui))); -} - -void -DSSIController::program_add(int bank, int program, const string& name) -{ - node_model()->add_program(bank, program, name); - m_banks_dirty = true; -} - - -void -DSSIController::program_remove(int bank, int program) -{ - node_model()->remove_program(bank, program); - m_banks_dirty = true; -} - -/** Trivial wrapper of attempt_to_show_gui for libsigc - */ -void -DSSIController::show_gui() -{ - attempt_to_show_gui(); -} - - -void -DSSIController::update_program_menu() -{ - m_program_menu.items().clear(); - - const map >& banks = node_model()->get_programs(); - std::ostringstream oss; - - map >::const_iterator i; - for (i = banks.begin(); i != banks.end(); ++i) { - Gtk::Menu* bank_menu; - if (banks.size() > 1) - bank_menu = manage(new Gtk::Menu()); - else - bank_menu = &m_program_menu; - map::const_iterator j; - for (j = i->second.begin(); j != i->second.end(); ++j) { - oss.str(""); - oss << std::setw(3) << std::setfill('0') - << j->first << ' ' << j->second; - sigc::slot slt = bind( - bind(sigc::mem_fun(*this, &DSSIController::send_program_change), - j->first), i->first); - bank_menu->items().push_back( - Gtk::Menu_Helpers::MenuElem(oss.str(), slt)); - } - if (banks.size() > 1) { - oss.str(""); - oss << "Bank " << i->first; - m_program_menu.items().push_back( - Gtk::Menu_Helpers::MenuElem(oss.str(), *bank_menu)); - } - } - - // Disable the program menu if there are no programs - if (banks.size() == 0) - m_program_menu_item->set_sensitive(false); - else - m_program_menu_item->set_sensitive(true); - - m_banks_dirty = false; -} - - -void -DSSIController::send_program_change(int bank, int program) -{ - Controller::instance().set_program(node_model()->path(), bank, program); -} - - -void -DSSIController::create_module(OmFlowCanvas* canvas) -{ - //cerr << "Creating DSSI module " << m_model->path() << endl; - - assert(canvas != NULL); - assert(m_module == NULL); - - m_module = new DSSIModule(canvas, this); - create_all_ports(); - - m_module->move_to(node_model()->x(), node_model()->y()); -} - - - -/** Attempt to show the DSSI GUI for this plugin. - * - * Returns whether or not GUI was successfully loaded/shown. - */ -bool -DSSIController::attempt_to_show_gui() -{ - // Shamelessley "inspired by" jack-dssi-host - // Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. - - const bool verbose = false; - - string engine_url = Controller::instance().engine_url(); - // Hack off last character if it's a / - if (engine_url[engine_url.length()-1] == '/') - engine_url = engine_url.substr(0, engine_url.length()-1); - - const char* dllName = node_model()->plugin()->lib_name().c_str(); - const char* label = node_model()->plugin()->plug_label().c_str(); - const char* myName = "om_gtk"; - const string& oscUrl = engine_url + "/dssi" + node_model()->path(); - - struct dirent* entry = NULL; - char* dllBase = strdup(dllName); - char* subpath = NULL; - DIR* subdir = NULL; - char* filename = NULL; - struct stat buf; - int fuzzy = 0; - - char* env_dssi_path = getenv("DSSI_PATH"); - string dssi_path; - if (!env_dssi_path) { - cerr << "DSSI_PATH is empty. Assuming /usr/lib/dssi:/usr/local/lib/dssi." << endl; - dssi_path = "/usr/lib/dssi:/usr/local/lib/dssi"; - } else { - dssi_path = env_dssi_path; - } - - if (strlen(dllBase) > 3 && !strcasecmp(dllBase + strlen(dllBase) - 3, ".so")) { - dllBase[strlen(dllBase) - 3] = '\0'; - } - - - // This is pretty nasty, it loops through the path, even if the dllBase is absolute - while (dssi_path != "") { - string directory = dssi_path.substr(0, dssi_path.find(':')); - if (dssi_path.find(':') != string::npos) - dssi_path = dssi_path.substr(dssi_path.find(':')+1); - else - dssi_path = ""; - - if (*dllBase == '/') { - subpath = strdup(dllBase); - } else { - subpath = (char*)malloc(strlen(directory.c_str()) + strlen(dllBase) + 2); - sprintf(subpath, "%s/%s", directory.c_str(), dllBase); - } - - for (fuzzy = 0; fuzzy <= 1; ++fuzzy) { - - if (!(subdir = opendir(subpath))) { - if (verbose) { - fprintf(stderr, "%s: can't open plugin GUI directory \"%s\"\n", myName, subpath); - } - break; - } - - while ((entry = readdir(subdir))) { - - if (entry->d_name[0] == '.') - continue; - if (!strchr(entry->d_name, '_')) - continue; - - if (fuzzy) { - if (verbose) { - fprintf(stderr, "checking %s against %s\n", entry->d_name, dllBase); - } - if (strncmp(entry->d_name, dllBase, strlen(dllBase))) - continue; - } else { - if (verbose) { - fprintf(stderr, "checking %s against %s\n", entry->d_name, label); - } - if (strncmp(entry->d_name, label, strlen(label))) - continue; - } - - filename = (char*)malloc(strlen(subpath) + strlen(entry->d_name) + 2); - sprintf(filename, "%s/%s", subpath, entry->d_name); - - if (stat(filename, &buf)) { - perror("stat failed"); - free(filename); - continue; - } - - if ((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) && - (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { - - if (verbose) { - fprintf(stderr, "%s: trying to execute GUI at \"%s\"\n", - myName, filename); - } - - if (fork() == 0) { - execlp(filename, filename, oscUrl.c_str(), dllName, label, - node_model()->name().c_str(), 0); - perror("exec failed"); - exit(1); - } - - free(filename); - free(subpath); - free(dllBase); - return true; - } - - free(filename); - } - } - } - - cerr << "Unable to launch DSSI GUI for " << node_model()->path() << endl; - - free(subpath); - free(dllBase); - return false; -} - - -void -DSSIController::show_menu(GdkEventButton* event) -{ - if (m_banks_dirty) - update_program_menu(); - NodeController::show_menu(event); -} - - -} // namespace OmGtk - diff --git a/src/clients/gtk/DSSIController.h b/src/clients/gtk/DSSIController.h deleted file mode 100644 index 53f6fc8b..00000000 --- a/src/clients/gtk/DSSIController.h +++ /dev/null @@ -1,79 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 DSSICONTROLLER_H -#define DSSICONTROLLER_H - -#include -#include -#include "util/Path.h" -#include "NodeController.h" - -using std::string; -using Om::Path; -using namespace LibOmClient; - -namespace LibOmClient { - class MetadataModel; - class NodeModel; - class PortModel; -} - -namespace OmGtk { - -class Controller; -class OmModule; -class NodeControlWindow; -class NodePropertiesWindow; -class PortController; -class OmFlowCanvas; -class DSSIModule; - -/* Controller for a DSSI node. - * - * \ingroup OmGtk - */ -class DSSIController : public NodeController -{ -public: - DSSIController(NodeModel* model); - - virtual ~DSSIController() {} - - void show_gui(); - bool attempt_to_show_gui(); - void program_add(int bank, int program, const string& name); - void program_remove(int bank, int program); - - void send_program_change(int bank, int program); - - void create_module(OmFlowCanvas* canvas); - - void show_menu(GdkEventButton* event); - -private: - void update_program_menu(); - - Gtk::Menu m_program_menu; - Glib::RefPtr m_program_menu_item; - - bool m_banks_dirty; -}; - - -} // namespace OmGtk - -#endif // DSSICONTROLLER_H diff --git a/src/clients/gtk/DSSIModule.cpp b/src/clients/gtk/DSSIModule.cpp deleted file mode 100644 index 7dae48ac..00000000 --- a/src/clients/gtk/DSSIModule.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "DSSIModule.h" -#include "DSSIController.h" - -namespace OmGtk { - - -DSSIModule::DSSIModule(OmFlowCanvas* canvas, DSSIController* node) -: OmModule(canvas, static_cast(node)) -{ -} - - -void -DSSIModule::on_double_click(GdkEventButton* ev) -{ - DSSIController* const dc = static_cast(m_node); - if (!dc->attempt_to_show_gui()) - show_control_window(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/DSSIModule.h b/src/clients/gtk/DSSIModule.h deleted file mode 100644 index 2ad10c04..00000000 --- a/src/clients/gtk/DSSIModule.h +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 DSSIMODULE_H -#define DSSIMODULE_H - -#include "OmModule.h" - -namespace OmGtk { - -class DSSIController; - -/* Module for a DSSI node. - * - * \ingroup OmGtk - */ -class DSSIModule : public OmModule -{ -public: - DSSIModule(OmFlowCanvas* canvas, DSSIController* node); - virtual ~DSSIModule() {} - - void on_double_click(GdkEventButton* ev); -}; - - -} // namespace OmGtk - -#endif // DSSIMODULE_H - diff --git a/src/clients/gtk/GladeFactory.cpp b/src/clients/gtk/GladeFactory.cpp deleted file mode 100644 index e930c4c4..00000000 --- a/src/clients/gtk/GladeFactory.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "GladeFactory.h" -#include -#include -using std::cout; using std::cerr; using std::endl; -using std::ifstream; - -namespace OmGtk { - - -Glib::ustring GladeFactory::glade_filename = ""; - - -void -GladeFactory::find_glade_file() -{ - // Check for the .glade file in current directory - glade_filename = "./om_gtk.glade"; - ifstream fs(glade_filename.c_str()); - if (fs.fail()) { // didn't find it, check PKGDATADIR - fs.clear(); - glade_filename = PKGDATADIR; - glade_filename += "/om_gtk.glade"; - - fs.open(glade_filename.c_str()); - if (fs.fail()) { - cerr << "[GladeFactory] Unable to find om_gtk.glade in current directory or " << PKGDATADIR << "." << endl; - throw; - } - fs.close(); - } - cerr << "[GladeFactory] Loading widgets from " << glade_filename.c_str() << endl; -} - - -Glib::RefPtr -GladeFactory::new_glade_reference(const string& toplevel_widget) -{ - if (glade_filename == "") - find_glade_file(); - - try { - if (toplevel_widget == "") - return Gnome::Glade::Xml::create(glade_filename); - else - return Gnome::Glade::Xml::create(glade_filename, toplevel_widget.c_str()); - } catch (const Gnome::Glade::XmlError& ex) { - cerr << ex.what() << endl; - throw ex; - } -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/GladeFactory.h b/src/clients/gtk/GladeFactory.h deleted file mode 100644 index a3ee1022..00000000 --- a/src/clients/gtk/GladeFactory.h +++ /dev/null @@ -1,48 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 GLADEFACTORY_H -#define GLADEFACTORY_H - -#include -#include - -using std::string; - -namespace OmGtk { - - -/** Creates glade references, so various objects can create widgets. - * Purely static. - * - * \ingroup OmGtk - */ -class GladeFactory { -public: - static Glib::RefPtr - new_glade_reference(const string& toplevel_widget = ""); - -private: - GladeFactory() {} - - static void find_glade_file(); - static Glib::ustring glade_filename; -}; - - -} // namespace OmGtk - -#endif // GLADEFACTORY_H diff --git a/src/clients/gtk/GtkClientInterface.cpp b/src/clients/gtk/GtkClientInterface.cpp deleted file mode 100644 index 7bda1e9e..00000000 --- a/src/clients/gtk/GtkClientInterface.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "GtkClientInterface.h" -#include -#include -#include -#include -#include -#include "ControlInterface.h" - -namespace OmGtk { - - -GtkClientInterface::GtkClientInterface(ControlInterface* interface, int client_port) -: OSCListener(client_port) -, ModelClientInterface() -, _interface(interface) -, _num_plugins(0) -, _events(4096) -{ -} - - -/** Push an event (from the engine, ie 'new patch') on to the queue. - */ -void -GtkClientInterface::push_event(Closure ev) -{ - bool success = false; - bool first = true; - - // (Very) slow busy-wait if the queue is full - // FIXME: Make this wait on a signal from process_events iff this happens - while (!success) { - success = _events.push(ev); - if (!success) { - if (first) { - cerr << "[GtkClientInterface] WARNING: (Client) event queue full. Waiting to try again..." << endl; - first = false; - } - usleep(200000); // 100 milliseconds (2* rate process_events is called) - } - } -} - - -/** Process all queued events that came from the OSC thread. - * - * This function is to be called from the Gtk thread only. - */ -bool -GtkClientInterface::process_events() -{ - // Process a maximum of queue-size events, to prevent locking the GTK - // thread indefinitely while processing continually arriving events - size_t num_processed = 0; - while (!_events.is_empty() && num_processed++ < _events.capacity()/2) { - Closure& ev = _events.pop(); - ev(); - ev.disconnect(); - } - - return true; -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/GtkClientInterface.h b/src/clients/gtk/GtkClientInterface.h deleted file mode 100644 index 7214ef19..00000000 --- a/src/clients/gtk/GtkClientInterface.h +++ /dev/null @@ -1,156 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 GTKCLIENTHOOKS_H -#define GTKCLIENTHOOKS_H - -#include -#include -#include -#include -#include -#include "ControlInterface.h" -#include "OSCListener.h" -#include "util/Queue.h" -#include "util/CountedPtr.h" -#include "ModelClientInterface.h" -#include "SigClientInterface.h" -using std::string; -using std::cerr; using std::endl; - -namespace LibOmClient { class PluginModel; } -using namespace LibOmClient; - -namespace OmGtk { - -/** Returns nothing and takes no parameters (because they have been bound) */ -typedef sigc::slot Closure; - -#if 0 -/** ModelClientInterface implementation for the Gtk client. - * - * This is a threadsafe interface to OmGtk. It provides the same interface as - * @ref ControlInterface, except all public functions may be called in a thread - * other than the GTK thread (a closure will be created and pushed through a - * queue for the GTK thread to execute). - * - * It is also a ModelClientInterface, which is how it is driven by the engine. - * This is redundant, "ControlInterface" needs to go away. A model database - * that wraps a ClientInterface and emits sigc signals when things change would - * be a much better way of doing this. - * - * \ingroup OmGtk - */ -class GtkClientInterface : public OSCListener, public ModelClientInterface -{ -public: - GtkClientInterface(ControlInterface* interface, int client_port); - - void set_ignore_port(const string& path) { _ignore_port_path = path; } - void clear_ignore_port() { _ignore_port_path = ""; } - - // FIXME: ugly accessor - size_t num_plugins() const { return _num_plugins; } - - // OSC thread functions (deferred calls) - - void bundle_begin() {} - void bundle_end() {} - - void num_plugins(size_t num) { _num_plugins = num; } - - void error(const string& msg) - { push_event(sigc::bind(_interface->error_slot, msg)); } - - void new_plugin_model(PluginModel* const pm) - { push_event(sigc::bind(_interface->new_plugin_slot, pm)); } - - void new_patch_model(PatchModel* const pm) - { push_event(sigc::bind(_interface->new_patch_slot, pm)); } - - void new_node_model(NodeModel* const nm) - { assert(nm); push_event(sigc::bind(_interface->new_node_slot, nm)); } - - void new_port_model(PortModel* const pm) - { push_event(sigc::bind(_interface->new_port_slot, pm)); } - - void connection_model(ConnectionModel* const cm) - { push_event(sigc::bind(_interface->connection_slot, cm)); } - - void object_destroyed(const string& path) - { push_event(sigc::bind(_interface->object_destroyed_slot, path)); } - - void patch_enabled(const string& path) - { push_event(sigc::bind(_interface->patch_enabled_slot, path)); } - - void patch_disabled(const string& path) - { push_event(sigc::bind(_interface->patch_disabled_slot, path)); } - - void patch_cleared(const string& path) - { push_event(sigc::bind(_interface->patch_cleared_slot, path)); } - - void object_renamed(const string& old_path, const string& new_path) - { push_event(sigc::bind(_interface->object_renamed_slot, old_path, new_path)); } - - void disconnection(const string& src_port_path, const string& dst_port_path) - { push_event(sigc::bind(_interface->disconnection_slot, src_port_path, dst_port_path)); } - - void metadata_update(const string& path, const string& key, const string& value) - { push_event(sigc::bind(_interface->metadata_update_slot, path, key, value)); } - - void control_change(const string& port_path, float value) - { push_event(sigc::bind(_interface->control_change_slot, port_path, value)); } - - void program_add(const string& path, uint32_t bank, uint32_t program, const string& name) - { push_event(sigc::bind(_interface->program_add_slot, path, bank, program, name)); } - - void program_remove(const string& path, uint32_t bank, uint32_t program) - { push_event(sigc::bind(_interface->program_remove_slot, path, bank, program)); } - - /** Process all queued events - MUST be called from Gtk thread. - * Registered as a GTK idle handler by App. */ - bool process_events(); - - static void instantiate(ControlInterface* interface, int client_port) - { if (!_instance) _instance = new GtkClientInterface(interface, client_port); } - - inline static CountedPtr instance() - { assert(_instance); return _instance; } - -private: - - static CountedPtr _instance; - - /** Provides the functions/slots the closures will actually call in the GTK thread */ - ControlInterface* _interface; - - size_t _num_plugins; - - void push_event(Closure ev); - - /** Set if a port slider is grabbed and is being dragged. - * If a control event comes in for a port with this path, we'll just - * ignore it outright. (Just an optimization over doing all the searching - * for the port slider just to ignore the event) */ - string _ignore_port_path; - - Queue _events; -}; -#endif - -} // namespace OmGtk - -#endif // GTKCLIENTHOOKS_H diff --git a/src/clients/gtk/GtkObjectController.cpp b/src/clients/gtk/GtkObjectController.cpp deleted file mode 100644 index 7277d346..00000000 --- a/src/clients/gtk/GtkObjectController.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "GtkObjectController.h" - -namespace OmGtk { - - -GtkObjectController::GtkObjectController(ObjectModel* model) -: m_model(model) -{ - assert(m_model != NULL); -} - - -/** Derived classes should override this to handle special metadata - * keys, then call this to set the model's metadata key. - */ -void -GtkObjectController::metadata_update(const string& key, const string& value) -{ - m_model->set_metadata(key, value); -} - - -} // namespace OmGtk - diff --git a/src/clients/gtk/GtkObjectController.h b/src/clients/gtk/GtkObjectController.h deleted file mode 100644 index 4a09b9c7..00000000 --- a/src/clients/gtk/GtkObjectController.h +++ /dev/null @@ -1,77 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 GTKOBJECTCONTROLLER_H -#define GTKOBJECTCONTROLLER_H - -#include -#include - -#include "ObjectModel.h" -#include "ObjectController.h" - - -using std::string; - -using namespace LibOmClient; - -namespace OmGtk { - -class Controller; - - -/** Controller for an Om object. - * - * Management of the model and view are this object's responsibility. - * The view may not be created (ie in the case of patches which have never - * been shown and all their children). - * - * \ingroup OmGtk - */ -class GtkObjectController : public LibOmClient::ObjectController -{ -public: - GtkObjectController(ObjectModel* model); - virtual ~GtkObjectController() {} - - /** Destroy object. - * - * Object must be safe to delete immediately following the return of - * this call. - */ - virtual void destroy() = 0; - - virtual void add_to_store() = 0; - virtual void remove_from_store() = 0; - - virtual void metadata_update(const string& key, const string& value); - - /** Rename object */ - virtual void set_path(const Path& new_path) - { m_model->set_path(new_path); } - - const Path& path() const { return m_model->path(); } - - ObjectModel* model() const { return m_model; } - -protected: - ObjectModel* m_model; ///< Model for this object -}; - - -} // namespace OmGtk - -#endif // GTKOBJECTCONTROLLER_H diff --git a/src/clients/gtk/LashController.cpp b/src/clients/gtk/LashController.cpp deleted file mode 100644 index d95d8515..00000000 --- a/src/clients/gtk/LashController.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "LashController.h" -#include "config.h" -#include -#include -#include -#include -#include -#include "App.h" -#include "PatchController.h" -#include "PatchModel.h" - -using std::cerr; using std::cout; using std::endl; -using std::string; - -namespace OmGtk { - - -LashController::LashController(lash_args_t* args) -: m_client(NULL) -{ - m_client = lash_init(args, PACKAGE_NAME, - /*LASH_Config_Data_Set|*/LASH_Config_File, LASH_PROTOCOL(2, 0)); - if (m_client == NULL) { - cerr << "[LashController] Failed to connect to LASH. Session management will not function." << endl; - } else { - cout << "[LashController] Lash initialised" << endl; - } - - lash_event_t* event = lash_event_new_with_type(LASH_Client_Name); - lash_event_set_string(event, "OmGtk"); - lash_send_event(m_client, event); -} - - -LashController::~LashController() -{ - if (m_client != NULL) { - lash_event_t* quit_event = lash_event_new_with_type(LASH_Quit); - lash_send_event(m_client, quit_event); - } -} - - -void -LashController::process_events() -{ - assert(m_client != NULL); - - 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 -LashController::handle_event(lash_event_t* ev) -{ - assert(ev != NULL); - - 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; - - if (type == LASH_Save_File) { - cout << "[LashController] LASH Save File - " << str << endl; - save(str); - lash_send_event(m_client, lash_event_new_with_type(LASH_Save_File)); - } else if (type == LASH_Restore_File) { - cout << "[LashController] LASH Restore File - " << str << endl; - cerr << "LASH RESTORE NOT YET (RE)IMPLEMENTED." << endl; - /*_controller->load_session_blocking(str + "/session"); - _controller->lash_restore_finished(); - lash_send_event(m_client, lash_event_new_with_type(LASH_Restore_File)); - */ - /*} else if (type == LASH_Save_Data_Set) { - //cout << "[LashController] 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) { - cout << "[LashController] LASH Quit" << endl; - m_client = NULL; - App::instance().quit(); - } else { - cerr << "[LashController] Unhandled LASH event, type: " << static_cast(type) << endl; - } -} - - -void -LashController::handle_config(lash_config_t* conf) -{ - assert(conf != NULL); - - const char* key = NULL; - const void* val = NULL; - size_t val_size = 0; - - cout << "[LashController] 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); -} - -void -LashController::save(const string& dir) -{ - cerr << "LASH SAVING NOT YET (RE)IMPLEMENTED\n"; - /* - PatchController* pc = NULL; - - // Save every patch under dir with it's path as a filename - // (so the dir structure will resemble the patch heirarchy) - for (map::iterator i = m_app->patches().begin(); - i != m_app->patches().end(); ++i) { - pc = (*i).second; - pc->model()->filename(dir + pc->model()->path() + ".om"); - } - - // Create directories - for (map::iterator i = m_app->patches().begin(); - i != m_app->patches().end(); ++i) { - pc = (*i).second; - if (pc->model()->parent() != NULL) { - string path = OmPath::parent(pc->model()->path()).substr(1) + "/"; - while (path.find("/") != string::npos) { - mkdir(string(dir +"/"+ path.substr(0, path.find("/"))).c_str(), 0744); - path = path.substr(path.find("/")+1); - } - } - _controller->save_patch_blocking(pc->model(), pc->model()->filename(), false); - } - - //m_app->state_manager()->save(str + "/omgtkrc"); - _controller->save_session_blocking(dir + "/session"); - */ -} - -} // namespace OmGtk diff --git a/src/clients/gtk/LashController.h b/src/clients/gtk/LashController.h deleted file mode 100644 index f61c9f7f..00000000 --- a/src/clients/gtk/LashController.h +++ /dev/null @@ -1,53 +0,0 @@ -/* This file is part of OmGtk. Copyright (C) 2006 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 LASHCONTROLLER_H -#define LASHCONTROLLER_H - -#include -#include -using std::string; - -namespace OmGtk { - -class App; - -/* Old and unused LASH controller. - * - * \ingroup OmGtk - */ -class LashController -{ -public: - LashController(lash_args_t* args); - ~LashController(); - - bool enabled() { return lash_enabled(m_client); } - void process_events(); - -private: - void save(const string& dir); - - lash_client_t* m_client; - - void handle_event(lash_event_t* conf); - void handle_config(lash_config_t* conf); -}; - - -} // namespace OmGtk - -#endif // LASHCONTROLLER_H diff --git a/src/clients/gtk/LoadPatchWindow.cpp b/src/clients/gtk/LoadPatchWindow.cpp deleted file mode 100644 index 60f6e15f..00000000 --- a/src/clients/gtk/LoadPatchWindow.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "LoadPatchWindow.h" -#include -#include -#include "App.h" -#include "Configuration.h" -#include "PatchController.h" -#include "PatchModel.h" -#include "Controller.h" - -namespace OmGtk { - - -LoadPatchWindow::LoadPatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::FileChooserDialog(cobject), - m_patch_controller(NULL), - m_replace(true) -{ - xml->get_widget("load_patch_poly_from_current_radio", m_poly_from_current_radio); - xml->get_widget("load_patch_poly_from_file_radio", m_poly_from_file_radio); - xml->get_widget("load_patch_poly_from_user_radio", m_poly_from_user_radio); - xml->get_widget("load_patch_poly_spinbutton", m_poly_spinbutton); - xml->get_widget("load_patch_ok_button", m_ok_button); - xml->get_widget("load_patch_cancel_button", m_cancel_button); - - m_poly_from_current_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_file_selected)); - m_poly_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_file_selected)); - m_poly_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_user_selected)); - m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &LoadPatchWindow::ok_clicked)); - m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &LoadPatchWindow::cancel_clicked)); - - m_poly_from_current_radio->set_active(true); - - Gtk::FileFilter filt; - filt.add_pattern("*.om"); - filt.set_name("Om patch files (*.om)"); - set_filter(filt); - - // Add global examples directory to "shortcut folders" (bookmarks) - string examples_dir = PKGDATADIR; - examples_dir.append("/patches"); - DIR* d = opendir(examples_dir.c_str()); - if (d != NULL) - add_shortcut_folder(examples_dir); -} - - -/** Sets the patch controller for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -LoadPatchWindow::patch_controller(PatchController* pc) -{ - m_patch_controller = pc; -} - - -void -LoadPatchWindow::on_show() -{ - if (App::instance().configuration()->patch_folder().length() > 0) - set_current_folder(App::instance().configuration()->patch_folder()); - Gtk::FileChooserDialog::on_show(); -} - - -///// Event Handlers ////// - - -void -LoadPatchWindow::poly_from_file_selected() -{ - m_poly_spinbutton->property_sensitive() = false; -} - - -void -LoadPatchWindow::poly_from_user_selected() -{ - m_poly_spinbutton->property_sensitive() = true; -} - - -void -LoadPatchWindow::ok_clicked() -{ - // These values are interpreted by load_patch() as "not defined", ie load from file - string name = ""; - int poly = 0; - - if (m_poly_from_user_radio->get_active()) - poly = m_poly_spinbutton->get_value_as_int(); - - if (m_replace) - Controller::instance().clear_patch(m_patch_controller->model()->path()); - - PatchModel* pm = new PatchModel(m_patch_controller->model()->path(), poly); - pm->filename(get_filename()); - pm->set_metadata("filename", get_filename()); - pm->set_parent(m_patch_controller->patch_model()->parent()); - //Controller::instance().push_added_patch(pm); - Controller::instance().load_patch(pm, true, true); - - hide(); -} - - -void -LoadPatchWindow::cancel_clicked() -{ - hide(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/LoadPatchWindow.h b/src/clients/gtk/LoadPatchWindow.h deleted file mode 100644 index 7d7093bd..00000000 --- a/src/clients/gtk/LoadPatchWindow.h +++ /dev/null @@ -1,73 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 LOADPATCHWINDOW_H -#define LOADPATCHWINDOW_H - -#include "PluginModel.h" - -#include -#include - -namespace OmGtk { - -class PatchController; - - -/** 'Load Patch' window. - * - * Loaded by glade as a derived object. Used for both "Load" and "Load Into" - * operations (the radio button state should be changed with the provided - * methods prior to presenting this window). - * - * This is not for loading subpatches. See @a LoadSubpatchWindow for that. - * - * \ingroup OmGtk - */ -class LoadPatchWindow : public Gtk::FileChooserDialog -{ -public: - LoadPatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); - - void patch_controller(PatchController* pc); - - void set_replace() { m_replace = true; } - void set_merge() { m_replace = false; } - -protected: - void on_show(); - -private: - void poly_from_file_selected(); - void poly_from_user_selected(); - void ok_clicked(); - void cancel_clicked(); - - PatchController* m_patch_controller; - bool m_replace; - - Gtk::RadioButton* m_poly_from_current_radio; - Gtk::RadioButton* m_poly_from_file_radio; - Gtk::RadioButton* m_poly_from_user_radio; - Gtk::SpinButton* m_poly_spinbutton; - Gtk::Button* m_ok_button; - Gtk::Button* m_cancel_button; -}; - - -} // namespace OmGtk - -#endif // LOADPATCHWINDOW_H diff --git a/src/clients/gtk/LoadPluginWindow.cpp b/src/clients/gtk/LoadPluginWindow.cpp deleted file mode 100644 index b84ae39e..00000000 --- a/src/clients/gtk/LoadPluginWindow.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "LoadPluginWindow.h" -#include -#include -#include -#include -#include "PatchController.h" -#include "NodeModel.h" -#include "Controller.h" -#include "App.h" -#include "PatchWindow.h" -#include "OmFlowCanvas.h" -#include "PatchModel.h" -#include "Store.h" -using std::cout; using std::cerr; using std::endl; - - -namespace OmGtk { - -LoadPluginWindow::LoadPluginWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::Window(cobject), - m_patch_controller(NULL), - m_has_shown(false), - m_plugin_name_offset(0), - m_new_module_x(0), - m_new_module_y(0) -{ - xml->get_widget("load_plugin_plugins_treeview", m_plugins_treeview); - xml->get_widget("load_plugin_polyphonic_checkbutton", m_polyphonic_checkbutton); - xml->get_widget("load_plugin_name_entry", m_node_name_entry); - xml->get_widget("load_plugin_clear_button", m_clear_button); - xml->get_widget("load_plugin_add_button", m_add_button); - xml->get_widget("load_plugin_close_button", m_close_button); - //xml->get_widget("load_plugin_ok_button", m_ok_button); - - xml->get_widget("load_plugin_filter_combo", m_filter_combo); - xml->get_widget("load_plugin_search_entry", m_search_entry); - - // Set up the plugins list - m_plugins_liststore = Gtk::ListStore::create(m_plugins_columns); - m_plugins_treeview->set_model(m_plugins_liststore); - m_plugins_treeview->append_column("Name", m_plugins_columns.m_col_name); - m_plugins_treeview->append_column("Type", m_plugins_columns.m_col_type); - m_plugins_treeview->append_column("URI", m_plugins_columns.m_col_uri); - //m_plugins_treeview->append_column("Library", m_plugins_columns.m_col_library); - //m_plugins_treeview->append_column("Label", m_plugins_columns.m_col_label); - - // This could be nicer.. store the TreeViewColumns locally maybe? - m_plugins_treeview->get_column(0)->set_sort_column(m_plugins_columns.m_col_name); - m_plugins_treeview->get_column(1)->set_sort_column(m_plugins_columns.m_col_type); - m_plugins_treeview->get_column(2)->set_sort_column(m_plugins_columns.m_col_uri); - //m_plugins_treeview->get_column(3)->set_sort_column(m_plugins_columns.m_col_library); - //m_plugins_treeview->get_column(4)->set_sort_column(m_plugins_columns.m_col_label); - for (int i=0; i < 3; ++i) - m_plugins_treeview->get_column(i)->set_resizable(true); - - // Set up the search criteria combobox - m_criteria_liststore = Gtk::ListStore::create(m_criteria_columns); - m_filter_combo->set_model(m_criteria_liststore); - Gtk::TreeModel::iterator iter = m_criteria_liststore->append(); - Gtk::TreeModel::Row row = *iter; - row[m_criteria_columns.m_col_label] = "Name contains: "; - row[m_criteria_columns.m_col_criteria] = CriteriaColumns::NAME; - m_filter_combo->set_active(iter); - iter = m_criteria_liststore->append(); row = *iter; - row[m_criteria_columns.m_col_label] = "Type contains: "; - row[m_criteria_columns.m_col_criteria] = CriteriaColumns::TYPE; - iter = m_criteria_liststore->append(); row = *iter; - row[m_criteria_columns.m_col_label] = "URI contains: "; - row[m_criteria_columns.m_col_criteria] = CriteriaColumns::URI; - /*iter = m_criteria_liststore->append(); row = *iter; - row[m_criteria_columns.m_col_label] = "Library contains: "; - row[m_criteria_columns.m_col_criteria] = CriteriaColumns::LIBRARY; - iter = m_criteria_liststore->append(); row = *iter; - row[m_criteria_columns.m_col_label] = "Label contains: "; - row[m_criteria_columns.m_col_criteria] = CriteriaColumns::LABEL;*/ - - m_clear_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::clear_clicked)); - m_add_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::add_clicked)); - m_close_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::close_clicked)); - //m_ok_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::ok_clicked)); - m_plugins_treeview->signal_row_activated().connect(sigc::mem_fun(this, &LoadPluginWindow::plugin_activated)); - m_search_entry->signal_activate().connect( sigc::mem_fun(this, &LoadPluginWindow::add_clicked)); - m_search_entry->signal_changed().connect( sigc::mem_fun(this, &LoadPluginWindow::filter_changed)); - - m_selection = m_plugins_treeview->get_selection(); - m_selection->signal_changed().connect(sigc::mem_fun(this, &LoadPluginWindow::plugin_selection_changed)); - - //m_add_button->grab_default(); -} - - -/** Sets the patch controller for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -LoadPluginWindow::patch_controller(PatchController* pc) -{ - m_patch_controller = pc; - - if (pc->patch_model()->poly() <= 1) - m_polyphonic_checkbutton->property_sensitive() = false; - else - m_polyphonic_checkbutton->property_sensitive() = true; - -} - - -/** Populates the plugin list on the first show. - * - * This is done here instead of construction time as the list population is - * really expensive and bogs down creation of a patch. This is especially - * important when many patch notifications are sent at one time from the - * engine. - */ -void -LoadPluginWindow::on_show() -{ - if (!m_has_shown) { - set_plugin_model(Store::instance().plugins()); - - // Center on patch window - int m_w, m_h; - get_size(m_w, m_h); - - int parent_x, parent_y, parent_w, parent_h; - m_patch_controller->window()->get_position(parent_x, parent_y); - m_patch_controller->window()->get_size(parent_w, parent_h); - - move(parent_x + parent_w/2 - m_w/2, parent_y + parent_h/2 - m_h/2); - - m_has_shown = true; - } - Gtk::Window::on_show(); -} - - -void -LoadPluginWindow::on_hide() -{ - m_new_module_x = 0; - m_new_module_y = 0; - Gtk::Window::on_hide(); -} - - -void -LoadPluginWindow::set_plugin_model(const std::map& m) -{ - m_plugins_liststore->clear(); - - const PluginModel* plugin = NULL; - for (std::map::const_iterator i = m.begin(); i != m.end(); ++i) { - plugin = (*i).second; - - Gtk::TreeModel::iterator iter = m_plugins_liststore->append(); - Gtk::TreeModel::Row row = *iter; - - row[m_plugins_columns.m_col_name] = plugin->name(); - //row[m_plugins_columns.m_col_label] = plugin->plug_label(); - row[m_plugins_columns.m_col_type] = plugin->type_string(); - row[m_plugins_columns.m_col_uri] = plugin->uri(); - row[m_plugins_columns.m_col_label] = plugin->name(); - //row[m_plugins_columns.m_col_library] = plugin->lib_name(); - row[m_plugins_columns.m_col_plugin_model] = plugin; - } - - m_plugins_treeview->columns_autosize(); -} - - -void -LoadPluginWindow::add_plugin(const PluginModel* const plugin) -{ - Gtk::TreeModel::iterator iter = m_plugins_liststore->append(); - Gtk::TreeModel::Row row = *iter; - - row[m_plugins_columns.m_col_name] = plugin->name(); - //row[m_plugins_columns.m_col_label] = plugin->plug_label(); - row[m_plugins_columns.m_col_type] = plugin->type_string(); - row[m_plugins_columns.m_col_uri] = plugin->uri(); - row[m_plugins_columns.m_col_label] = plugin->name(); - //row[m_plugins_columns.m_col_library] = plugin->lib_name(); - row[m_plugins_columns.m_col_plugin_model] = plugin; -} - - - -///// Event Handlers ////// - - -void -LoadPluginWindow::plugin_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* col) -{ - add_clicked(); -} - - -void -LoadPluginWindow::plugin_selection_changed() -{ - m_plugin_name_offset = 0; - - m_node_name_entry->set_text(generate_module_name()); - - //Gtk::TreeModel::iterator iter = m_selection->get_selected(); - //Gtk::TreeModel::Row row = *iter; - //const PluginModel* plugin = row.get_value(m_plugins_columns.m_col_plugin_model); -} - - -/** Generate an automatic name for this Node. - * - * Offset is an offset of the number that will be appended to the plugin's - * label, needed if the user adds multiple plugins faster than the engine - * sends the notification back. - */ -string -LoadPluginWindow::generate_module_name(int offset) -{ - string name = ""; - - Gtk::TreeModel::iterator iter = m_selection->get_selected(); - - if (iter) { - Gtk::TreeModel::Row row = *iter; - const PluginModel* const plugin = row.get_value(m_plugins_columns.m_col_plugin_model); - char num_buf[3]; - for (uint i=0; i < 99; ++i) { - name = plugin->plug_label(); - if (name == "") - name = plugin->name().substr(0, plugin->name().find(' ')); - if (i+offset != 0) { - snprintf(num_buf, 3, "%d", i+offset+1); - name += "_"; - name += num_buf; - } - if (m_patch_controller->patch_model()->get_node(name) == NULL) - break; - else - name = ""; - } - } - - return name; -} - - -void -LoadPluginWindow::add_clicked() -{ - Gtk::TreeModel::iterator iter = m_selection->get_selected(); - bool polyphonic = m_polyphonic_checkbutton->get_active(); - - if (iter) { // If anything is selected - Gtk::TreeModel::Row row = *iter; - const PluginModel* const plugin = row.get_value(m_plugins_columns.m_col_plugin_model); - string name = m_node_name_entry->get_text(); - if (name == "") { - name = generate_module_name(); - } - if (name == "") { - Gtk::MessageDialog dialog(*this, - "Unable to chose a default name for this node. Please enter a name.", - false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - - dialog.run(); - } else { - const string path = m_patch_controller->model()->base_path() + name; - NodeModel* nm = new NodeModel(path); - nm->plugin(plugin); - nm->polyphonic(polyphonic); - - if (m_new_module_x == 0 && m_new_module_y == 0) { - m_patch_controller->get_new_module_location( - m_new_module_x, m_new_module_y); - } - nm->x(m_new_module_x); - nm->y(m_new_module_y); - - Controller::instance().create_node_from_model(nm); - ++m_plugin_name_offset; - m_node_name_entry->set_text(generate_module_name(m_plugin_name_offset)); - - // Set the next module location 20 over, for a cascade effect - m_new_module_x += 20; - m_new_module_y += 20; - } - } -} - - -void -LoadPluginWindow::close_clicked() -{ - hide(); -} - - -/* -void -LoadPluginWindow::ok_clicked() -{ - add_clicked(); - close_clicked(); -} -*/ - -void -LoadPluginWindow::filter_changed() -{ - m_plugins_liststore->clear(); - - string search = m_search_entry->get_text(); - transform(search.begin(), search.end(), search.begin(), toupper); - - // Get selected criteria - const Gtk::TreeModel::Row row = *(m_filter_combo->get_active()); - CriteriaColumns::Criteria criteria = row[m_criteria_columns.m_col_criteria]; - - string field; - - Gtk::TreeModel::Row model_row; - Gtk::TreeModel::iterator model_iter; - size_t num_visible = 0; - - const PluginModel* plugin = NULL; - for (std::map::const_iterator i = Store::instance().plugins().begin(); - i != Store::instance().plugins().end(); ++i) { - plugin = (*i).second; - - switch (criteria) { - case CriteriaColumns::NAME: - field = plugin->name(); break; - case CriteriaColumns::TYPE: - field = plugin->type_string(); break; - case CriteriaColumns::URI: - field = plugin->uri(); break; - /*case CriteriaColumns::LIBRARY: - field = plugin->lib_name(); break; - case CriteriaColumns::LABEL: - field = plugin->plug_label(); break;*/ - default: - throw; - } - - transform(field.begin(), field.end(), field.begin(), toupper); - - if (field.find(search) != string::npos) { - model_iter = m_plugins_liststore->append(); - model_row = *model_iter; - - model_row[m_plugins_columns.m_col_name] = plugin->name(); - //model_row[m_plugins_columns.m_col_label] = plugin->plug_label(); - model_row[m_plugins_columns.m_col_type] = plugin->type_string(); - model_row[m_plugins_columns.m_col_uri] = plugin->uri(); - model_row[m_plugins_columns.m_col_label] = plugin->plug_label(); - //model_row[m_plugins_columns.m_col_library] = plugin->lib_name(); - model_row[m_plugins_columns.m_col_plugin_model] = plugin; - - ++num_visible; - } - } - - if (num_visible == 1) { - m_selection->unselect_all(); - m_selection->select(model_iter); - } -} - - -void -LoadPluginWindow::clear_clicked() -{ - m_search_entry->set_text(""); - set_plugin_model(Store::instance().plugins()); -} - -bool -LoadPluginWindow::on_key_press_event(GdkEventKey* event) -{ - if (event->keyval == GDK_w && event->state & GDK_CONTROL_MASK) { - hide(); - return true; - } else { - return Gtk::Window::on_key_press_event(event); - } -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/LoadPluginWindow.h b/src/clients/gtk/LoadPluginWindow.h deleted file mode 100644 index adf11ab4..00000000 --- a/src/clients/gtk/LoadPluginWindow.h +++ /dev/null @@ -1,145 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 LOADPLUGINWINDOW_H -#define LOADPLUGINWINDOW_H - -#include "PluginModel.h" -#include -#include -#include -#include - - -using LibOmClient::PluginModel; - -namespace OmGtk { - -class PatchController; - -// Gtkmm _really_ needs to add some helper to abstract away this stupid nonsense - -/** Columns for the plugin list in the load plugin window. - * - * \ingroup OmGtk - */ -class ModelColumns : public Gtk::TreeModel::ColumnRecord -{ -public: - ModelColumns() { - add(m_col_name); - add(m_col_type); - add(m_col_uri); - add(m_col_label); - //add(m_col_library); - //add(m_col_label); - add(m_col_plugin_model); - } - - Gtk::TreeModelColumn m_col_name; - Gtk::TreeModelColumn m_col_type; - Gtk::TreeModelColumn m_col_uri; - - // Not displayed: - Gtk::TreeModelColumn m_col_label; - Gtk::TreeModelColumn m_col_plugin_model; -}; - - -/** Column for the criteria combo box in the load plugin window. - * - * \ingroup OmGtk - */ -class CriteriaColumns : public Gtk::TreeModel::ColumnRecord -{ -public: - enum Criteria { NAME, TYPE, URI, }; - - CriteriaColumns() { add(m_col_label); add(m_col_criteria); } - - Gtk::TreeModelColumn m_col_label; - Gtk::TreeModelColumn m_col_criteria; -}; - - -/** 'Load Plugin' window. - * - * Loaded by glade as a derived object. - * - * \ingroup OmGtk - */ -class LoadPluginWindow : public Gtk::Window -{ -public: - LoadPluginWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); - - void patch_controller(PatchController* pc); - void set_plugin_model(const std::map& m); - - void set_next_module_location(int x, int y) - { m_new_module_x = x; m_new_module_y = y; } - - void add_plugin(const PluginModel* info); - bool has_shown() const { return m_has_shown; } - -protected: - void on_show(); - void on_hide(); - bool on_key_press_event(GdkEventKey* event); - -private: - void add_clicked(); - void close_clicked(); - //void ok_clicked(); - void filter_changed(); - void clear_clicked(); - - void plugin_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* col); - void plugin_selection_changed(); - string generate_module_name(int offset = 0); - - PatchController* m_patch_controller; - bool m_has_shown; // plugin list only populated on show to speed patch window creation - - Glib::RefPtr m_plugins_liststore; - ModelColumns m_plugins_columns; - - Glib::RefPtr m_criteria_liststore; - CriteriaColumns m_criteria_columns; - - Glib::RefPtr m_selection; - - int m_plugin_name_offset; // see comments for generate_plugin_name - - int m_new_module_x; - int m_new_module_y; - - Gtk::TreeView* m_plugins_treeview; - Gtk::CheckButton* m_polyphonic_checkbutton; - Gtk::Entry* m_node_name_entry; - Gtk::Button* m_clear_button; - Gtk::Button* m_add_button; - Gtk::Button* m_close_button; - //Gtk::Button* m_ok_button; - Gtk::ComboBox* m_filter_combo; - Gtk::Entry* m_search_entry; -}; - - -} // namespace OmGtk - -#endif // LOADPLUGINWINDOW_H diff --git a/src/clients/gtk/LoadSubpatchWindow.cpp b/src/clients/gtk/LoadSubpatchWindow.cpp deleted file mode 100644 index fe02d772..00000000 --- a/src/clients/gtk/LoadSubpatchWindow.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "LoadSubpatchWindow.h" -#include -#include -#include -#include "App.h" -#include "PatchController.h" -#include "NodeModel.h" -#include "Controller.h" -#include "PatchModel.h" -#include "Configuration.h" - -namespace OmGtk { - - -LoadSubpatchWindow::LoadSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::FileChooserDialog(cobject), - m_patch_controller(NULL), - m_new_module_x(0), - m_new_module_y(0) -{ - xml->get_widget("load_subpatch_name_from_file_radio", m_name_from_file_radio); - xml->get_widget("load_subpatch_name_from_user_radio", m_name_from_user_radio); - xml->get_widget("load_subpatch_name_entry", m_name_entry); - xml->get_widget("load_subpatch_poly_from_file_radio", m_poly_from_file_radio); - xml->get_widget("load_subpatch_poly_from_parent_radio", m_poly_from_parent_radio); - xml->get_widget("load_subpatch_poly_from_user_radio", m_poly_from_user_radio); - xml->get_widget("load_subpatch_poly_spinbutton", m_poly_spinbutton); - xml->get_widget("load_subpatch_ok_button", m_ok_button); - xml->get_widget("load_subpatch_cancel_button", m_cancel_button); - - m_name_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_name_entry)); - m_name_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::enable_name_entry)); - m_poly_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_poly_spinner)); - m_poly_from_parent_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_poly_spinner)); - m_poly_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::enable_poly_spinner)); - m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &LoadSubpatchWindow::ok_clicked)); - m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &LoadSubpatchWindow::cancel_clicked)); - - Gtk::FileFilter filt; - filt.add_pattern("*.om"); - filt.set_name("Om patch files (*.om)"); - set_filter(filt); - - // Add global examples directory to "shortcut folders" (bookmarks) - string examples_dir = PKGDATADIR; - examples_dir.append("/patches"); - DIR* d = opendir(examples_dir.c_str()); - if (d != NULL) - add_shortcut_folder(examples_dir); -} - - -/** Sets the patch controller for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -LoadSubpatchWindow::patch_controller(PatchController* pc) -{ - m_patch_controller = pc; - - char temp_buf[4]; - snprintf(temp_buf, 4, "%zd", pc->patch_model()->poly()); - Glib::ustring txt = "Same as parent ("; - txt.append(temp_buf).append(")"); - m_poly_from_parent_radio->set_label(txt); -} - - -void -LoadSubpatchWindow::on_show() -{ - if (App::instance().configuration()->patch_folder().length() > 0) - set_current_folder(App::instance().configuration()->patch_folder()); - Gtk::FileChooserDialog::on_show(); -} - - -///// Event Handlers ////// - - - -void -LoadSubpatchWindow::disable_name_entry() -{ - m_name_entry->property_sensitive() = false; -} - - -void -LoadSubpatchWindow::enable_name_entry() -{ - m_name_entry->property_sensitive() = true; -} - - -void -LoadSubpatchWindow::disable_poly_spinner() -{ - m_poly_spinbutton->property_sensitive() = false; -} - - -void -LoadSubpatchWindow::enable_poly_spinner() -{ - m_poly_spinbutton->property_sensitive() = true; -} - - -void -LoadSubpatchWindow::ok_clicked() -{ - assert(m_patch_controller != NULL); - assert(m_patch_controller->model() != NULL); - - // These values are interpreted by load_patch() as "not defined", ie load from file - string name = ""; - int poly = 0; - - if (m_name_from_user_radio->get_active()) - name = m_name_entry->get_text(); - - if (m_poly_from_user_radio->get_active()) - poly = m_poly_spinbutton->get_value_as_int(); - else if (m_poly_from_parent_radio->get_active()) - poly = m_patch_controller->patch_model()->poly(); - - if (m_new_module_x == 0 && m_new_module_y == 0) { - m_patch_controller->get_new_module_location( - m_new_module_x, m_new_module_y); - } - - PatchModel* pm = new PatchModel(m_patch_controller->model()->base_path() + name, poly); - pm->filename(get_filename()); - pm->set_parent(m_patch_controller->model()); - pm->x(m_new_module_x); - pm->y(m_new_module_y); - if (name == "") - pm->set_path(""); - char temp_buf[16]; - snprintf(temp_buf, 16, "%d", m_new_module_x); - pm->set_metadata("module-x", temp_buf); - snprintf(temp_buf, 16, "%d", m_new_module_y); - pm->set_metadata("module-y", temp_buf); - Controller::instance().load_patch(pm); - - App::instance().configuration()->set_patch_folder(pm->filename().substr(0, pm->filename().find_last_of("/"))); - - hide(); -} - - -void -LoadSubpatchWindow::cancel_clicked() -{ - hide(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/LoadSubpatchWindow.h b/src/clients/gtk/LoadSubpatchWindow.h deleted file mode 100644 index 45efdd15..00000000 --- a/src/clients/gtk/LoadSubpatchWindow.h +++ /dev/null @@ -1,78 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 LOADSUBPATCHWINDOW_H -#define LOADSUBPATCHWINDOW_H - -#include "PluginModel.h" -#include -#include - - -namespace OmGtk { - -class PatchController; - - -/** 'Add Subpatch' window. - * - * Loaded by glade as a derived object. - * - * \ingroup OmGtk - */ -class LoadSubpatchWindow : public Gtk::FileChooserDialog -{ -public: - LoadSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); - - void patch_controller(PatchController* pc); - - void set_next_module_location(int x, int y) - { m_new_module_x = x; m_new_module_y = y; } - -protected: - void on_show(); - -private: - void disable_name_entry(); - void enable_name_entry(); - void disable_poly_spinner(); - void enable_poly_spinner(); - - void ok_clicked(); - void cancel_clicked(); - - PatchController* m_patch_controller; - - int m_new_module_x; - int m_new_module_y; - - Gtk::RadioButton* m_name_from_file_radio; - Gtk::RadioButton* m_name_from_user_radio; - Gtk::Entry* m_name_entry; - Gtk::RadioButton* m_poly_from_file_radio; - Gtk::RadioButton* m_poly_from_parent_radio; - Gtk::RadioButton* m_poly_from_user_radio; - Gtk::SpinButton* m_poly_spinbutton; - Gtk::Button* m_ok_button; - Gtk::Button* m_cancel_button; -}; - - -} // namespace OmGtk - -#endif // LOADSUBPATCHWINDOW_H diff --git a/src/clients/gtk/Loader.cpp b/src/clients/gtk/Loader.cpp deleted file mode 100644 index 643dc3c9..00000000 --- a/src/clients/gtk/Loader.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "Loader.h" -#include -#include -#include -#include "PatchLibrarian.h" -#include "PatchModel.h" -#include "PatchController.h" -using std::cout; using std::endl; - -namespace OmGtk { - - -// LoadPatchEvent // - -void -LoadPatchEvent::execute() -{ - assert(m_patch_librarian != NULL); - m_patch_librarian->load_patch(m_patch_model, m_wait, m_merge); -} - - - -// SavePatchEvent // - -void -SavePatchEvent::execute() -{ - assert(m_patch_librarian != NULL); - m_patch_librarian->save_patch(m_patch_model, m_filename, m_recursive); -} - -/* -void -LoadSessionEvent::execute() -{ - std::ifstream is; - is.open(m_filename.c_str(), std::ios::in); - - if ( ! is.good()) { - cout << "[Loader] Unable to open session file " << m_filename << endl; - return; - } else { - cout << "[Loader] Loading session from " << m_filename << endl; - } - string s; - - is >> s; - if (s != "version") { - cout << "[Loader] Corrupt session file." << endl; - is.close(); - return; - } - - is >> s; - if (s != "1") { - cout << "[Loader] Unrecognised session file version." << endl; - is.close(); - return; - } - - while (!is.eof()) { - is >> s; - if (s == "") continue; - - if (s != "patch") { - //cerr << "[Loader] Corrupt session file, aborting session load." << endl; - break; - } else { - is >> s; - PatchModel* pm = new PatchModel("", 0); - if (s.substr(0, 1) != "/") - s = m_filename.substr(0, m_filename.find_last_of("/")+1) + s; - pm->filename(s); - pm->parent(NULL); - m_patch_librarian->load_patch(pm); - } - } - - is.close(); -} - - -void -SaveSessionEvent::execute() -{ - assert(m_filename != ""); - string dir = m_filename.substr(0, m_filename.find_last_of("/")); - - string patch_filename; - - std::ofstream os; - os.open(m_filename.c_str(), std::ios::out); - - if ( ! os.good()) { - cout << "[Loader] Unable to write to session file " << m_filename << endl; - return; - } else { - cout << "[Loader] Saving session to " << m_filename << endl; - } - - os << "version 1" << endl; - - for (map::iterator i = app->patches().begin(); - i != app->patches().end(); ++i) - { - if ((*i).second->model()->parent() == NULL) { - patch_filename = (*i).second->model()->filename(); - - // Make path relative if possible - if (patch_filename.length() > dir.length() && - patch_filename.substr(0, dir.length()) == dir) - patch_filename = patch_filename.substr(dir.length()+1); - - os << "patch " << patch_filename << endl; - } - } - - os.close(); -} -*/ - - -//////// Loader ////////// - - -Loader::Loader(PatchLibrarian* const patch_librarian) -: m_patch_librarian(patch_librarian), - m_event(NULL), - m_thread_exit_flag(false) -{ - assert(m_patch_librarian != NULL); - pthread_mutex_init(&m_mutex, NULL); - pthread_cond_init(&m_cond, NULL); -} - - -void -Loader::set_event(LoaderEvent* ev) -{ - assert(ev != NULL); - - pthread_mutex_lock(&m_mutex); - assert(m_event == NULL); - m_event = ev; - pthread_cond_signal(&m_cond); - pthread_mutex_unlock(&m_mutex); -} - - -void -Loader::launch() -{ - pthread_create(&m_thread, NULL, Loader::thread_function, this); -} - - -void* -Loader::thread_function(void* me) -{ - Loader* ct = static_cast(me); - return ct->m_thread_function(NULL); -} - - -void* -Loader::m_thread_function(void *) -{ - while ( ! m_thread_exit_flag) { - pthread_mutex_lock(&m_mutex); - pthread_cond_wait(&m_cond, &m_mutex); - - LoaderEvent* ev = m_event; - ev->execute(); - delete ev; - m_event = NULL; - - pthread_mutex_unlock(&m_mutex); - } - - pthread_exit(NULL); - return NULL; -} - - -void -Loader::load_patch(PatchModel* model, bool wait, bool merge) -{ - set_event(new LoadPatchEvent(m_patch_librarian, model, wait, merge)); -} - - -void -Loader::save_patch(PatchModel* model, const string& filename, bool recursive) -{ - cout << "[Loader] Saving patch " << filename << endl; - set_event(new SavePatchEvent(m_patch_librarian, model, filename, recursive)); -} - - -/* -void -Loader::load_session(const string& filename) -{ - set_event(new LoadSessionEvent(m_patch_librarian, filename)); -} - - -void -Loader::save_session(const string& filename) -{ - cout << "Saving session..." << endl; - set_event(new SaveSessionEvent(m_patch_librarian, filename)); -} -*/ - -} // namespace OmGtk diff --git a/src/clients/gtk/Loader.h b/src/clients/gtk/Loader.h deleted file mode 100644 index 46b5f3a8..00000000 --- a/src/clients/gtk/Loader.h +++ /dev/null @@ -1,154 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 LOADERTHREAD_H -#define LOADERTHREAD_H - -#include -#include -using std::string; - -namespace LibOmClient { - class PatchLibrarian; - class PatchModel; -} -using LibOmClient::PatchLibrarian; -using LibOmClient::PatchModel; - - -namespace OmGtk { - -/** Event to run in the Loader thread. - * - * \ingroup OmGtk - */ -class LoaderEvent -{ -public: - virtual void execute() = 0; - virtual ~LoaderEvent() {} -protected: - LoaderEvent() {} -}; - - -/** Loader thread patch loading event. - * - * \ingroup OmGtk - */ -class LoadPatchEvent : public LoaderEvent -{ -public: - LoadPatchEvent(PatchLibrarian* pl, PatchModel* model, bool wait, bool merge) - : m_patch_librarian(pl), m_patch_model(model), m_wait(wait), m_merge(merge) {} - virtual ~LoadPatchEvent() {} - void execute(); -private: - PatchLibrarian* m_patch_librarian; - PatchModel* m_patch_model; - bool m_wait; - bool m_merge; -}; - - -/** Loader thread patch loading event. - * - * \ingroup OmGtk - */ -class SavePatchEvent : public LoaderEvent -{ -public: - SavePatchEvent(PatchLibrarian* pl, PatchModel* pm, const string& filename, bool recursive) - : m_patch_librarian(pl), m_patch_model(pm), m_filename(filename), m_recursive(recursive) {} - virtual ~SavePatchEvent() {} - void execute(); -private: - PatchLibrarian* m_patch_librarian; - PatchModel* m_patch_model; - string m_filename; - bool m_recursive; -}; - -/* -class LoadSessionEvent : public LoaderEvent -{ -public: - LoadSessionEvent(PatchLibrarian* pl, const string& filename) - : m_patch_librarian(pl), m_filename(filename) {} - virtual ~LoadSessionEvent() {} - void execute(); -private: - PatchLibrarian* m_patch_librarian; - string m_filename; -}; - - -class SaveSessionEvent : public LoaderEvent -{ -public: - SaveSessionEvent(PatchLibrarian* pl, const string& filename) - : m_patch_librarian(pl), m_filename(filename) {} - virtual ~SaveSessionEvent() {} - void execute(); -private: - PatchLibrarian* m_patch_librarian; - string m_filename; -}; -*/ - -/** Thread for loading patch files. - * - * This is a seperate thread so it can send all the loading message without - * blocking everything else, so the app can respond to the incoming events - * caused as a result of the patch loading. - * - * \ingroup OmGtk - */ -class Loader -{ -public: - Loader(PatchLibrarian* const patch_librarian); - ~Loader() { m_thread_exit_flag = true; } - - void launch(); - void exit() { m_thread_exit_flag = true; } - - void load_patch(PatchModel* model, bool wait, bool merge); - void save_patch(PatchModel* model, const string& filename, bool recursive); - - //void load_session(const string& filename); - //void save_session(const string& filename); - - static void* thread_function(void* me); - -private: - void* m_thread_function(void*); - - void set_event(LoaderEvent* ev); - - PatchLibrarian* const m_patch_librarian; - LoaderEvent* m_event; - bool m_thread_exit_flag; - pthread_t m_thread; - pthread_mutex_t m_mutex; - pthread_cond_t m_cond; - -}; - - -} // namespace OmGtk - -#endif // LOADERRTHREAD_H diff --git a/src/clients/gtk/Makefile.am b/src/clients/gtk/Makefile.am deleted file mode 100644 index c92ae2b2..00000000 --- a/src/clients/gtk/Makefile.am +++ /dev/null @@ -1,98 +0,0 @@ -if BUILD_GTK_CLIENT - -EXTRA_DIST = om_gtk.gladep - -sharefilesdir = $(pkgdatadir) -dist_sharefiles_DATA = om_gtk.glade om-icon.png - -AM_CXXFLAGS = -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -I$(top_srcdir)/src/common -I$(top_srcdir)/src/clients -DPKGDATADIR=\"$(pkgdatadir)\" @GTKMM_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @LOSC_CFLAGS@ @LASH_CFLAGS@ @FLOWCANVAS_CFLAGS@ -om_gtk_LDADD = @GTKMM_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @LOSC_LIBS@ @LASH_LIBS@ @FLOWCANVAS_LIBS@ ../libomclient.a -om_gtk_DEPENDENCIES = ../libomclient.a - - -bin_PROGRAMS = om_gtk -om_gtk_SOURCES = \ - cmdline.h \ - cmdline.c \ - main.cpp \ - singletons.cpp \ - ConnectWindow.h \ - ConnectWindow.cpp \ - App.h \ - App.cpp \ - Store.h \ - Store.cpp \ - Configuration.h \ - Configuration.cpp \ - GladeFactory.h \ - GladeFactory.cpp \ - Controller.h \ - Controller.cpp \ - GtkObjectController.h \ - GtkObjectController.cpp \ - PatchController.h \ - PatchController.cpp \ - NodeController.h \ - NodeController.cpp \ - PortController.h \ - PortController.cpp \ - DSSIController.h \ - DSSIController.cpp \ - LoadPluginWindow.h \ - LoadPluginWindow.cpp \ - LoadPatchWindow.h \ - LoadPatchWindow.cpp \ - MessagesWindow.h \ - MessagesWindow.cpp \ - LoadSubpatchWindow.h \ - LoadSubpatchWindow.cpp \ - ControlInterface.h \ - ControlInterface.cpp \ - NodeControlWindow.h \ - NodeControlWindow.cpp \ - ControlPanel.h \ - ControlPanel.cpp \ - ControlGroups.h \ - ControlGroups.cpp \ - PatchView.h \ - PatchView.cpp \ - PatchWindow.h \ - PatchWindow.cpp \ - BreadCrumb.h \ - OmFlowCanvas.h \ - OmFlowCanvas.cpp \ - ../../common/types.h \ - ../../common/Path.h \ - OmModule.h \ - OmModule.cpp \ - DSSIModule.h \ - DSSIModule.cpp \ - SubpatchModule.h \ - SubpatchModule.cpp \ - OmPort.h \ - OmPort.cpp \ - NewSubpatchWindow.h \ - NewSubpatchWindow.cpp \ - ConfigWindow.h \ - ConfigWindow.cpp \ - PatchDescriptionWindow.h \ - PatchDescriptionWindow.cpp \ - Loader.h \ - Loader.cpp \ - RenameWindow.h \ - RenameWindow.cpp \ - NodePropertiesWindow.h \ - NodePropertiesWindow.cpp \ - PatchTreeWindow.h \ - PatchTreeWindow.cpp - -#GtkClientInterface.h -#GtkClientInterface.cpp - - -if WITH_LASH -om_gtk_SOURCES += LashController.h LashController.cpp -endif - - -endif # WITH_GTK_CLIENT diff --git a/src/clients/gtk/MessagesWindow.cpp b/src/clients/gtk/MessagesWindow.cpp deleted file mode 100644 index dfdc3750..00000000 --- a/src/clients/gtk/MessagesWindow.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "MessagesWindow.h" -#include - -namespace OmGtk { -using std::string; - - -MessagesWindow::MessagesWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml) -: Gtk::Window(cobject) -{ - glade_xml->get_widget("messages_textview", m_textview); - glade_xml->get_widget("messages_clear_button", m_clear_button); - glade_xml->get_widget("messages_close_button", m_close_button); - - m_clear_button->signal_clicked().connect(sigc::mem_fun(this, &MessagesWindow::clear_clicked)); - m_close_button->signal_clicked().connect(sigc::mem_fun(this, &MessagesWindow::close_clicked)); -} - - -void -MessagesWindow::post(const string& msg) -{ - Glib::RefPtr text_buf = m_textview->get_buffer(); - text_buf->insert(text_buf->end(), msg); - text_buf->insert(text_buf->end(), "\n"); - - if (!m_clear_button->is_sensitive()) - m_clear_button->set_sensitive(true); -} - - -void -MessagesWindow::close_clicked() -{ - hide(); -} - - -void -MessagesWindow::clear_clicked() -{ - Glib::RefPtr text_buf = m_textview->get_buffer(); - text_buf->erase(text_buf->begin(), text_buf->end()); - m_clear_button->set_sensitive(false); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/MessagesWindow.h b/src/clients/gtk/MessagesWindow.h deleted file mode 100644 index 5f5b86e6..00000000 --- a/src/clients/gtk/MessagesWindow.h +++ /dev/null @@ -1,55 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 MESSAGESWINDOW_H -#define MESSAGESWINDOW_H - -#include -#include -#include -using std::string; - - -namespace OmGtk { - - -/** Messages Window. - * - * Loaded by libglade as a derived object. - * This is shown when errors occur (ie during patch loading). - * - * \ingroup OmGtk - */ -class MessagesWindow : public Gtk::Window -{ -public: - MessagesWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); - - void post(const string& str); - -private: - void clear_clicked(); - void close_clicked(); - - Gtk::TextView* m_textview; - Gtk::Button* m_clear_button; - Gtk::Button* m_close_button; -}; - - -} // namespace OmGtk - -#endif // MESSAGESWINDOW_H diff --git a/src/clients/gtk/NewSubpatchWindow.cpp b/src/clients/gtk/NewSubpatchWindow.cpp deleted file mode 100644 index dcc2cd2d..00000000 --- a/src/clients/gtk/NewSubpatchWindow.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "NewSubpatchWindow.h" -#include "PatchController.h" -#include "NodeModel.h" -#include "Controller.h" -#include "PatchModel.h" - -namespace OmGtk { - - -NewSubpatchWindow::NewSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::Window(cobject), - m_new_module_x(0), - m_new_module_y(0) -{ - xml->get_widget("new_subpatch_name_entry", m_name_entry); - xml->get_widget("new_subpatch_message_label", m_message_label); - xml->get_widget("new_subpatch_polyphony_spinbutton", m_poly_spinbutton); - xml->get_widget("new_subpatch_ok_button", m_ok_button); - xml->get_widget("new_subpatch_cancel_button", m_cancel_button); - - m_name_entry->signal_changed().connect(sigc::mem_fun(this, &NewSubpatchWindow::name_changed)); - m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubpatchWindow::ok_clicked)); - m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubpatchWindow::cancel_clicked)); - - m_ok_button->property_sensitive() = false; -} - - -/** Sets the patch controller for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -NewSubpatchWindow::patch_controller(PatchController* pc) -{ - m_patch_controller = pc; -} - - -/** Called every time the user types into the name input box. - * Used to display warning messages, and enable/disable the OK button. - */ -void -NewSubpatchWindow::name_changed() -{ - string name = m_name_entry->get_text(); - if (name.find("/") != string::npos) { - m_message_label->set_text("Name may not contain '/'"); - m_ok_button->property_sensitive() = false; - } else if (m_patch_controller->patch_model()->get_node(name) != NULL) { - m_message_label->set_text("An object already exists with that name."); - m_ok_button->property_sensitive() = false; - } else if (name.length() == 0) { - m_message_label->set_text(""); - m_ok_button->property_sensitive() = false; - } else { - m_message_label->set_text(""); - m_ok_button->property_sensitive() = true; - } -} - - -void -NewSubpatchWindow::ok_clicked() -{ - PatchModel* pm = new PatchModel( - m_patch_controller->model()->base_path() + m_name_entry->get_text(), - m_poly_spinbutton->get_value_as_int()); - - if (m_new_module_x == 0 && m_new_module_y == 0) { - m_patch_controller->get_new_module_location( - m_new_module_x, m_new_module_y); - } - pm->set_parent(m_patch_controller->patch_model()); - pm->x(m_new_module_x); - pm->y(m_new_module_y); - char temp_buf[16]; - snprintf(temp_buf, 16, "%d", m_new_module_x); - pm->set_metadata("module-x", temp_buf); - snprintf(temp_buf, 16, "%d", m_new_module_y); - pm->set_metadata("module-y", temp_buf); - Controller::instance().create_patch_from_model(pm); - hide(); -} - - -void -NewSubpatchWindow::cancel_clicked() -{ - hide(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/NewSubpatchWindow.h b/src/clients/gtk/NewSubpatchWindow.h deleted file mode 100644 index 8421ea08..00000000 --- a/src/clients/gtk/NewSubpatchWindow.h +++ /dev/null @@ -1,67 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 NEWSUBPATCHWINDOW_H -#define NEWSUBPATCHWINDOW_H - -#include "PluginModel.h" -#include -#include - - -namespace OmGtk { - -class PatchController; - - -/** 'New Subpatch' window. - * - * Loaded by glade as a derived object. - * - * \ingroup OmGtk - */ -class NewSubpatchWindow : public Gtk::Window -{ -public: - NewSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); - - void patch_controller(PatchController* pc); - - void set_next_module_location(int x, int y) - { m_new_module_x = x; m_new_module_y = y; } - -private: - void name_changed(); - void ok_clicked(); - void cancel_clicked(); - - PatchController* m_patch_controller; - - int m_new_module_x; - int m_new_module_y; - - Gtk::Entry* m_name_entry; - Gtk::Label* m_message_label; - Gtk::SpinButton* m_poly_spinbutton; - Gtk::Button* m_ok_button; - Gtk::Button* m_cancel_button; -}; - - -} // namespace OmGtk - -#endif // NEWSUBPATCHWINDOW_H diff --git a/src/clients/gtk/NodeControlWindow.cpp b/src/clients/gtk/NodeControlWindow.cpp deleted file mode 100644 index e40af67f..00000000 --- a/src/clients/gtk/NodeControlWindow.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 alongCont - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "NodeControlWindow.h" -#include "GladeFactory.h" -#include "NodeController.h" -#include "ControlGroups.h" -#include "PatchWindow.h" -#include -#include -using std::cerr; using std::cout; using std::endl; - -namespace OmGtk { - - -/** Create a node control window and load a new ControlPanel for it. - */ -NodeControlWindow::NodeControlWindow(NodeController* node, size_t poly) -: m_node(node), - m_position_stored(false), - m_x(0), m_y(0) -{ - assert(m_node != NULL); - - property_resizable() = true; - set_border_width(5); - - set_title(m_node->path() + " Controls"); - - Glib::RefPtr xml = GladeFactory::new_glade_reference("warehouse_win"); - xml->get_widget_derived("control_panel_vbox", m_control_panel); - m_control_panel->reparent(*this); - - m_control_panel->init(m_node, poly); - - show_all_children(); - resize(); - - // FIXME: not working - set_icon_from_file(string(PKGDATADIR) + "/om-icon.png"); - - m_callback_enabled = true; -} - - -/** Create a node control window and with an existing ControlPanel. - */ -NodeControlWindow::NodeControlWindow(NodeController* node, ControlPanel* panel) -: m_node(node), - m_control_panel(panel) -{ - assert(m_node != NULL); - - property_resizable() = true; - set_border_width(5); - - set_title(m_node->path() + " Controls"); - - m_control_panel->reparent(*this); - - show_all_children(); - resize(); - - m_callback_enabled = true; -} - - -NodeControlWindow::~NodeControlWindow() -{ - delete m_control_panel; -} - - -void -NodeControlWindow::resize() -{ - pair controls_size = m_control_panel->ideal_size(); - /*int width = 400; - int height = controls_size.second - + ((m_node->polyphonic()) ? 4 : 40);*/ - int width = controls_size.first; - int height = controls_size.second; - - if (height > property_screen().get_value()->get_height() - 64) - height = property_screen().get_value()->get_height() - 64; - if (width > property_screen().get_value()->get_width() - 64) - width = property_screen().get_value()->get_width() - 64; - - //cerr << "Resizing to: " << width << " x " << height << endl; - - Gtk::Window::resize(width, height); -} - - -void -NodeControlWindow::on_show() -{ - if (m_position_stored) - move(m_x, m_y); - - Gtk::Window::on_show(); -} - - -void -NodeControlWindow::on_hide() -{ - m_position_stored = true; - get_position(m_x, m_y); - Gtk::Window::on_hide(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/NodeControlWindow.h b/src/clients/gtk/NodeControlWindow.h deleted file mode 100644 index a9224de9..00000000 --- a/src/clients/gtk/NodeControlWindow.h +++ /dev/null @@ -1,69 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 NODECONTROLWINDOW_H -#define NODECONTROLWINDOW_H - -#include -#include -#include -#include -#include -#include "ControlPanel.h" -using std::string; using std::vector; - -using namespace LibOmClient; - -namespace OmGtk { - -class ControlGroup; -class NodeController; - - -/** Window with controls (sliders) for all control-rate ports on a Node. - * - * \ingroup OmGtk - */ -class NodeControlWindow : public Gtk::Window -{ -public: - NodeControlWindow(NodeController* node, size_t poly); - NodeControlWindow(NodeController* node, ControlPanel* panel); - virtual ~NodeControlWindow(); - - ControlPanel* control_panel() const { return m_control_panel; } - - void resize(); - -protected: - void on_show(); - void on_hide(); - -private: - NodeController* m_node; - ControlPanel* m_control_panel; - bool m_callback_enabled; - - bool m_position_stored; - int m_x; - int m_y; -}; - - -} // namespace OmGtk - -#endif // NODECONTROLWINDOW_H diff --git a/src/clients/gtk/NodeController.cpp b/src/clients/gtk/NodeController.cpp deleted file mode 100644 index 57756877..00000000 --- a/src/clients/gtk/NodeController.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "NodeController.h" -#include -#include -#include "OmModule.h" -#include "NodeModel.h" -#include "PortModel.h" -#include "PortController.h" -#include "GtkObjectController.h" -#include "NodeControlWindow.h" -#include "OmModule.h" -#include "PatchController.h" -#include "OmFlowCanvas.h" -#include "RenameWindow.h" -#include "GladeFactory.h" -#include "Controller.h" -#include "PatchWindow.h" -#include "PatchModel.h" -#include "NodePropertiesWindow.h" -#include "Store.h" -using std::cerr; using std::endl; - -namespace OmGtk { - - -NodeController::NodeController(NodeModel* model) -: GtkObjectController(model), - m_controls_menuitem(NULL), - m_module(NULL), - m_control_window(NULL), - m_properties_window(NULL), - m_bridge_port(NULL) -{ - assert(model->controller() == NULL); - model->set_controller(this); - - // Create port controllers - for (list::const_iterator i = node_model()->ports().begin(); - i != node_model()->ports().end(); ++i) { - assert((*i)->controller() == NULL); - assert((*i)->parent() == model); - PortController* const pc = new PortController(*i); - assert((*i)->controller() == pc); // PortController() does this - } - - // Build menu - - Gtk::Menu::MenuList& items = m_menu.items(); - - Gtk::Menu_Helpers::MenuElem controls_elem - = Gtk::Menu_Helpers::MenuElem("Controls", - sigc::mem_fun(this, &NodeController::show_control_window)); - m_controls_menuitem = controls_elem.get_child(); - items.push_back(controls_elem); - items.push_back(Gtk::Menu_Helpers::MenuElem("Properties", - sigc::mem_fun(this, &NodeController::show_properties_window))); - items.push_back(Gtk::Menu_Helpers::SeparatorElem()); - items.push_back(Gtk::Menu_Helpers::MenuElem("Rename...", - sigc::mem_fun(this, &NodeController::show_rename_window))); - items.push_back(Gtk::Menu_Helpers::MenuElem("Clone", - sigc::mem_fun(this, &NodeController::on_menu_clone))); - items.push_back(Gtk::Menu_Helpers::MenuElem("Disconnect All", - sigc::mem_fun(this, &NodeController::on_menu_disconnect_all))); - items.push_back(Gtk::Menu_Helpers::MenuElem("Destroy", - sigc::mem_fun(this, &NodeController::on_menu_destroy))); - - m_controls_menuitem->property_sensitive() = false; - - if (node_model()->plugin()->type() == PluginModel::Internal - && node_model()->plugin()->plug_label() == "midi_control_in") { - Gtk::Menu::MenuList& items = m_menu.items(); - items.push_back(Gtk::Menu_Helpers::MenuElem("Learn", - sigc::mem_fun(this, &NodeController::on_menu_learn))); - } -} - - -NodeController::~NodeController() -{ -} - - -void -NodeController::create_module(OmFlowCanvas* canvas) -{ - //cerr << "Creating node module " << m_model->path() << endl; - - // If this is a DSSI plugin, DSSIController should be doing this - assert(node_model()->plugin()->type() != PluginModel::DSSI); - assert(canvas != NULL); - assert(m_module == NULL); - - m_module = new OmModule(canvas, this); - - create_all_ports(); - - m_module->move_to(node_model()->x(), node_model()->y()); -} - - -void -NodeController::add_to_store() -{ - // Add self - Store::instance().add_object(this); - - // Add ports - for (list::const_iterator i = node_model()->ports().begin(); - i != node_model()->ports().end(); ++i) { - //GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); - assert((*i)->controller() != NULL); - ((GtkObjectController*)((*i)->controller()))->add_to_store(); - } -} - - -void -NodeController::remove_from_store() -{ - // Remove ports - for (list::const_iterator i = node_model()->ports().begin(); - i != node_model()->ports().end(); ++i) { - GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); - assert(pc != NULL); - pc->remove_from_store(); - } - - // Remove self - Store::instance().remove_object(this); -} - - -void -NodeController::set_path(const Path& new_path) -{ - remove_from_store(); - - // Rename ports - for (list::const_iterator i = node_model()->ports().begin(); - i != node_model()->ports().end(); ++i) { - GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); - assert(pc != NULL); - pc->set_path(m_model->path().base_path() + pc->model()->name()); - } - - // Handle bridge port, if this node represents one - if (m_bridge_port != NULL) - m_bridge_port->set_path(new_path); - - if (m_module != NULL) - m_module->canvas()->rename_module(node_model()->path().name(), new_path.name()); - - GtkObjectController::set_path(new_path); - - add_to_store(); -} - - -void -NodeController::destroy() -{ - PatchController* pc = ((PatchController*)m_model->parent()->controller()); - assert(pc != NULL); - - remove_from_store(); - pc->remove_node(m_model->path().name()); - - if (m_bridge_port != NULL) - m_bridge_port->destroy(); - m_bridge_port = NULL; - - //if (m_module != NULL) - // delete m_module; -} - - -void -NodeController::metadata_update(const string& key, const string& value) -{ - //cout << "[NodeController] Metadata update: " << m_model->path() << endl; - - if (m_module != NULL) { - if (key == "module-x") { - float x = atof(value.c_str()); - //if (x > 0 && x < m_canvas->width()) - m_module->move_to(x, m_module->property_y().get_value()); - } else if (key == "module-y") { - float y = atof(value.c_str()); - //if (y > 0 && y < m_canvas->height()) - m_module->move_to(m_module->property_x().get_value(), y); - } - } - - if (m_bridge_port != NULL) - m_bridge_port->metadata_update(key, value); - GtkObjectController::metadata_update(key, value); -} - - -void -NodeController::add_port(PortModel* pm) -{ - assert(pm->parent() == NULL); - - cout << "[NodeController] Adding port " << pm->path() << endl; - - node_model()->add_port(pm); - PortController* pc = new PortController(pm); - assert(pm->controller() == pc); - pc->add_to_store(); - - if (m_module != NULL) { - pc->create_port(m_module); - m_module->resize(); - - // Enable "Controls" menu item on module - if (has_control_inputs()) - enable_controls_menuitem(); - } - - if (m_control_window != NULL) { - assert(m_control_window->control_panel() != NULL); - m_control_window->control_panel()->add_port(pc); - m_control_window->resize(); - } -} - - -void -NodeController::show_control_window() -{ - size_t poly = 1; - if (node_model()->polyphonic()) - poly = node_model()->parent_patch()->poly(); - - if (m_control_window == NULL) - m_control_window = new NodeControlWindow(this, poly); - - if (m_control_window->control_panel()->num_controls() > 0) - m_control_window->present(); -} - - -void -NodeController::on_menu_destroy() -{ - Controller::instance().destroy(node_model()->path()); -} - - -void -NodeController::show_rename_window() -{ - assert(node_model()->parent() != NULL); - - // FIXME: will this be magically cleaned up? - RenameWindow* win = NULL; - Glib::RefPtr xml = GladeFactory::new_glade_reference("rename_win"); - xml->get_widget_derived("rename_win", win); - - PatchController* parent = ((PatchController*)node_model()->parent()->controller()); - assert(parent != NULL); - - if (parent->window() != NULL) - win->set_transient_for(*parent->window()); - - win->set_object(this); - win->show(); -} - -void -NodeController::on_menu_clone() -{ - assert(node_model() != NULL); - //assert(m_parent != NULL); - //assert(m_parent->model() != NULL); - - string clone_name = node_model()->name(); - int i = 2; // postfix number (ie oldname_2) - - // Check if name already has a number postfix - if (clone_name.find_last_of("_") != string::npos) { - string name_postfix = clone_name.substr(clone_name.find_last_of("_")+1); - clone_name = clone_name.substr(0, clone_name.find_last_of("_")); - if (sscanf(name_postfix.c_str(), "%d", &i)) - ++i; - } - - char clone_postfix[4]; - for ( ; i < 100; ++i) { - snprintf(clone_postfix, 4, "_%d", i); - if (node_model()->parent_patch()->get_node(clone_name + clone_postfix) == NULL) - break; - } - - clone_name = clone_name + clone_postfix; - - const string path = node_model()->parent_patch()->base_path() + clone_name; - NodeModel* nm = new NodeModel(path); - nm->plugin(node_model()->plugin()); - nm->polyphonic(node_model()->polyphonic()); - nm->x(node_model()->x() + 20); - nm->y(node_model()->y() + 20); - Controller::instance().create_node_from_model(nm); -} - - -void -NodeController::on_menu_learn() -{ - Controller::instance().midi_learn(node_model()->path()); -} - -void -NodeController::on_menu_disconnect_all() -{ - Controller::instance().disconnect_all(node_model()->path()); -} - - -void -NodeController::show_properties_window() -{ - PatchController* parent = ((PatchController*)node_model()->parent()->controller()); - assert(parent != NULL); - - if (m_properties_window == NULL) { - Glib::RefPtr xml = GladeFactory::new_glade_reference("node_properties_win"); - xml->get_widget_derived("node_properties_win", m_properties_window); - } - assert(m_properties_window != NULL); - assert(parent != NULL); - m_properties_window->set_node(node_model()); - if (parent->window() != NULL) - m_properties_window->set_transient_for(*parent->window()); - m_properties_window->show(); -} - - -/** Create all (visual) ports and add them to module (and resize it). - */ -void -NodeController::create_all_ports() -{ - assert(m_module != NULL); - - PortController* pc = NULL; - for (PortModelList::const_iterator i = node_model()->ports().begin(); - i != node_model()->ports().end(); ++i) { - pc = dynamic_cast((*i)->controller()); - assert(pc != NULL); - pc->create_port(m_module); - } - - m_module->resize(); - - if (has_control_inputs()) - enable_controls_menuitem(); -} - - -bool -NodeController::has_control_inputs() -{ - for (PortModelList::const_iterator i = node_model()->ports().begin(); - i != node_model()->ports().end(); ++i) - if ((*i)->is_input() && (*i)->is_control()) - return true; - - return false; -} - - -void -NodeController::enable_controls_menuitem() -{ - m_controls_menuitem->property_sensitive() = true; -} - - -void -NodeController::disable_controls_menuitem() -{ - m_controls_menuitem->property_sensitive() = false; - - if (m_control_window != NULL) - m_control_window->hide(); -} - - - -} // namespace OmGtk - diff --git a/src/clients/gtk/NodeController.h b/src/clients/gtk/NodeController.h deleted file mode 100644 index ed2a6d59..00000000 --- a/src/clients/gtk/NodeController.h +++ /dev/null @@ -1,114 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 NODECONTROLLER_H -#define NODECONTROLLER_H - -#include -#include -#include "util/Path.h" -#include "GtkObjectController.h" - -using std::string; -using Om::Path; -using namespace LibOmClient; - -namespace LibOmClient { - class MetadataModel; - class NodeModel; - class PortModel; -} - -namespace OmGtk { - -class Controller; -class OmModule; -class NodeControlWindow; -class NodePropertiesWindow; -class PortController; -class OmFlowCanvas; - -/** Controller for a Node. - * - * \ingroup OmGtk - */ -class NodeController : public GtkObjectController -{ -public: - NodeController(NodeModel* model); - virtual ~NodeController(); - - virtual void destroy(); - - virtual void add_to_store(); - virtual void remove_from_store(); - - virtual void metadata_update(const string& key, const string& value); - - virtual void create_module(OmFlowCanvas* canvas); - - void set_path(const Path& new_path); - - virtual void add_port(PortModel* pm); - virtual void remove_port(const Path& path, bool resize_module) {} - - virtual void program_add(int bank, int program, const string& name) {} - virtual void program_remove(int bank, int program) {} - - OmModule* module() { return m_module; } - - void bridge_port(PortController* port) { m_bridge_port = port; } - PortController* as_port() { return m_bridge_port; } - - NodeModel* node_model() { return (NodeModel*)m_model; } - - NodeControlWindow* control_window() { return m_control_window; } - void control_window(NodeControlWindow* cw) { m_control_window = cw; } - - virtual void show_control_window(); - void show_rename_window(); - void show_properties_window(); - - bool has_control_inputs(); - - virtual void show_menu(GdkEventButton* event) - { m_menu.popup(event->button, event->time); } - - virtual void enable_controls_menuitem(); - virtual void disable_controls_menuitem(); - -protected: - void create_all_ports(); - - void on_menu_destroy(); - void on_menu_clone(); - void on_menu_learn(); - void on_menu_disconnect_all(); - - Gtk::Menu m_menu; - Glib::RefPtr m_controls_menuitem; - - OmModule* m_module; ///< View (module on a patch canvas) - - NodeControlWindow* m_control_window; - NodePropertiesWindow* m_properties_window; - PortController* m_bridge_port; -}; - - -} // namespace OmGtk - -#endif // NODECONTROLLER_H diff --git a/src/clients/gtk/NodePropertiesWindow.cpp b/src/clients/gtk/NodePropertiesWindow.cpp deleted file mode 100644 index 048f2513..00000000 --- a/src/clients/gtk/NodePropertiesWindow.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "NodePropertiesWindow.h" -#include -#include -#include "NodeModel.h" -#include "PluginModel.h" - -namespace OmGtk { -using std::string; - - -NodePropertiesWindow::NodePropertiesWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml) -: Gtk::Window(cobject) -{ - glade_xml->get_widget("node_properties_path_label", m_node_path_label); - glade_xml->get_widget("node_properties_polyphonic_checkbutton", m_node_polyphonic_toggle); - glade_xml->get_widget("node_properties_plugin_type_label", m_plugin_type_label); - glade_xml->get_widget("node_properties_plugin_uri_label", m_plugin_uri_label); - glade_xml->get_widget("node_properties_plugin_name_label", m_plugin_name_label); -} - - -/** Set the node this window is associated with. - * This function MUST be called before using this object in any way. - */ -void -NodePropertiesWindow::set_node(NodeModel* node_model) -{ - assert(node_model != NULL); - - m_node_model = node_model; - - set_title(node_model->path() + " Properties"); - - m_node_path_label->set_text(node_model->path()); - m_node_polyphonic_toggle->set_active(node_model->polyphonic()); - - const PluginModel* const pm = node_model->plugin(); - - m_plugin_type_label->set_text(pm->type_string()); - m_plugin_uri_label->set_text(pm->uri()); - m_plugin_name_label->set_text(pm->name()); -} - - -} // namespace OmGtk - diff --git a/src/clients/gtk/NodePropertiesWindow.h b/src/clients/gtk/NodePropertiesWindow.h deleted file mode 100644 index efff01bb..00000000 --- a/src/clients/gtk/NodePropertiesWindow.h +++ /dev/null @@ -1,55 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 NODEPROPERTIESWINDOW_H -#define NODEPROPERTIESWINDOW_H - -#include -#include - -namespace LibOmClient { class NodeModel; } -using namespace LibOmClient; - -namespace OmGtk { - - -/** 'New Patch' Window. - * - * Loaded by libglade as a derived object. - * - * \ingroup OmGtk - */ -class NodePropertiesWindow : public Gtk::Window -{ -public: - NodePropertiesWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); - - void set_node(NodeModel* node_model); - -private: - - NodeModel* m_node_model; - - Gtk::Label* m_node_path_label; - Gtk::CheckButton* m_node_polyphonic_toggle; - Gtk::Label* m_plugin_type_label; - Gtk::Label* m_plugin_uri_label; - Gtk::Label* m_plugin_name_label; -}; - -} // namespace OmGtk - -#endif // NODEPROPERTIESWINDOW_H diff --git a/src/clients/gtk/OmFlowCanvas.cpp b/src/clients/gtk/OmFlowCanvas.cpp deleted file mode 100644 index a7e41ea2..00000000 --- a/src/clients/gtk/OmFlowCanvas.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "OmFlowCanvas.h" -#include -#include -#include "Controller.h" -#include "PatchController.h" -#include "PatchModel.h" -#include "PatchWindow.h" -#include "LoadPluginWindow.h" -#include "LoadSubpatchWindow.h" -#include "NewSubpatchWindow.h" -#include "OmPort.h" -#include "NodeModel.h" -#include "OmModule.h" - - -namespace OmGtk { - - -OmFlowCanvas::OmFlowCanvas(PatchController* controller, int width, int height) -: FlowCanvas(width, height), - m_patch_controller(controller), - m_last_click_x(0), - m_last_click_y(0) -{ - assert(controller != NULL); - - Gtk::Menu::MenuList& items = m_menu.items(); - items.push_back(Gtk::Menu_Helpers::MenuElem("Load Plugin...", - sigc::mem_fun(this, &OmFlowCanvas::menu_load_plugin))); - items.push_back(Gtk::Menu_Helpers::MenuElem("Load Subpatch...", - sigc::mem_fun(this, &OmFlowCanvas::menu_load_subpatch))); - items.push_back(Gtk::Menu_Helpers::MenuElem("New Subpatch...", - sigc::mem_fun(this, &OmFlowCanvas::menu_create_subpatch))); -} - - -void -OmFlowCanvas::connect(const Port* src_port, const Port* dst_port) -{ - assert(src_port != NULL); - assert(dst_port != NULL); - - const OmPort* const src = static_cast(src_port); - const OmPort* const dst = static_cast(dst_port); - - // Midi binding/learn shortcut - if (src->model()->type() == PortModel::MIDI && - dst->model()->type() == PortModel::CONTROL) - { - // FIXME: leaks? - NodeModel* nm = new NodeModel(m_patch_controller->model()->base_path() - + src->name() + "-" + dst->name()); - PluginModel* pm = new PluginModel(PluginModel::Internal, "", "midi_control_in", ""); - nm->plugin(pm); - nm->x(dst->module()->property_x() - dst->module()->width() - 20); - nm->y(dst->module()->property_y()); - Controller::instance().create_node_from_model(nm); - Controller::instance().connect(src->model()->path(), nm->path() + "/MIDI In"); - Controller::instance().connect(nm->path() + "/Out (CR)", dst->model()->path()); - Controller::instance().midi_learn(nm->path()); - - // Set control node range to port's user range - - Controller::instance().set_port_value_queued(nm->path().base_path() + "Min", - atof(dst->model()->get_metadata("user-min").c_str())); - Controller::instance().set_port_value_queued(nm->path().base_path() + "Max", - atof(dst->model()->get_metadata("user-max").c_str())); - } else { - Controller::instance().connect(src->model()->path(), - dst->model()->path()); - } -} - - -void -OmFlowCanvas::disconnect(const Port* src_port, const Port* dst_port) -{ - assert(src_port != NULL); - assert(dst_port != NULL); - - Controller::instance().disconnect(((OmPort*)src_port)->model()->path(), - ((OmPort*)dst_port)->model()->path()); -} - - -bool -OmFlowCanvas::canvas_event(GdkEvent* event) -{ - assert(event != NULL); - - switch (event->type) { - - case GDK_BUTTON_PRESS: - if (event->button.button == 3) { - m_last_click_x = (int)event->button.x; - m_last_click_y = (int)event->button.y; - show_menu(event); - } - break; - - /*case GDK_KEY_PRESS: - if (event->key.keyval == GDK_Delete) - destroy_selected(); - break; - */ - - default: - break; - } - - return FlowCanvas::canvas_event(event); -} - - -void -OmFlowCanvas::destroy_selected() -{ - for (list::iterator m = m_selected_modules.begin(); m != m_selected_modules.end(); ++m) - Controller::instance().destroy(((OmModule*)(*m))->node()->path()); -} - - -void -OmFlowCanvas::menu_load_plugin() -{ - m_patch_controller->window()->load_plugin_window()->set_next_module_location( - m_last_click_x, m_last_click_y); - m_patch_controller->window()->load_plugin_window()->show(); -} - - -void -OmFlowCanvas::menu_load_subpatch() -{ - m_patch_controller->window()->load_subpatch_window()->set_next_module_location( - m_last_click_x, m_last_click_y); - m_patch_controller->window()->load_subpatch_window()->show(); -} - - -void -OmFlowCanvas::menu_create_subpatch() -{ - m_patch_controller->window()->new_subpatch_window()->set_next_module_location( - m_last_click_x, m_last_click_y); - m_patch_controller->window()->new_subpatch_window()->show(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/OmFlowCanvas.h b/src/clients/gtk/OmFlowCanvas.h deleted file mode 100644 index 2a553f5b..00000000 --- a/src/clients/gtk/OmFlowCanvas.h +++ /dev/null @@ -1,70 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 OMPATCHBAYAREA_H -#define OMPATCHBAYAREA_H - -#include -#include - - -using std::string; -using namespace LibFlowCanvas; - -using LibFlowCanvas::Port; - -namespace OmGtk { - -class OmModule; -class PatchController; - -/** Patch canvas widget. - * - * \ingroup OmGtk - */ -class OmFlowCanvas : public LibFlowCanvas::FlowCanvas -{ -public: - OmFlowCanvas(PatchController* controller, int width, int height); - - OmModule* find_module(const string& name) - { return (OmModule*)FlowCanvas::find_module(name); } - - void connect(const Port* src_port, const Port* dst_port); - void disconnect(const Port* src_port, const Port* dst_port); - - bool canvas_event(GdkEvent* event); - void destroy_selected(); - - void show_menu(GdkEvent* event) - { m_menu.popup(event->button.button, event->button.time); } - - void menu_load_plugin(); - void menu_load_subpatch(); - void menu_create_subpatch(); - -private: - PatchController* m_patch_controller; - int m_last_click_x; - int m_last_click_y; - - Gtk::Menu m_menu; -}; - - -} // namespace OmGtk - -#endif // OMPATCHBAYAREA_H diff --git a/src/clients/gtk/OmModule.cpp b/src/clients/gtk/OmModule.cpp deleted file mode 100644 index 3a31b7f3..00000000 --- a/src/clients/gtk/OmModule.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "OmModule.h" -#include -#include "Controller.h" -#include "OmFlowCanvas.h" -#include "PatchModel.h" -#include "NodeModel.h" -#include "OmPort.h" -#include "GladeFactory.h" -#include "RenameWindow.h" -#include "PatchController.h" -#include "PatchWindow.h" - -namespace OmGtk { - - -OmModule::OmModule(OmFlowCanvas* canvas, NodeController* node) -: LibFlowCanvas::Module(canvas, node->node_model()->name(), - node->node_model()->x(), node->node_model()->y()), - m_node(node) -{ - assert(m_node != NULL); - - /*if (node_model()->polyphonic() && node_model()->parent() != NULL - && node_model()->parent_patch()->poly() > 1) { - border_width(2.0); - }*/ - if (node->node_model()->polyphonic()) { - border_width(2.0); - } -} - - -void -OmModule::show_control_window() -{ - node()->show_control_window(); -} - - -void -OmModule::store_location() -{ - if (m_node->node_model()->x() == 0 || m_node->node_model()->y() == 0) - return; - - char temp_buf[16]; - - m_node->node_model()->x(property_x()); - snprintf(temp_buf, 16, "%f", m_node->node_model()->x()); - m_node->node_model()->set_metadata("module-x", temp_buf); // just in case? - Controller::instance().set_metadata(m_node->node_model()->path(), "module-x", temp_buf); - - m_node->node_model()->y(property_y()); - snprintf(temp_buf, 16, "%f", m_node->node_model()->y()); - m_node->node_model()->set_metadata("module-y", temp_buf); // just in case? - Controller::instance().set_metadata(m_node->node_model()->path(), "module-y", temp_buf); -} - - -void -OmModule::move_to(double x, double y) -{ - Module::move_to(x, y); - m_node->node_model()->x(x); - m_node->node_model()->y(y); - //store_location(); -} - -} // namespace OmGtk diff --git a/src/clients/gtk/OmModule.h b/src/clients/gtk/OmModule.h deleted file mode 100644 index ebb36fe6..00000000 --- a/src/clients/gtk/OmModule.h +++ /dev/null @@ -1,77 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 OMMODULE_H -#define OMMODULE_H - -#include -#include -#include -#include "NodeController.h" -using std::string; - -namespace LibOmClient { -class PortModel; -class NodeModel; -class ControlModel; -} -using namespace LibOmClient; - -namespace OmGtk { - -class PatchController; -class OmFlowCanvas; -class OmPort; - - -/** A module in a patch. - * - * This base class is extended for various types of modules - SubpatchModule, - * DSSIModule, etc. - * - * \ingroup OmGtk - */ -class OmModule : public LibFlowCanvas::Module -{ -public: - OmModule(OmFlowCanvas* canvas, NodeController* node); - virtual ~OmModule() {} - - virtual OmPort* port(const string& port_name) { - return (OmPort*)Module::port(port_name); - } - - virtual void store_location(); - void move_to(double x, double y); - - void on_right_click(GdkEventButton* event) { m_node->show_menu(event); } - - void show_control_window(); - - NodeController* node() const { return m_node; } - -protected: - virtual void on_double_click(GdkEventButton* ev) { show_control_window(); } - virtual void on_middle_click(GdkEventButton* ev) { show_control_window(); } - - NodeController* m_node; -}; - - -} // namespace OmGtk - -#endif // OMMODULE_H diff --git a/src/clients/gtk/OmPort.cpp b/src/clients/gtk/OmPort.cpp deleted file mode 100644 index b43b8294..00000000 --- a/src/clients/gtk/OmPort.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "OmPort.h" -#include -#include -#include "PortModel.h" -#include "OmModule.h" -#include "ControlModel.h" -#include "Configuration.h" -#include "App.h" -using std::cerr; using std::endl; - -using namespace LibOmClient; - -namespace OmGtk { - -OmPort::OmPort(OmModule* module, PortModel* pm) -: Port(module, pm->name(), pm->is_input(), App::instance().configuration()->get_port_color(pm)), - m_port_model(pm) -{ - assert(module != NULL); - assert(m_port_model != NULL); -} - -#if 0 -void -OmPort::set_name(const string& n) -{ - cerr << "********** OmPort::set_name broken **********************" << endl; - - /* FIXME: move to PortController - string new_path = OmPath::parent(m_port_model->path()) +"/"+ n; - - for (list::iterator i = m_control_panels.begin(); i != m_control_panels.end(); ++i) - (*i)->rename_port(m_port_model->path(), new_path); - - Port::set_name(n); - m_port_model->path(new_path); - */ -} -#endif - -} // namespace OmGtk diff --git a/src/clients/gtk/OmPort.h b/src/clients/gtk/OmPort.h deleted file mode 100644 index 69a867d5..00000000 --- a/src/clients/gtk/OmPort.h +++ /dev/null @@ -1,59 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 OMPORT_H -#define OMPORT_H - -#include -#include -#include - -namespace LibOmClient { class PortModel; } -using namespace LibOmClient; -using namespace LibFlowCanvas; -using std::string; using std::list; - -namespace OmGtk { - -class FlowCanvas; -class PatchController; -class PatchWindow; -class OmModule; - - -/** A Port on an OmModule. - * - * \ingroup OmGtk - */ -class OmPort : public LibFlowCanvas::Port -{ -public: - OmPort(OmModule* module, PortModel* pm); - - virtual ~OmPort() {} - - //void set_name(const string& n); - - PortModel* model() const { return m_port_model; } - -private: - PortModel* m_port_model; -}; - - -} // namespace OmGtk - -#endif // OMPORT_H diff --git a/src/clients/gtk/PatchController.cpp b/src/clients/gtk/PatchController.cpp deleted file mode 100644 index 83ba62d9..00000000 --- a/src/clients/gtk/PatchController.cpp +++ /dev/null @@ -1,685 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "PatchController.h" -#include -#include -#include "GladeFactory.h" -#include "Configuration.h" -#include "util/Path.h" -#include "ControlPanel.h" -#include "ConnectionModel.h" -#include "OmFlowCanvas.h" -#include "PatchView.h" -#include "flowcanvas/Module.h" -#include "PluginModel.h" -#include "Controller.h" -#include "SubpatchModule.h" -#include "DSSIModule.h" -#include "PatchWindow.h" -#include "NodeModel.h" -#include "OmModule.h" -#include "OmPort.h" -#include "ControlModel.h" -#include "NodeControlWindow.h" -#include "NodeController.h" -#include "PortController.h" -#include "App.h" -#include "PatchTreeWindow.h" -#include "DSSIController.h" -#include "PatchModel.h" -#include "Store.h" - -using std::cerr; using std::cout; using std::endl; -using Om::Path; -using namespace LibOmClient; - -namespace OmGtk { - - -PatchController::PatchController(PatchModel* model) -: NodeController(model), - m_window(NULL), - m_patch_view(NULL), - m_module_x(0), - m_module_y(0) -{ - assert(model->path().length() > 0); - assert(model->parent() == NULL); - assert(model->controller() == this); // NodeController() does this - - if (model->path() != "/") { - PatchController* parent = Store::instance().patch(model->path().parent()); - if (parent != NULL) - parent->add_subpatch(this); - else - cerr << "[PatchController] " << path() << " ERROR: Parent not found." << endl; - } -} - - -PatchController::~PatchController() -{ - if (m_patch_view != NULL) { - claim_patch_view(); - m_patch_view->hide(); - delete m_patch_view; - m_patch_view = NULL; - } - - if (m_control_window != NULL) { - m_control_window->hide(); - delete m_control_window; - m_control_window = NULL; - } - - if (m_window != NULL) { - m_window->hide(); - delete m_window; - m_window = NULL; - } -} - - -void -PatchController::add_to_store() -{ - Store::instance().add_object(this); -} - - -void -PatchController::remove_from_store() -{ - Store::instance().remove_object(this); -} - - -void -PatchController::clear() -{ - // Destroy model - // Destroying nodes removes models from patch model, which invalidates any - // iterator to nodes, so avoid the iterator problem by doing it this way: - const NodeModelMap& nodes = patch_model()->nodes(); - size_t remaining = nodes.size(); - - while (remaining > 0) { - NodeController* const nc = (NodeController*)(*nodes.begin()).second->controller(); - assert(nc != NULL); - nc->destroy(); - assert(nodes.size() == remaining - 1); - --remaining; - } - assert(nodes.empty()); - - patch_model()->clear(); - - if (m_patch_view != NULL) { - assert(m_patch_view->canvas() != NULL); - m_patch_view->canvas()->destroy(); - } -} - - -void -PatchController::destroy() -{ - // Destroying nodes removes models from patch model, which invalidates any - // iterator to nodes, so avoid the iterator problem by doing it this way: - const NodeModelMap& nodes = patch_model()->nodes(); - size_t remaining = nodes.size(); - - while (remaining > 0) { - NodeController* const nc = (NodeController*) - (*nodes.begin()).second->controller(); - assert(nc != NULL); - nc->destroy(); - assert(nodes.size() == remaining - 1); - --remaining; - } - assert(nodes.empty()); - - //App::instance().remove_patch(this); - App::instance().patch_tree()->remove_patch(path()); - - // Delete all children models - //patch_model()->clear(); - - // Remove self from object store - Store::instance().remove_object(this); - - // Delete self from parent (this will delete model) - if (patch_model()->parent() != NULL) { - PatchController* const parent = (PatchController*)patch_model()->parent()->controller(); - assert(parent != NULL); - parent->remove_node(name()); - } else { - delete m_model; - } -} - - -void -PatchController::metadata_update(const string& key, const string& value) -{ - NodeController::metadata_update(key, value); - - if (key == "filename") - patch_model()->filename(value); -} - - -void -PatchController::set_path(const Path& new_path) -{ - assert(m_model != NULL); - Path old_path = path(); - - // Rename nodes - for (NodeModelMap::const_iterator i = patch_model()->nodes().begin(); - i != patch_model()->nodes().end(); ++i) { - const NodeModel* const nm = (*i).second; - assert(nm != NULL); - NodeController* const nc = ((NodeController*)nm->controller()); - assert(nc != NULL); - nc->set_path(new_path.base_path() + nc->node_model()->name()); - } - -#ifdef DEBUG - // Be sure ports were renamed by their bridge nodes - for (list::const_iterator i = node_model()->ports().begin(); - i != node_model()->ports().end(); ++i) { - GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); - assert(pc != NULL); - assert(pc->path().parent()== new_path); - } -#endif - - App::instance().patch_tree()->patch_renamed(old_path, new_path); - - if (m_window != NULL) - m_window->patch_renamed(new_path); - - if (m_control_window != NULL) - m_control_window->set_title(new_path + " Controls"); - - if (m_module != NULL) { - assert(m_module->canvas() != NULL); - m_module->canvas()->rename_module(old_path.name(), new_path.name()); - assert(m_module->name() == new_path.name()); - } - - PatchController* parent = dynamic_cast( - patch_model()->parent()->controller()); - - if (parent != NULL && parent->window() != NULL) - parent->window()->node_renamed(old_path, new_path); - - remove_from_store(); - GtkObjectController::set_path(new_path); - add_to_store(); - - if (old_path.name() != new_path.name()) - parent->patch_model()->rename_node(old_path, new_path); -} - - -void -PatchController::enable() -{ - if (m_patch_view != NULL) - m_patch_view->enabled(true); - - patch_model()->enabled(true); - - App::instance().patch_tree()->patch_enabled(m_model->path()); -} - - -void -PatchController::disable() -{ - if (m_patch_view != NULL) - m_patch_view->enabled(false); - - patch_model()->enabled(false); - - App::instance().patch_tree()->patch_disabled(m_model->path()); -} - - -void -PatchController::create_module(OmFlowCanvas* canvas) -{ - //cerr << "Creating patch module " << m_model->path() << endl; - - assert(canvas != NULL); - assert(m_module == NULL); - - m_module = new SubpatchModule(canvas, this); - - - m_menu.remove(m_menu.items()[4]); - - // Add navigation menu items - Gtk::Menu::MenuList& items = m_menu.items(); - items.push_front(Gtk::Menu_Helpers::SeparatorElem()); - items.push_front(Gtk::Menu_Helpers::MenuElem("Browse to Patch", - sigc::mem_fun((SubpatchModule*)m_module, &SubpatchModule::browse_to_patch))); - items.push_front(Gtk::Menu_Helpers::MenuElem("Open Patch in New Window", - sigc::mem_fun(this, &PatchController::show_patch_window))); - - create_all_ports(); - - m_module->move_to(node_model()->x(), node_model()->y()); - m_module->store_location(); -} - - -void -PatchController::create_view() -{ - assert(m_patch_view == NULL); - - Glib::RefPtr xml = GladeFactory::new_glade_reference(); - - xml->get_widget_derived("patch_view_vbox", m_patch_view); - assert(m_patch_view != NULL); - m_patch_view->patch_controller(this); - assert(m_patch_view->canvas() != NULL); - - // Create modules for nodes - for (NodeModelMap::const_iterator i = patch_model()->nodes().begin(); - i != patch_model()->nodes().end(); ++i) { - - NodeModel* const nm = (*i).second; - - string val = nm->get_metadata("module-x"); - if (val != "") - nm->x(atof(val.c_str())); - val = nm->get_metadata("module-y"); - if (val != "") - nm->y(atof(val.c_str())); - - /* Set sane default coordinates if not set already yet */ - if (nm->x() == 0.0f && nm->y() == 0.0f) { - int x, y; - get_new_module_location(x, y); - nm->x(x); - nm->y(y); - } - - NodeController* nc = ((NodeController*)nm->controller()); - assert(nc != NULL); - if (nc->module() == NULL); - nc->create_module(m_patch_view->canvas()); - assert(nc->module() != NULL); - m_patch_view->canvas()->add_module(nc->module()); - } - - // Create connections - for (list::const_iterator i = patch_model()->connections().begin(); - i != patch_model()->connections().end(); ++i) { - create_connection(*i); - } - - // Set run checkbox - m_patch_view->enabled(patch_model()->enabled()); -} - - -/** Create a connection in the view (canvas). - */ -void -PatchController::create_connection(const ConnectionModel* cm) -{ - m_patch_view->canvas()->add_connection( - cm->src_port_path().parent().name(), - cm->src_port_path().name(), - cm->dst_port_path().parent().name(), - cm->dst_port_path().name()); - - // Disable control slider from destination node control window - - PortController* p = Store::instance().port(cm->dst_port_path()); - assert(p != NULL); - - if (p->control_panel() != NULL) - p->control_panel()->disable_port(p->path()); - // FIXME: don't use canvas as a model (search object store) - /*OmModule* m = (OmModule*)m_patch_view->canvas()->find_module( - cm->dst_port_path().parent().name()); - - if (m != NULL) { - OmPort* p = m->port(cm->dst_port_path().name()); - if (p != NULL && p->connections().size() == 1) { - p->model()->connected(true); - assert(m->node_model()->controller() != NULL); - NodeControlWindow* cw = (((NodeController*) - m->node_model()->controller())->control_window()); - if (cw != NULL) - cw->control_panel()->disable_port(cm->dst_port_path()); - } - }*/ -} - - -/** Add a subpatch to this patch. - */ -void -PatchController::add_subpatch(PatchController* patch) -{ - assert(patch != NULL); - assert(patch->patch_model() != NULL); - assert(patch->patch_model()->parent() == NULL); - - /*if (pm->x() == 0 && pm->y() == 0) { - int x, y; - parent_pc->get_new_module_location(x, y); - pm->x(x); - pm->y(y); - }*/ - - patch_model()->add_node(patch->patch_model()); - - if (m_patch_view != NULL) { - patch->create_module(m_patch_view->canvas()); - m_patch_view->canvas()->add_module(patch->module()); - patch->module()->resize(); - } -} - - -void -PatchController::add_node(NodeModel* nm) -{ - assert(nm != NULL); - assert(nm->parent() == NULL); - assert(nm->path().parent() == m_model->path()); - - if (patch_model()->get_node(nm->name()) != NULL) { - // Node already exists, ignore - delete nm; - } else { - // FIXME: Should PatchController really be responsible for creating these? - NodeController* nc = NULL; - - if (nm->plugin()->type() == PluginModel::DSSI) - nc = new DSSIController(nm); - else - nc = new NodeController(nm); - - assert(nc != NULL); - assert(nm->controller() == nc); - - // Check if this is a bridge node - PortModel* const pm = patch_model()->get_port(nm->path().name()); - if (pm != NULL) { - cerr << "Bridge node." << endl; - PortController* pc = ((PortController*)pm->controller()); - assert(pc != NULL); - nc->bridge_port(pc); - } - - nc->add_to_store(); - patch_model()->add_node(nm); - - if (m_patch_view != NULL) { - - int x, y; - get_new_module_location(x, y); - nm->x(x); - nm->y(y); - - // Set zoom to 1.0 so module isn't messed up (Death to GnomeCanvas) - float old_zoom = m_patch_view->canvas()->zoom(); - if (old_zoom != 1.0) - m_patch_view->canvas()->zoom(1.0); - - if (nc->module() == NULL) - nc->create_module(m_patch_view->canvas()); - assert(nc->module() != NULL); - m_patch_view->canvas()->add_module(nc->module()); - nc->module()->resize(); - - // Reset zoom - if (old_zoom != 1.0) { - m_patch_view->canvas()->zoom(old_zoom); - nc->module()->zoom(old_zoom); - } - } - } -} - - -/** Removes a node from this patch. - */ -void -PatchController::remove_node(const string& name) -{ - assert(name.find("/") == string::npos); - - // Update breadcrumbs if necessary - if (m_window != NULL) - m_window->node_removed(name); - - if (m_patch_view != NULL) { - assert(m_patch_view->canvas() != NULL); - m_patch_view->canvas()->remove_module(name); - } - - patch_model()->remove_node(name); -} - - -/** Add a port to this patch. - * - * Will add a port to the subpatch module and the control window, if they - * exist. - */ -void -PatchController::add_port(PortModel* pm) -{ - assert(pm != NULL); - assert(pm->parent() == NULL); - - //cerr << "[PatchController] Adding port " << pm->path() << endl; - - if (patch_model()->get_port(pm->name()) != NULL) { - cerr << "[PatchController] Ignoring duplicate port " - << pm->path() << endl; - delete pm; - return; - } - - node_model()->add_port(pm); - PortController* pc = new PortController(pm); - - // Handle bridge ports/nodes (this is uglier than it should be) - NodeController* nc = Store::instance().node(pm->path()); - if (nc != NULL) - nc->bridge_port(pc); - - if (m_module != NULL) { - pc->create_port(m_module); - m_module->resize(); - } - - if (m_control_window != NULL) { - assert(m_control_window->control_panel() != NULL); - m_control_window->control_panel()->add_port(pc); - m_control_window->resize(); - } - - // Enable "Controls" menuitem on module and patch window, if necessary - if (has_control_inputs()) - enable_controls_menuitem(); -} - - -/** Removes a port from this patch - */ -void -PatchController::remove_port(const Path& path, bool resize_module) -{ - assert(path.parent() == m_model->path()); - - //cerr << "[PatchController] Removing port " << path << endl; - - /* FIXME - if (m_control_panel != NULL) { - m_control_panel->remove_port(path); - if (m_control_window != NULL) { - assert(m_control_window->control_panel() == m_control_panel); - m_control_window->resize(); - } - }*/ - - // Remove port on module - if (m_module != NULL) { - assert(m_module->port(path.name()) != NULL); - m_module->remove_port(path.name(), resize_module); - assert(m_module->port(path.name()) == NULL); - } - - patch_model()->remove_port(path); - assert(patch_model()->get_port(path.name()) == NULL); - - // Disable "Controls" menuitem on module and patch window, if necessary - if (!has_control_inputs()) - disable_controls_menuitem(); -} - - -void -PatchController::connection(ConnectionModel* const cm) -{ - assert(cm != NULL); - - patch_model()->add_connection(cm); - - if (m_patch_view != NULL) - create_connection(cm); -} - - - -void -PatchController::disconnection(const Path& src_port_path, const Path& dst_port_path) -{ - const string& src_node_name = src_port_path.parent().name(); - const string& src_port_name = src_port_path.name(); - const string& dst_node_name = dst_port_path.parent().name(); - const string& dst_port_name = dst_port_path.name(); - - if (m_patch_view != NULL) - m_patch_view->canvas()->remove_connection( - src_node_name, src_port_name, dst_node_name, dst_port_name); - - patch_model()->remove_connection(src_port_path, dst_port_path); - - // Enable control slider in destination node control window - PortController* p = Store::instance().port(dst_port_path); - assert(p != NULL); - - if (p->control_panel() != NULL) - p->control_panel()->enable_port(p->path()); -} - - -/** Try to guess a suitable location for a new module. - */ -void -PatchController::get_new_module_location(int& x, int& y) -{ - assert(m_patch_view != NULL); - assert(m_patch_view->canvas() != NULL); - m_patch_view->canvas()->get_scroll_offsets(x, y); - x += 20; - y += 20; -} - - -void -PatchController::show_patch_window() -{ - if (m_window == NULL) { - Glib::RefPtr xml = GladeFactory::new_glade_reference(); - - xml->get_widget_derived("patch_win", m_window); - assert(m_window != NULL); - - if (m_patch_view == NULL) - create_view(); - - m_window->patch_controller(this); - } - - assert(m_window != NULL); - m_window->present(); -} - - -/** Become the parent of the patch view. - * - * Steals the view away from whatever window is currently showing it. - */ -void -PatchController::claim_patch_view() -{ - assert(m_patch_view != NULL); - - m_patch_view->hide(); - m_patch_view->reparent(m_patch_view_bin); -} - - -void -PatchController::show_control_window() -{ - assert(patch_model() != NULL); - - if (m_control_window == NULL) - m_control_window = new NodeControlWindow(this, patch_model()->poly()); - - if (m_control_window->control_panel()->num_controls() > 0) - m_control_window->present(); -} - - -void -PatchController::enable_controls_menuitem() -{ - if (m_window != NULL) - m_window->menu_view_control_window()->property_sensitive() = true; - - NodeController::enable_controls_menuitem(); -} - - -void -PatchController::disable_controls_menuitem() -{ - if (m_window != NULL) - m_window->menu_view_control_window()->property_sensitive() = false; - - NodeController::disable_controls_menuitem(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/PatchController.h b/src/clients/gtk/PatchController.h deleted file mode 100644 index de4af5e4..00000000 --- a/src/clients/gtk/PatchController.h +++ /dev/null @@ -1,127 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 PATCHCONTROLLER_H -#define PATCHCONTROLLER_H - -#include -#include -#include "NodeController.h" - -namespace LibOmClient { -class PatchModel; -class NodeModel; -class PortModel; -class ControlModel; -class ConnectionModel; -} - -using std::string; -using namespace LibOmClient; - -namespace OmGtk { - -class PatchWindow; -class SubpatchModule; -class Controller; -class OmFlowCanvas; -class NodeControlWindow; -class ControlPanel; -class PatchView; -class NodeController; - - -/** Controller for a patch. - * - * A patch is different from a port or node because there are two - * representations in the Gtk client - the window and the module in the parent - * patch (if applicable). So, this is a master class that contains both of - * those representations, and acts as the recipient of all patch related - * events (being the controller). - * - * \ingroup OmGtk - */ -class PatchController : public NodeController -{ -public: - PatchController(PatchModel* model); - virtual ~PatchController(); - - virtual void add_to_store(); - virtual void remove_from_store(); - - virtual void destroy(); - - virtual void metadata_update(const string& key, const string& value); - - void add_node(NodeModel* nm); - void remove_node(const string& name); - - virtual void add_port(PortModel* pm); - virtual void remove_port(const Path& path, bool resize_module); - - void connection(ConnectionModel* const cm); - void disconnection(const Path& src_port_path, const Path& dst_port_path); - void clear(); - - void add_subpatch(PatchController* patch); - - void get_new_module_location(int& x, int& y); - - void show_control_window(); - void show_patch_window(); - - void claim_patch_view(); - - void create_module(OmFlowCanvas* canvas); - void create_view(); - - PatchView* view() const { return m_patch_view; } - PatchWindow* window() const { return m_window; } - void window(PatchWindow* pw) { m_window = pw; } - - inline string name() const { return m_model->name(); } - inline const string& path() const { return m_model->path(); } - - void set_path(const Path& new_path); - - void enable(); - void disable(); - - PatchModel* patch_model() const { return (PatchModel*)m_model; } - - void enable_controls_menuitem(); - void disable_controls_menuitem(); - -private: - void create_connection(const ConnectionModel* cm); - - PatchWindow* m_window; ///< Window currently showing this patch - PatchView* m_patch_view; ///< View (canvas) of this patch - - /** Invisible bin used to store patch view when not shown by a patch window */ - Gtk::Alignment m_patch_view_bin; - - // Coordinates for next added plugin (used by canvas menu) - // 0 means "not set", ie guess at the best location - int m_module_x; - int m_module_y; -}; - - -} // namespace OmGtk - -#endif // PATCHCONTROLLER_H diff --git a/src/clients/gtk/PatchDescriptionWindow.cpp b/src/clients/gtk/PatchDescriptionWindow.cpp deleted file mode 100644 index d10a9c0e..00000000 --- a/src/clients/gtk/PatchDescriptionWindow.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "PatchDescriptionWindow.h" -#include -#include "PatchModel.h" - -namespace OmGtk { -using std::string; - - -PatchDescriptionWindow::PatchDescriptionWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml) -: Gtk::Window(cobject) -{ - glade_xml->get_widget("description_author_entry", m_author_entry); - glade_xml->get_widget("description_description_textview", m_textview); - glade_xml->get_widget("description_cancel_button", m_cancel_button); - glade_xml->get_widget("description_ok_button", m_ok_button); - - m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &PatchDescriptionWindow::cancel_clicked)); - m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &PatchDescriptionWindow::ok_clicked)); -} - - -/** Set the patch model this description is for. - * - * This function is a "post-constructor" - it MUST be called before using - * the window in any way. - */ -void -PatchDescriptionWindow::patch_model(PatchModel* patch_model) -{ - property_title() = patch_model->path() + " Properties"; - m_patch_model = patch_model; - m_author_entry->set_text(m_patch_model->get_metadata("author")); - m_textview->get_buffer()->set_text(m_patch_model->get_metadata("description")); -} - - -void -PatchDescriptionWindow::cancel_clicked() -{ - m_author_entry->set_text(m_patch_model->get_metadata("author")); - m_textview->get_buffer()->set_text(m_patch_model->get_metadata("description")); - hide(); -} - - -void -PatchDescriptionWindow::ok_clicked() -{ - m_patch_model->set_metadata("author", m_author_entry->get_text()); - m_patch_model->set_metadata("description", m_textview->get_buffer()->get_text()); - hide(); -} - - - -} // namespace OmGtk diff --git a/src/clients/gtk/PatchDescriptionWindow.h b/src/clients/gtk/PatchDescriptionWindow.h deleted file mode 100644 index 7c00faab..00000000 --- a/src/clients/gtk/PatchDescriptionWindow.h +++ /dev/null @@ -1,59 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 PATCHDESCRIPTIONWINDOW_H -#define PATCHDESCRIPTIONWINDOW_H - -#include -#include -#include -using std::string; - -namespace LibOmClient { class PatchModel; } -using LibOmClient::PatchModel; - -namespace OmGtk { - - -/** Patch Description Window. - * - * Loaded by libglade as a derived object. - * - * \ingroup OmGtk - */ -class PatchDescriptionWindow : public Gtk::Window -{ -public: - PatchDescriptionWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); - - void patch_model(PatchModel* patch_model); - - void cancel_clicked(); - void ok_clicked(); - -private: - PatchModel* m_patch_model; - - Gtk::Entry* m_author_entry; - Gtk::TextView* m_textview; - Gtk::Button* m_cancel_button; - Gtk::Button* m_ok_button; -}; - - -} // namespace OmGtk - -#endif // PATCHDESCRIPTIONWINDOW_H diff --git a/src/clients/gtk/PatchTreeWindow.cpp b/src/clients/gtk/PatchTreeWindow.cpp deleted file mode 100644 index 065f4d6a..00000000 --- a/src/clients/gtk/PatchTreeWindow.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "PatchTreeWindow.h" -#include "Controller.h" -#include "PatchController.h" -#include "PatchWindow.h" -#include "SubpatchModule.h" -#include "PatchModel.h" -#include "util/Path.h" - -using Om::Path; - -namespace OmGtk { - - -PatchTreeWindow::PatchTreeWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml) -: Gtk::Window(cobject), - m_enable_signal(true) -{ - xml->get_widget_derived("patches_treeview", m_patches_treeview); - - m_patch_treestore = Gtk::TreeStore::create(m_patch_tree_columns); - m_patches_treeview->set_window(this); - m_patches_treeview->set_model(m_patch_treestore); - Gtk::TreeViewColumn* name_col = Gtk::manage(new Gtk::TreeViewColumn( - "Patch", m_patch_tree_columns.name_col)); - Gtk::TreeViewColumn* enabled_col = Gtk::manage(new Gtk::TreeViewColumn( - "Run", m_patch_tree_columns.enabled_col)); - name_col->set_resizable(true); - name_col->set_expand(true); - - m_patches_treeview->append_column(*name_col); - m_patches_treeview->append_column(*enabled_col); - Gtk::CellRendererToggle* enabled_renderer = dynamic_cast( - m_patches_treeview->get_column_cell_renderer(1)); - enabled_renderer->property_activatable() = true; - - m_patch_tree_selection = m_patches_treeview->get_selection(); - - //m_patch_tree_selection->signal_changed().connect( - // sigc::mem_fun(this, &PatchTreeWindow::event_patch_selected)); - m_patches_treeview->signal_row_activated().connect( - sigc::mem_fun(this, &PatchTreeWindow::event_patch_activated)); - enabled_renderer->signal_toggled().connect( - sigc::mem_fun(this, &PatchTreeWindow::event_patch_enabled_toggled)); - - m_patches_treeview->columns_autosize(); -} - - -void -PatchTreeWindow::add_patch(PatchController* pc) -{ - PatchModel* const pm = pc->patch_model(); - - if (pm->parent() == NULL) { - Gtk::TreeModel::iterator iter = m_patch_treestore->append(); - Gtk::TreeModel::Row row = *iter; - if (pm->path() == "/") { - string root_name = Controller::instance().engine_url(); - // Hack off trailing '/' if it's there (ugly) - //if (root_name.substr(root_name.length()-1,1) == "/") - // root_name = root_name.substr(0, root_name.length()-1); - //root_name.append(":/"); - row[m_patch_tree_columns.name_col] = root_name; - } else { - row[m_patch_tree_columns.name_col] = pm->path().name(); - } - row[m_patch_tree_columns.enabled_col] = false; - row[m_patch_tree_columns.patch_controller_col] = pc; - m_patches_treeview->expand_row(m_patch_treestore->get_path(iter), true); - } else { - Gtk::TreeModel::Children children = m_patch_treestore->children(); - Gtk::TreeModel::iterator c = find_patch(children, pm->parent()->path()); - - if (c != children.end()) { - Gtk::TreeModel::iterator iter = m_patch_treestore->append(c->children()); - Gtk::TreeModel::Row row = *iter; - row[m_patch_tree_columns.name_col] = pm->path().name(); - row[m_patch_tree_columns.enabled_col] = false; - row[m_patch_tree_columns.patch_controller_col] = pc; - m_patches_treeview->expand_row(m_patch_treestore->get_path(iter), true); - } - } -} - - -void -PatchTreeWindow::remove_patch(const Path& path) -{ - Gtk::TreeModel::iterator i = find_patch(m_patch_treestore->children(), path); - if (i != m_patch_treestore->children().end()) - m_patch_treestore->erase(i); -} - - -Gtk::TreeModel::iterator -PatchTreeWindow::find_patch(Gtk::TreeModel::Children root, const Path& path) -{ - PatchController* pc = NULL; - - for (Gtk::TreeModel::iterator c = root.begin(); c != root.end(); ++c) { - pc = (*c)[m_patch_tree_columns.patch_controller_col]; - if (pc->model()->path() == path) { - return c; - } else if ((*c)->children().size() > 0) { - Gtk::TreeModel::iterator ret = find_patch(c->children(), path); - if (ret != c->children().end()) - return ret; - } - } - return root.end(); -} - -/* -void -PatchTreeWindow::event_patch_selected() -{ - Gtk::TreeModel::iterator active = m_patch_tree_selection->get_selected(); - if (active) { - Gtk::TreeModel::Row row = *active; - PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; - } -} -*/ - - -/** Show the context menu for the selected patch in the patches treeview. - */ -void -PatchTreeWindow::show_patch_menu(GdkEventButton* ev) -{ - Gtk::TreeModel::iterator active = m_patch_tree_selection->get_selected(); - if (active) { - Gtk::TreeModel::Row row = *active; - PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; - if (pc != NULL) - pc->show_menu(ev); - } -} - - -void -PatchTreeWindow::event_patch_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col) -{ - Gtk::TreeModel::iterator active = m_patch_treestore->get_iter(path); - Gtk::TreeModel::Row row = *active; - PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; - - pc->show_patch_window(); -} - - -void -PatchTreeWindow::event_patch_enabled_toggled(const Glib::ustring& path_str) -{ - Gtk::TreeModel::Path path(path_str); - Gtk::TreeModel::iterator active = m_patch_treestore->get_iter(path); - Gtk::TreeModel::Row row = *active; - - PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; - Glib::ustring patch_path = pc->model()->path(); - - assert(pc != NULL); - - if ( ! pc->patch_model()->enabled()) { - if (m_enable_signal) - Controller::instance().enable_patch(patch_path); - pc->enable(); - row[m_patch_tree_columns.enabled_col] = true; - } else { - if (m_enable_signal) - Controller::instance().disable_patch(patch_path); - pc->disable(); - row[m_patch_tree_columns.enabled_col] = false; - } -} - - -void -PatchTreeWindow::patch_enabled(const Path& path) -{ - m_enable_signal = false; - - Gtk::TreeModel::iterator i - = find_patch(m_patch_treestore->children(), path); - - if (i != m_patch_treestore->children().end()) { - Gtk::TreeModel::Row row = *i; - row[m_patch_tree_columns.enabled_col] = true; - } else { - cerr << "[PatchTreeWindow] Unable to find patch " << path << endl; - } - - m_enable_signal = true; -} - - -void -PatchTreeWindow::patch_disabled(const Path& path) -{ - m_enable_signal = false; - - Gtk::TreeModel::iterator i - = find_patch(m_patch_treestore->children(), path); - - if (i != m_patch_treestore->children().end()) { - Gtk::TreeModel::Row row = *i; - row[m_patch_tree_columns.enabled_col] = false; - } else { - cerr << "[PatchTreeWindow] Unable to find patch " << path << endl; - } - - m_enable_signal = true; -} - - -void -PatchTreeWindow::patch_renamed(const Path& old_path, const Path& new_path) -{ - m_enable_signal = false; - - Gtk::TreeModel::iterator i - = find_patch(m_patch_treestore->children(), old_path); - - if (i != m_patch_treestore->children().end()) { - Gtk::TreeModel::Row row = *i; - row[m_patch_tree_columns.name_col] = new_path.name(); - } else { - cerr << "[PatchTreeWindow] Unable to find patch " << old_path << endl; - } - - m_enable_signal = true; -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/PatchTreeWindow.h b/src/clients/gtk/PatchTreeWindow.h deleted file mode 100644 index 3177e5e2..00000000 --- a/src/clients/gtk/PatchTreeWindow.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 PATCHTREEWINDOW_H -#define PATCHTREEWINDOW_H - -#include -#include -#include "util/Path.h" - - -using namespace Om; -using Om::Path; - -namespace OmGtk { - -class PatchWindow; -class PatchController; -class PatchTreeView; - - -/** Window with a TreeView of all loaded patches. - * - * \ingroup OmGtk - */ -class PatchTreeWindow : public Gtk::Window -{ -public: - PatchTreeWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); - - void patch_enabled(const Path& path); - void patch_disabled(const Path& path); - void patch_renamed(const Path& old_path, const Path& new_path); - - void add_patch(PatchController* pc); - void remove_patch(const Path& path); - void show_patch_menu(GdkEventButton* ev); - -protected: - //void event_patch_selected(); - void event_patch_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col); - void event_patch_enabled_toggled(const Glib::ustring& path_str); - - Gtk::TreeModel::iterator find_patch(Gtk::TreeModel::Children root, const Path& path); - - PatchTreeView* m_patches_treeview; - - struct PatchTreeModelColumns : public Gtk::TreeModel::ColumnRecord - { - PatchTreeModelColumns() - { add(name_col); add(enabled_col); add(patch_controller_col); } - - Gtk::TreeModelColumn name_col; - Gtk::TreeModelColumn enabled_col; - Gtk::TreeModelColumn patch_controller_col; - }; - - bool m_enable_signal; - PatchTreeModelColumns m_patch_tree_columns; - Glib::RefPtr m_patch_treestore; - Glib::RefPtr m_patch_tree_selection; -}; - - -/** Derived TreeView class to support context menus for patches */ -class PatchTreeView : public Gtk::TreeView -{ -public: - PatchTreeView(BaseObjectType* cobject, const Glib::RefPtr& xml) - : Gtk::TreeView(cobject) - {} - - void set_window(PatchTreeWindow* win) { m_window = win; } - - bool on_button_press_event(GdkEventButton* ev) { - bool ret = Gtk::TreeView::on_button_press_event(ev); - - if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3)) - m_window->show_patch_menu(ev); - - return ret; - } - -private: - PatchTreeWindow* m_window; - -}; // struct PatchTreeView - - -} // namespace OmGtk - -#endif // PATCHTREEWINDOW_H diff --git a/src/clients/gtk/PatchView.cpp b/src/clients/gtk/PatchView.cpp deleted file mode 100644 index e89428e9..00000000 --- a/src/clients/gtk/PatchView.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "PatchView.h" -#include -#include -#include -#include "App.h" -#include "OmFlowCanvas.h" -#include "PatchController.h" -#include "LoadPluginWindow.h" -#include "PatchModel.h" -#include "NewSubpatchWindow.h" -#include "LoadSubpatchWindow.h" -#include "NodeControlWindow.h" -#include "PatchDescriptionWindow.h" -#include "PatchTreeWindow.h" -#include "Controller.h" - -namespace OmGtk { - - -PatchView::PatchView(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::Box(cobject), - m_patch(NULL), - m_canvas(NULL), - m_enable_signal(true) -{ - property_visible() = false; - - xml->get_widget("patch_canvas_scrolledwindow", m_canvas_scrolledwindow); - xml->get_widget("patch_zoom_scale", m_zoom_slider); - xml->get_widget("patch_polyphony_label", m_polyphony_label); - xml->get_widget("patch_process_checkbutton", m_process_checkbutton); - - m_zoom_slider->signal_value_changed().connect( sigc::mem_fun(this, &PatchView::zoom_changed)); - m_process_checkbutton->signal_toggled().connect(sigc::mem_fun(this, &PatchView::process_toggled)); -} - - -/** Sets the patch controller for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -PatchView::patch_controller(PatchController* pc) -{ - //m_patch = new PatchController(pm, controller); - m_patch = pc; - - m_canvas = new OmFlowCanvas(pc, 1600*2, 1200*2); - - m_canvas_scrolledwindow->add(*m_canvas); - //m_canvas->show(); - //m_canvas_scrolledwindow->show(); - - char txt[4]; - snprintf(txt, 8, "%zd", pc->patch_model()->poly()); - m_polyphony_label->set_text(txt); - - //m_description_window->patch_model(pc->model()); -} - - -void -PatchView::show_control_window() -{ - if (m_patch != NULL) - m_patch->show_control_window(); -} - - -void -PatchView::zoom_changed() -{ - float z = m_zoom_slider->get_value(); - m_canvas->zoom(z); -} - - -void -PatchView::process_toggled() -{ - if (!m_enable_signal) - return; - - if (m_process_checkbutton->get_active()) { - Controller::instance().enable_patch(m_patch->model()->path()); - App::instance().patch_tree()->patch_enabled(m_patch->model()->path()); - } else { - Controller::instance().disable_patch(m_patch->model()->path()); - App::instance().patch_tree()->patch_disabled(m_patch->model()->path()); - } -} - - -void -PatchView::enabled(bool e) -{ - m_enable_signal = false; - m_process_checkbutton->set_active(e); - m_enable_signal = true; -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/PatchView.h b/src/clients/gtk/PatchView.h deleted file mode 100644 index ff6aebf9..00000000 --- a/src/clients/gtk/PatchView.h +++ /dev/null @@ -1,86 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 PATCHVIEW_H -#define PATCHVIEW_H - -#include -#include -#include -#include - -using std::string; - -namespace LibOmClient { -class PatchModel; -class NodeModel; -class PortModel; -class ControlModel; -class MetadataModel; -} -using namespace LibOmClient; - - -namespace OmGtk { - -class PatchController; -class OmFlowCanvas; -class LoadPluginWindow; -class NewSubpatchWindow; -class LoadSubpatchWindow; -class NewSubpatchWindow; -class NodeControlWindow; -class PatchDescriptionWindow; -class SubpatchModule; -class OmPort; - - -/** The patch specific contents of a PatchWindow (ie the canvas and whatever else). - * - * \ingroup OmGtk - */ -class PatchView : public Gtk::Box -{ -public: - PatchView(BaseObjectType* cobject, const Glib::RefPtr& glade_xml); - - void patch_controller(PatchController* pc); - - OmFlowCanvas* canvas() const { return m_canvas; } - PatchController* patch_controller() const { return m_patch; } - - void show_control_window(); - void zoom_changed(); - void process_toggled(); - - void enabled(bool e); - -private: - PatchController* m_patch; - OmFlowCanvas* m_canvas; - - Gtk::ScrolledWindow* m_canvas_scrolledwindow; - Gtk::HScale* m_zoom_slider; - Gtk::Label* m_polyphony_label; - Gtk::CheckButton* m_process_checkbutton; - - bool m_enable_signal; -}; - - -} // namespace OmGtk - -#endif // PATCHVIEW_H diff --git a/src/clients/gtk/PatchWindow.cpp b/src/clients/gtk/PatchWindow.cpp deleted file mode 100644 index 1513d473..00000000 --- a/src/clients/gtk/PatchWindow.cpp +++ /dev/null @@ -1,532 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "PatchWindow.h" -#include -#include -#include -#include "App.h" -#include "PatchView.h" -#include "OmFlowCanvas.h" -#include "PatchController.h" -#include "LoadPluginWindow.h" -#include "PatchModel.h" -#include "NewSubpatchWindow.h" -#include "LoadPatchWindow.h" -#include "LoadSubpatchWindow.h" -#include "NodeControlWindow.h" -#include "PatchDescriptionWindow.h" -#include "ConfigWindow.h" -#include "MessagesWindow.h" -#include "PatchTreeWindow.h" -#include "Controller.h" -#include "BreadCrumb.h" -#include "Store.h" - -namespace OmGtk { - - -PatchWindow::PatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) -: Gtk::Window(cobject), - m_patch(NULL), - m_load_plugin_window(NULL), - m_new_subpatch_window(NULL), - m_enable_signal(true), - m_position_stored(false), - m_x(0), - m_y(0) -{ - property_visible() = false; - - xml->get_widget("patch_win_vbox", m_vbox); - xml->get_widget("patch_win_viewport", m_viewport); - xml->get_widget("patch_win_breadcrumb_box", m_breadcrumb_box); - //xml->get_widget("patch_win_status_bar", m_status_bar); - xml->get_widget("patch_open_menuitem", m_menu_open); - xml->get_widget("patch_open_into_menuitem", m_menu_open_into); - xml->get_widget("patch_save_menuitem", m_menu_save); - xml->get_widget("patch_save_as_menuitem", m_menu_save_as); - xml->get_widget("patch_close_menuitem", m_menu_close); - xml->get_widget("patch_configuration_menuitem", m_menu_configuration); - xml->get_widget("patch_quit_menuitem", m_menu_quit); - xml->get_widget("patch_quit_and_kill_menuitem", m_menu_quit_and_kill); - xml->get_widget("patch_view_control_window_menuitem", m_menu_view_control_window); - xml->get_widget("patch_description_menuitem", m_menu_view_patch_description); - xml->get_widget("patch_fullscreen_menuitem", m_menu_fullscreen); - xml->get_widget("patch_clear_menuitem", m_menu_clear); - xml->get_widget("patch_destroy_menuitem", m_menu_destroy_patch); - xml->get_widget("patch_add_plugin_menuitem", m_menu_add_plugin); - xml->get_widget("patch_add_new_subpatch_menuitem", m_menu_new_subpatch); - xml->get_widget("patch_add_subpatch_from_file_menuitem", m_menu_load_subpatch); - xml->get_widget("patch_view_messages_window_menuitem", m_menu_view_messages_window); - xml->get_widget("patch_view_patch_tree_window_menuitem", m_menu_view_patch_tree_window); - xml->get_widget("patch_help_about_menuitem", m_menu_help_about); - - xml->get_widget_derived("load_plugin_win", m_load_plugin_window); - xml->get_widget_derived("new_subpatch_win", m_new_subpatch_window); - xml->get_widget_derived("load_patch_win", m_load_patch_window); - xml->get_widget_derived("load_subpatch_win", m_load_subpatch_window); - xml->get_widget_derived("patch_description_win", m_description_window); - - //m_load_plugin_window->set_transient_for(*this); - m_new_subpatch_window->set_transient_for(*this); - m_load_patch_window->set_transient_for(*this); - m_load_subpatch_window->set_transient_for(*this); - m_description_window->set_transient_for(*this); - - m_menu_view_control_window->property_sensitive() = false; - //m_status_bar->push(Controller::instance().engine_url()); - //m_status_bar->pack_start(*Gtk::manage(new Gtk::Image(Gtk::Stock::CONNECT, Gtk::ICON_SIZE_MENU)), false, false); - - m_menu_open->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::event_open)); - m_menu_open_into->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::event_open_into)); - m_menu_save->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::event_save)); - m_menu_save_as->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::event_save_as)); - m_menu_close->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::event_close)); - m_menu_quit->signal_activate().connect( - sigc::mem_fun(App::instance(), &App::quit)); - m_menu_quit_and_kill->signal_activate().connect( - sigc::mem_fun(App::instance(), &App::quit_and_kill)); - m_menu_configuration->signal_activate().connect( - sigc::mem_fun(App::instance().configuration_dialog(), &ConfigWindow::show)); - m_menu_fullscreen->signal_toggled().connect( - sigc::mem_fun(this, &PatchWindow::event_fullscreen_toggled)); - m_menu_view_control_window->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::show_control_window)); - m_menu_view_patch_description->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::show_description_window)); - m_menu_destroy_patch->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::event_destroy)); - m_menu_clear->signal_activate().connect( - sigc::mem_fun(this, &PatchWindow::event_clear)); - m_menu_add_plugin->signal_activate().connect( - sigc::mem_fun(m_load_plugin_window, &LoadPluginWindow::present)); - m_menu_new_subpatch->signal_activate().connect( - sigc::mem_fun(m_new_subpatch_window, &NewSubpatchWindow::present)); - m_menu_load_subpatch->signal_activate().connect( - sigc::mem_fun(m_load_subpatch_window, &LoadSubpatchWindow::present)); - m_menu_view_messages_window->signal_activate().connect( - sigc::mem_fun(App::instance().messages_dialog(), &MessagesWindow::present)); - m_menu_view_patch_tree_window->signal_activate().connect( - sigc::mem_fun(App::instance().patch_tree(), &PatchTreeWindow::present)); - - // Temporary workaround for Gtkmm 2.4 (no AboutDialog) - if (App::instance().about_dialog() != NULL) - m_menu_help_about->signal_activate().connect( - sigc::mem_fun(App::instance().about_dialog(), &Gtk::Dialog::present)); - - App::instance().add_patch_window(this); -} - - -PatchWindow::~PatchWindow() -{ - App::instance().remove_patch_window(this); - - hide(); - - delete m_new_subpatch_window; - delete m_load_subpatch_window; -} - - -/** Sets the patch controller for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -PatchWindow::patch_controller(PatchController* pc) -{ - m_enable_signal = false; - - assert(pc != NULL); - assert(m_patch != pc); - assert(m_patch == NULL || - pc->model()->path() != m_patch->model()->path()); - - PatchController* old_pc = m_patch; - if (old_pc != NULL) { - assert(old_pc->window() == NULL || old_pc->window() == this); - old_pc->claim_patch_view(); - old_pc->window(NULL); - } - - m_patch = pc; - - if (pc->view() == NULL) - pc->create_view(); - assert(pc->view() != NULL); - - PatchView* const patch_view = pc->view(); - assert(patch_view != NULL); - patch_view->reparent(*m_viewport); - pc->window(this); - show_all(); - - assert(m_load_plugin_window != NULL); - assert(m_new_subpatch_window != NULL); - assert(m_load_patch_window != NULL); - assert(m_load_subpatch_window != NULL); - - m_load_patch_window->patch_controller(m_patch); - m_load_plugin_window->patch_controller(m_patch); - m_new_subpatch_window->patch_controller(m_patch); - m_load_subpatch_window->patch_controller(m_patch); - - m_menu_view_control_window->property_sensitive() = pc->has_control_inputs(); - - int width, height; - get_size(width, height); - patch_view->canvas()->scroll_to( - ((int)patch_view->canvas()->width() - width)/2, - ((int)patch_view->canvas()->height() - height)/2); - - set_title(m_patch->model()->path()); - - m_description_window->patch_model(pc->patch_model()); - - - // Setup breadcrumbs box - // FIXME: this is filthy - - // Moving to a parent patch, depress correct button - if (old_pc != NULL && - old_pc->model()->path().substr(0, pc->model()->path().length()) - == pc->model()->path()) { - for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { - if ((*i)->patch() == pc) - (*i)->set_active(true); - else if ((*i)->patch() == old_pc) - (*i)->set_active(false); - } - - // Rebuild breadcrumbs from scratch (yeah, laziness..) - } else { - rebuild_breadcrumbs(); - } - - if (pc->model()->path() == "/") - m_menu_destroy_patch->set_sensitive(false); - else - m_menu_destroy_patch->set_sensitive(true); - - assert(old_pc == NULL || old_pc->window() != this); - assert(m_patch == pc); - assert(m_patch->window() == this); - - m_enable_signal = true; -} - - -/** Destroys current breadcrumbs and rebuilds from scratch. - * - * (Needs to be called when a patch is cleared to eliminate children crumbs) - */ -void -PatchWindow::rebuild_breadcrumbs() -{ - // Empty existing breadcrumbs - for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) - m_breadcrumb_box->remove(**i); - m_breadcrumbs.clear(); - - // Add new ones - string path = m_patch->path(); // To be chopped up, starting at the left - string but_name; // Name on breadcrumb button - string but_path; // Full path breadcrumb represents - - // Add root - assert(path[0] == '/'); - BreadCrumb* but = manage(new BreadCrumb(this, Store::instance().patch("/"))); - m_breadcrumb_box->pack_start(*but, false, false, 1); - m_breadcrumbs.push_back(but); - path = path.substr(1); // hack off leading slash - - // Add the rest - while (path.length() > 0) { - if (path.find("/") != string::npos) { - but_name = path.substr(0, path.find("/")); - but_path += string("/") + path.substr(0, path.find("/")); - path = path.substr(path.find("/")+1); - } else { - but_name = path; - but_path += string("/") + path; - path = ""; - } - BreadCrumb* but = manage(new BreadCrumb(this, Store::instance().patch(but_path))); - m_breadcrumb_box->pack_start(*but, false, false, 1); - m_breadcrumbs.push_back(but); - } - (*m_breadcrumbs.back()).set_active(true); - -} - - -void -PatchWindow::breadcrumb_clicked(BreadCrumb* crumb) -{ - if (m_enable_signal) { - PatchController* const pc = crumb->patch(); - assert(pc != NULL); - - if (pc == m_patch) { - crumb->set_active(true); - } else if (pc->window() != NULL && pc->window()->is_visible()) { - pc->show_patch_window(); - crumb->set_active(false); - } else { - patch_controller(pc); - } - } -} - - -void -PatchWindow::show_control_window() -{ - if (m_patch != NULL) - m_patch->show_control_window(); -} - - -void -PatchWindow::show_description_window() -{ - m_description_window->show(); -} - - -/** Notification a node has been removed from the PatchView this window - * currently contains. - * - * This is used to update the breadcrumbs in case the Node is a patch which has - * a button present in the breadcrumbs that needs to be removed. - */ -void -PatchWindow::node_removed(const string& name) -{ - for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { - if ((*i)->patch()->path() == m_patch->model()->base_path() + name) { - for (list::iterator j = i; j != m_breadcrumbs.end(); ) { - BreadCrumb* bc = *j; - j = m_breadcrumbs.erase(j); - m_breadcrumb_box->remove(*bc); - } - break; - } - } -} - - -/** Same as @a node_removed, but for renaming. - */ -void -PatchWindow::node_renamed(const string& old_path, const string& new_path) -{ - for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { - if ((*i)->patch()->model()->path() == old_path) - (*i)->path(new_path); - } -} - - -/** Notification the patch this window is currently showing was renamed. - */ -void -PatchWindow::patch_renamed(const string& new_path) -{ - set_title(new_path); - for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { - if ((*i)->patch() == m_patch) - (*i)->path(new_path); - } -} - - -void -PatchWindow::event_open() -{ - m_load_patch_window->set_replace(); - m_load_patch_window->present(); -} - -void -PatchWindow::event_open_into() -{ - m_load_patch_window->set_merge(); - m_load_patch_window->present(); -} - - -void -PatchWindow::event_save() -{ - PatchModel* const model = m_patch->patch_model(); - - if (model->filename() == "") - event_save_as(); - else - Controller::instance().save_patch(model, model->filename(), false); -} - - -void -PatchWindow::event_save_as() -{ - Gtk::FileChooserDialog dialog(*this, "Save Patch", Gtk::FILE_CHOOSER_ACTION_SAVE); - - Gtk::VBox* box = dialog.get_vbox(); - Gtk::Label warning("Warning: Recursively saving will overwrite any subpatch files \ - without confirmation."); - box->pack_start(warning, false, false, 2); - Gtk::CheckButton recursive_checkbutton("Recursively save all subpatches"); - box->pack_start(recursive_checkbutton, false, false, 0); - recursive_checkbutton.show(); - - dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); - - // Set current folder to most sensible default - const string& current_filename = m_patch->patch_model()->filename(); - if (current_filename.length() > 0) - dialog.set_filename(current_filename); - else if (App::instance().configuration()->patch_folder().length() > 0) - dialog.set_current_folder(App::instance().configuration()->patch_folder()); - - int result = dialog.run(); - bool recursive = recursive_checkbutton.get_active(); - - assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); - - if (result == Gtk::RESPONSE_OK) { - string filename = dialog.get_filename(); - if (filename.length() < 4 || filename.substr(filename.length()-3) != ".om") - filename += ".om"; - - bool confirm = false; - std::fstream fin; - fin.open(filename.c_str(), std::ios::in); - if (fin.is_open()) { // File exists - string msg = "File already exists! Are you sure you want to overwrite "; - msg += filename + "?"; - Gtk::MessageDialog confirm_dialog(*this, - msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); - if (confirm_dialog.run() == Gtk::RESPONSE_YES) - confirm = true; - else - confirm = false; - } else { // File doesn't exist - confirm = true; - } - fin.close(); - - if (confirm) { - Controller::instance().save_patch(m_patch->patch_model(), filename, recursive); - m_patch->patch_model()->filename(filename); - } - } - App::instance().configuration()->set_patch_folder(dialog.get_current_folder()); -} - - -void -PatchWindow::on_show() -{ - if (m_position_stored) - move(m_x, m_y); - - Gtk::Window::on_show(); -} - - -void -PatchWindow::on_hide() -{ - m_position_stored = true; - get_position(m_x, m_y); - Gtk::Window::on_hide(); -} - - -bool -PatchWindow::on_delete_event(GdkEventAny* ev) -{ - event_close(); - return true; // destroy window -} - - -bool -PatchWindow::on_key_press_event(GdkEventKey* event) -{ - if (event->keyval == GDK_Delete) { - if (m_patch != NULL && m_patch->view() != NULL) { - assert(m_patch->view()->canvas() != NULL); - m_patch->view()->canvas()->destroy_selected(); - } - return true; - } else { - return Gtk::Window::on_key_press_event(event); - } -} - - -void -PatchWindow::event_close() -{ - if (App::instance().num_open_patch_windows() > 1) { - hide(); - } else { - Gtk::MessageDialog d(*this, "This is the last remaining open Om patch\ -window. Closing this window will exit OmGtk (the engine will remain running).\n\n\ -Are you sure you want to quit?", - true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL, true); - int ret = d.run(); - if (ret == Gtk::RESPONSE_OK) - App::instance().quit(); - } -} - - -void -PatchWindow::event_destroy() -{ - Controller::instance().destroy(m_patch->model()->path()); -} - - -void -PatchWindow::event_clear() -{ - Controller::instance().clear_patch(m_patch->model()->path()); -} - -void -PatchWindow::event_fullscreen_toggled() -{ - if (m_menu_fullscreen->get_active()) - fullscreen(); - else - unfullscreen(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/PatchWindow.h b/src/clients/gtk/PatchWindow.h deleted file mode 100644 index 54ea11ef..00000000 --- a/src/clients/gtk/PatchWindow.h +++ /dev/null @@ -1,142 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 PATCHWINDOW_H -#define PATCHWINDOW_H - -#include -#include -#include -#include -#include - -using std::string; using std::list; - -namespace LibOmClient { -class PatchModel; -class NodeModel; -class PortModel; -class ControlModel; -class MetadataModel; -} -using namespace LibOmClient; - - -namespace OmGtk { - -class PatchController; -class OmFlowCanvas; -class PatchView; -class LoadPluginWindow; -class LoadPatchWindow; -class NewSubpatchWindow; -class LoadSubpatchWindow; -class NewSubpatchWindow; -class NodeControlWindow; -class PatchDescriptionWindow; -class SubpatchModule; -class OmPort; -class BreadCrumb; - - -/** A window for a patch. - * - * \ingroup OmGtk - */ -class PatchWindow : public Gtk::Window -{ -public: - PatchWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml); - ~PatchWindow(); - - void patch_controller(PatchController* pc); - - PatchController* patch_controller() const { return m_patch; } - LoadPluginWindow* load_plugin_window() const { return m_load_plugin_window; } - LoadSubpatchWindow* load_subpatch_window() const { return m_load_subpatch_window; } - NewSubpatchWindow* new_subpatch_window() const { return m_new_subpatch_window; } - - void show_control_window(); - void show_description_window(); - - // Breadcrumb management - void node_removed(const string& name); - void node_renamed(const string& old_path, const string& new_path); - void patch_renamed(const string& new_path); - void rebuild_breadcrumbs(); - void breadcrumb_clicked(BreadCrumb* crumb); - - Gtk::MenuItem* menu_view_control_window() { return m_menu_view_control_window; } - -protected: - void on_show(); - void on_hide(); - bool on_delete_event(GdkEventAny* ev); - bool on_key_press_event(GdkEventKey* event); - -private: - void event_open(); - void event_open_into(); - void event_save(); - void event_save_as(); - void event_close(); - void event_destroy(); - void event_clear(); - void event_fullscreen_toggled(); - - PatchController* m_patch; - LoadPluginWindow* m_load_plugin_window; - LoadPatchWindow* m_load_patch_window; - NewSubpatchWindow* m_new_subpatch_window; - LoadSubpatchWindow* m_load_subpatch_window; - PatchDescriptionWindow* m_description_window; - - bool m_enable_signal; - bool m_position_stored; - int m_x; - int m_y; - - Gtk::MenuItem* m_menu_open; - Gtk::MenuItem* m_menu_open_into; - Gtk::MenuItem* m_menu_save; - Gtk::MenuItem* m_menu_save_as; - Gtk::MenuItem* m_menu_configuration; - Gtk::MenuItem* m_menu_close; - Gtk::MenuItem* m_menu_quit; - Gtk::MenuItem* m_menu_quit_and_kill; - Gtk::CheckMenuItem* m_menu_fullscreen; - Gtk::MenuItem* m_menu_clear; - Gtk::MenuItem* m_menu_destroy_patch; - Gtk::MenuItem* m_menu_view_control_window; - Gtk::MenuItem* m_menu_view_patch_description; - Gtk::MenuItem* m_menu_add_plugin; - Gtk::MenuItem* m_menu_new_subpatch; - Gtk::MenuItem* m_menu_load_subpatch; - Gtk::MenuItem* m_menu_view_messages_window; - Gtk::MenuItem* m_menu_view_patch_tree_window; - Gtk::MenuItem* m_menu_help_about; - - Gtk::VBox* m_vbox; - Gtk::Viewport* m_viewport; - Gtk::HBox* m_breadcrumb_box; - list m_breadcrumbs; - //Gtk::Statusbar* m_status_bar; -}; - - -} // namespace OmGtk - -#endif // PATCHWINDOW_H diff --git a/src/clients/gtk/PortController.cpp b/src/clients/gtk/PortController.cpp deleted file mode 100644 index ec05541b..00000000 --- a/src/clients/gtk/PortController.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "PortController.h" -#include "OmModule.h" -#include "PortModel.h" -#include "ControlPanel.h" -#include "OmPort.h" -#include "Store.h" - -namespace OmGtk { - - -PortController::PortController(PortModel* model) -: GtkObjectController(model), - m_port(NULL), - m_control_panel(NULL) -{ - assert(model != NULL); - assert(model->parent() != NULL); - assert(model->controller() == NULL); - - model->set_controller(this); -} - - -void -PortController::add_to_store() -{ - Store::instance().add_object(this); -} - - -void -PortController::remove_from_store() -{ - Store::instance().remove_object(this); -} - - -void -PortController::destroy() -{ - assert(m_model->parent() != NULL); - NodeController* parent = (NodeController*)m_model->parent()->controller(); - assert(parent != NULL); - - if (m_control_panel != NULL) - m_control_panel->remove_port(path()); - - parent->remove_port(path(), false); -} - - -void -PortController::metadata_update(const string& key, const string& value) -{ - // FIXME: double lookups - - //cerr << path() << ": " << key << " = " << value << endl; - - if (key == "user-min") { - port_model()->user_min(atof(value.c_str())); - if (m_control_panel != NULL) - m_control_panel->set_range_min(m_model->path(), atof(value.c_str())); - } else if (key == "user-max") { - port_model()->user_max(atof(value.c_str())); - if (m_control_panel != NULL) - m_control_panel->set_range_max(m_model->path(), atof(value.c_str())); - } - - GtkObjectController::metadata_update(key, value); -} - - -void -PortController::control_change(float value) -{ - // FIXME: double lookups - - port_model()->value(value); - - if (m_control_panel != NULL) - m_control_panel->set_control(port_model()->path(), value); -} - - -/** "Register" a control panel that is monitoring this port. - * - * The OmPort will handle notifying the ControlPanel when state - * changes occur, etc. - */ -void -PortController::set_control_panel(ControlPanel* cp) -{ - assert(m_control_panel == NULL); - m_control_panel = cp; -} - - -void -PortController::set_path(const Path& new_path) -{ - // Change port name on module, if view exists - if (m_port != NULL) - m_port->set_name(new_path.name()); - - if (m_control_panel != NULL) - m_control_panel->rename_port(m_model->path(), new_path); - - m_model->set_path(new_path); -} - - -/** Create the visible port on a canvas module. - * - * Does not resize the module, caller's responsibility to do so if necessary. - */ -void -PortController::create_port(OmModule* module) -{ - assert(module != NULL); - - m_port = new OmPort(module, port_model()); - module->add_port(m_port, false); -} - - -} // namespace OmGtk - diff --git a/src/clients/gtk/PortController.h b/src/clients/gtk/PortController.h deleted file mode 100644 index cc2f9dc3..00000000 --- a/src/clients/gtk/PortController.h +++ /dev/null @@ -1,75 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 PORTCONTROLLER_H -#define PORTCONTROLLER_H - -#include -#include -#include "GtkObjectController.h" - -using std::string; -using namespace LibOmClient; - -namespace LibOmClient { - class MetadataModel; - class PortModel; -} - -namespace OmGtk { - -class Controller; -class OmPort; -class ControlPanel; -class OmModule; - - -/** Controller for a port on a (non-patch) node. - * - * \ingroup OmGtk - */ -class PortController : public GtkObjectController -{ -public: - PortController(PortModel* model); - virtual ~PortController() {} - - virtual void destroy(); - - virtual void add_to_store(); - virtual void remove_from_store(); - - virtual void metadata_update(const string& key, const string& value); - - void create_port(OmModule* module); - void set_path(const Path& new_path); - - void control_change(float value); - - ControlPanel* control_panel() const { return m_control_panel; } - void set_control_panel(ControlPanel* cp); - - PortModel* port_model() const { return (PortModel*)m_model; } - -private: - OmPort* m_port; ///< Canvas module port - ControlPanel* m_control_panel; ///< Control panel that contains this port -}; - - -} // namespace OmGtk - -#endif // PORTCONTROLLER_H diff --git a/src/clients/gtk/RenameWindow.cpp b/src/clients/gtk/RenameWindow.cpp deleted file mode 100644 index bde9a2c1..00000000 --- a/src/clients/gtk/RenameWindow.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "RenameWindow.h" -#include -#include -#include "Controller.h" -#include "ObjectModel.h" -#include "GtkObjectController.h" -#include "Store.h" -using std::string; - -namespace OmGtk { - - -RenameWindow::RenameWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml) -: Gtk::Window(cobject) -{ - glade_xml->get_widget("rename_name_entry", m_name_entry); - glade_xml->get_widget("rename_message_label", m_message_label); - glade_xml->get_widget("rename_cancel_button", m_cancel_button); - glade_xml->get_widget("rename_ok_button", m_ok_button); - - m_name_entry->signal_changed().connect(sigc::mem_fun(this, &RenameWindow::name_changed)); - m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &RenameWindow::cancel_clicked)); - m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &RenameWindow::ok_clicked)); - - m_ok_button->property_sensitive() = false; -} - - -/** Set the object this window is renaming. - * This function MUST be called before using this object in any way. - */ -void -RenameWindow::set_object(GtkObjectController* object) -{ - m_object = object; - m_name_entry->set_text(object->path().name()); -} - - -/** Called every time the user types into the name input box. - * Used to display warning messages, and enable/disable the rename button. - */ -void -RenameWindow::name_changed() -{ - assert(m_name_entry != NULL); - assert(m_message_label != NULL); - assert(m_object->model() != NULL); - assert(m_object->model()->parent() != NULL); - - string name = m_name_entry->get_text(); - if (name.find("/") != string::npos) { - m_message_label->set_text("Name may not contain '/'"); - m_ok_button->property_sensitive() = false; - //} else if (m_object->parent()->patch_model()->get_node(name) != NULL) { - } else if (Store::instance().object(m_object->model()->parent()->base_path() + name) != NULL) { - m_message_label->set_text("An object already exists with that name."); - m_ok_button->property_sensitive() = false; - } else if (name.length() == 0) { - m_message_label->set_text(""); - m_ok_button->property_sensitive() = false; - } else { - m_message_label->set_text(""); - m_ok_button->property_sensitive() = true; - } -} - - -void -RenameWindow::cancel_clicked() -{ - cout << "cancel\n"; - m_name_entry->set_text(""); - hide(); -} - - -/** Rename the object. - * - * It shouldn't be possible for this to be called with an invalid name set - * (since the Rename button should be deactivated). This is just shinification - * though - the engine will handle invalid names gracefully. - */ -void -RenameWindow::ok_clicked() -{ - string name = m_name_entry->get_text(); - assert(name.length() > 0); - assert(name.find("/") == string::npos); - - Controller::instance().rename(m_object->model()->path(), name); - - hide(); -} - - -} // namespace OmGtk diff --git a/src/clients/gtk/RenameWindow.h b/src/clients/gtk/RenameWindow.h deleted file mode 100644 index 81dc96e3..00000000 --- a/src/clients/gtk/RenameWindow.h +++ /dev/null @@ -1,57 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 RENAMEWINDOW_H -#define RENAMEWINDOW_H - -#include -#include - - -namespace OmGtk { - -class GtkObjectController; - - -/** 'New Patch' Window. - * - * Loaded by libglade as a derived object. - * - * \ingroup OmGtk - */ -class RenameWindow : public Gtk::Window -{ -public: - RenameWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); - - void set_object(GtkObjectController* object); - -private: - void name_changed(); - void cancel_clicked(); - void ok_clicked(); - - GtkObjectController* m_object; - - Gtk::Entry* m_name_entry; - Gtk::Label* m_message_label; - Gtk::Button* m_cancel_button; - Gtk::Button* m_ok_button; -}; - -} // namespace OmGtk - -#endif // RENAMEWINDOW_H diff --git a/src/clients/gtk/Store.cpp b/src/clients/gtk/Store.cpp deleted file mode 100644 index 97e556c9..00000000 --- a/src/clients/gtk/Store.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "Store.h" -#include "GtkObjectController.h" -#include "PatchController.h" -#include "NodeController.h" -#include "PortController.h" -#include "PluginModel.h" -#include "SigClientInterface.h" - -namespace OmGtk { - -Store::Store(SigClientInterface& emitter) -{ - //emitter.new_plugin_sig.connect(sigc::mem_fun(this, &Store::add_plugin)); - emitter.object_destroyed_sig.connect(sigc::mem_fun(this, &Store::destruction_event)); - emitter.new_plugin_sig.connect(sigc::mem_fun(this, &Store::new_plugin_event)); -} - -void -Store::add_object(GtkObjectController* object) -{ - assert(object->path() != ""); - assert(m_objects.find(object->path()) == m_objects.end()); - - m_objects[object->path()] = object; - - cout << "[Store] Added " << object->path() << endl; -} - - -void -Store::remove_object(GtkObjectController* object) -{ - if (!object) - return; - - map::iterator i - = m_objects.find(object->model()->path()); - - if (i != m_objects.end()) { - assert((*i).second == object); - m_objects.erase(i); - } else { - cerr << "[App] Unable to find object " << object->model()->path() - << " to remove." << endl; - } - - cout << "[Store] Removed " << object->path() << endl; -} - - -GtkObjectController* -Store::object(const string& path) const -{ - assert(path.length() > 0); - map::const_iterator i = m_objects.find(path); - if (i == m_objects.end()) - return NULL; - else - return (*i).second; -} - - -PatchController* -Store::patch(const string& path) const -{ - assert(path.length() > 0); - map::const_iterator i = m_objects.find(path); - if (i == m_objects.end()) - return NULL; - else - return dynamic_cast((*i).second); -} - - -NodeController* -Store::node(const string& path) const -{ - assert(path.length() > 0); - map::const_iterator i = m_objects.find(path); - if (i == m_objects.end()) - return NULL; - else - return dynamic_cast((*i).second); -} - - -PortController* -Store::port(const string& path) const -{ - assert(path.length() > 0); - map::const_iterator i = m_objects.find(path); - if (i == m_objects.end()) { - return NULL; - } else { - // Normal port - PortController* const pc = dynamic_cast((*i).second); - if (pc != NULL) - return pc; - - // Patch port (corresponding Node is in store) - NodeController* const nc = dynamic_cast((*i).second); - if (nc != NULL) - return nc->as_port(); // Patch port (maybe) - } - - return NULL; -} - - -void -Store::add_plugin(const PluginModel* pm) -{ - if (m_plugins.find(pm->uri()) != m_plugins.end()) { - cerr << "DUPE! " << pm->uri() << endl; - delete m_plugins[pm->uri()]; - } - - m_plugins[pm->uri()] = pm; -} - - -/* ****** Slots ******** */ - -void -Store::destruction_event(const string& path) -{ - remove_object(object(path)); -} - -void -Store::new_plugin_event(const string& type, const string& uri, const string& name) -{ - PluginModel* const p = new PluginModel(type, uri); - p->name(name); - add_plugin(p); -} - -} // namespace OmGtk - diff --git a/src/clients/gtk/Store.h b/src/clients/gtk/Store.h deleted file mode 100644 index 9fb4b270..00000000 --- a/src/clients/gtk/Store.h +++ /dev/null @@ -1,75 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 STORE_H -#define STORE_H - -#include -#include -#include -using std::string; using std::map; - -namespace LibOmClient { class PatchModel; class PluginModel; class SigClientInterface; } -using namespace LibOmClient; - -namespace OmGtk { - -class GtkObjectController; -class PatchController; -class NodeController; -class PortController; - -/** Singeton which holds all "Om Objects" for easy/fast lookup - * - * \ingroup OmGtk - */ -class Store { -public: - GtkObjectController* object(const string& path) const; - PatchController* patch(const string& path) const; - NodeController* node(const string& path) const; - PortController* port(const string& path) const; - - void add_object(GtkObjectController* object); - void remove_object(GtkObjectController* object); - - size_t num_objects() { return m_objects.size(); } - - void add_plugin(const PluginModel* pm); - const map& plugins() const { return m_plugins; } - - static void instantiate(SigClientInterface& emitter) - { if (!_instance) _instance = new Store(emitter); } - - inline static Store& instance() { assert(_instance); return *_instance; } - -private: - Store(SigClientInterface& emitter); - - static Store* _instance; - - // Slots for SigClientInterface signals - void destruction_event(const string& path); - void new_plugin_event(const string& type, const string& uri, const string& name); - - map m_objects; ///< Keyed by Om path - map m_plugins; ///< Keyed by URI -}; - - -} // namespace OmGtk - -#endif // STORE_H diff --git a/src/clients/gtk/SubpatchModule.cpp b/src/clients/gtk/SubpatchModule.cpp deleted file mode 100644 index 9c0e78e4..00000000 --- a/src/clients/gtk/SubpatchModule.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "SubpatchModule.h" -#include -#include -#include "OmModule.h" -#include "NodeControlWindow.h" -#include "PatchModel.h" -#include "PatchWindow.h" -#include "OmFlowCanvas.h" -#include "PatchController.h" -#include "OmPort.h" -#include "Controller.h" -using std::cerr; using std::cout; using std::endl; - -namespace OmGtk { - - -SubpatchModule::SubpatchModule(OmFlowCanvas* canvas, PatchController* patch) -: OmModule(canvas, patch), - m_patch(patch) -{ - assert(canvas != NULL); - assert(patch != NULL); -} - - -void -SubpatchModule::add_om_port(PortModel* pm, bool resize_to_fit) -{ - OmPort* port = new OmPort(this, pm); - - port->signal_event().connect( - sigc::bind(sigc::mem_fun(m_canvas, &OmFlowCanvas::port_event), port)); - - Module::add_port(port, resize_to_fit); -} - - -void -SubpatchModule::on_double_click(GdkEventButton* event) -{ - assert(m_patch != NULL); - - // If window is visible - if (m_patch->window() != NULL - && m_patch->window()->is_visible()) { - m_patch->show_patch_window(); // just raise it - // No window visible - } else { - if (event->state & GDK_SHIFT_MASK) - m_patch->show_patch_window(); // open a new window - else - browse_to_patch(); - } -} - - - -/** Browse to this patch in current (parent's) window. */ -void -SubpatchModule::browse_to_patch() -{ - assert(m_patch->model()->parent() != NULL); - PatchController* pc = (PatchController*)m_patch->model()->parent()->controller(); - assert(pc != NULL); - assert(pc->window() != NULL); - - assert(pc->window() != NULL); - pc->window()->patch_controller(m_patch); -} - - - -void -SubpatchModule::show_dialog() -{ - m_patch->show_control_window(); -} - - -void -SubpatchModule::menu_remove() -{ - Controller::instance().destroy(m_patch->model()->path()); -} - -} // namespace OmGtk diff --git a/src/clients/gtk/SubpatchModule.h b/src/clients/gtk/SubpatchModule.h deleted file mode 100644 index 162779d7..00000000 --- a/src/clients/gtk/SubpatchModule.h +++ /dev/null @@ -1,69 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 SUBPATCHMODULE_H -#define SUBPATCHMODULE_H - -#include -#include -#include "OmModule.h" -#include "PatchController.h" -using std::string; using std::list; - -namespace LibOmClient { -class PatchModel; -class NodeModel; -class PortModel; -class PatchWindow; -} -using namespace LibOmClient; - -namespace OmGtk { - -class OmFlowCanvas; -class NodeControlWindow; -class PatchController; - - -/** A module to represent a subpatch - * - * \ingroup OmGtk - */ -class SubpatchModule : public OmModule -{ -public: - SubpatchModule(OmFlowCanvas* canvas, PatchController* controller); - virtual ~SubpatchModule() {} - - void add_om_port(PortModel* pm, bool resize=true); - - void on_double_click(GdkEventButton* ev); - - void show_dialog(); - void browse_to_patch(); - void menu_remove(); - - PatchController* patch() { return m_patch; } - -protected: - PatchController* m_patch; -}; - - -} // namespace OmGtk - -#endif // SUBPATCHMODULE_H diff --git a/src/clients/gtk/cmdline.c b/src/clients/gtk/cmdline.c deleted file mode 100644 index 11fcd108..00000000 --- a/src/clients/gtk/cmdline.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - File autogenerated by gengetopt version 2.10 - generated with the following command: - gengetopt - - The developers of gengetopt consider the fixed text that goes in all - gengetopt output files to be in the public domain: - we make no copyright claims on it. -*/ - - -#include -#include -#include - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "getopt.h" - -#include "cmdline.h" - -void -cmdline_parser_print_version (void) -{ - printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); -} - -void -cmdline_parser_print_help (void) -{ - cmdline_parser_print_version (); - printf("\n" - "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); - printf(" -h --help Print help and exit\n"); - printf(" -V --version Print version and exit\n"); - printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n"); - printf(" -pINT --client-port=INT Client port to listen on\n"); -} - - -static char *gengetopt_strdup (const char *s); - -/* gengetopt_strdup() */ -/* strdup.c replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) -{ - char *result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; -} - -int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) -{ - int c; /* Character of the parsed option. */ - int missing_required_options = 0; - - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->engine_url_given = 0 ; - args_info->client_port_given = 0 ; -#define clear_args() { \ - args_info->engine_url_arg = NULL; \ -} - - clear_args(); - - optarg = 0; - optind = 1; - opterr = 1; - optopt = '?'; - - while (1) - { - int option_index = 0; - char *stop_char; - - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "engine-url", 1, NULL, 'u' }, - { "client-port", 1, NULL, 'p' }, - { NULL, 0, NULL, 0 } - }; - - stop_char = 0; - c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index); - - if (c == -1) break; /* Exit from `while (1)' loop. */ - - switch (c) - { - case 'h': /* Print help and exit. */ - clear_args (); - cmdline_parser_print_help (); - exit (EXIT_SUCCESS); - - case 'V': /* Print version and exit. */ - clear_args (); - cmdline_parser_print_version (); - exit (EXIT_SUCCESS); - - case 'u': /* Om engine URL to connect to. */ - if (args_info->engine_url_given) - { - fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->engine_url_given = 1; - args_info->engine_url_arg = gengetopt_strdup (optarg); - break; - - case 'p': /* Client port to listen on. */ - if (args_info->client_port_given) - { - fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->client_port_given = 1; - args_info->client_port_arg = strtol (optarg,&stop_char,0); - break; - - - case 0: /* Long option with no short option */ - - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - exit (EXIT_FAILURE); - - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); - abort (); - } /* switch */ - } /* while */ - - - if ( missing_required_options ) - exit (EXIT_FAILURE); - - return 0; -} diff --git a/src/clients/gtk/cmdline.ggo b/src/clients/gtk/cmdline.ggo deleted file mode 100644 index d62cf521..00000000 --- a/src/clients/gtk/cmdline.ggo +++ /dev/null @@ -1,7 +0,0 @@ -# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) - -package "om_gtk - A GUI client for the Om realtime modular synthesizer" - -option "engine-url" u "Om engine URL to connect to" string no -option "client-port" p "Client port to listen on" int no - diff --git a/src/clients/gtk/cmdline.h b/src/clients/gtk/cmdline.h deleted file mode 100644 index e404ac2e..00000000 --- a/src/clients/gtk/cmdline.h +++ /dev/null @@ -1,45 +0,0 @@ -/* cmdline.h */ - -/* File autogenerated by gengetopt version 2.10 */ - -#ifndef CMDLINE_H -#define CMDLINE_H - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef CMDLINE_PARSER_PACKAGE -#define CMDLINE_PARSER_PACKAGE "om_gtk - A GUI client for the Om realtime modular synthesizer" -#endif - -#ifndef CMDLINE_PARSER_VERSION -#define CMDLINE_PARSER_VERSION VERSION -#endif - -struct gengetopt_args_info -{ - char * engine_url_arg; /* Om engine URL to connect to. */ - int client_port_arg; /* Client port to listen on. */ - - int help_given ; /* Whether help was given. */ - int version_given ; /* Whether version was given. */ - int engine_url_given ; /* Whether engine-url was given. */ - int client_port_given ; /* Whether client-port was given. */ - -} ; - -int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); - -void cmdline_parser_print_help(void); -void cmdline_parser_print_version(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CMDLINE_H */ diff --git a/src/clients/gtk/main.cpp b/src/clients/gtk/main.cpp deleted file mode 100644 index 702d52f9..00000000 --- a/src/clients/gtk/main.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "cmdline.h" -#include "ConnectWindow.h" -#include "App.h" -#include "Store.h" -#include "Controller.h" -#include "Configuration.h" -#include "GtkClientInterface.h" -#ifdef HAVE_LASH - #include "LashController.h" -#endif -#include "ThreadedSigClientInterface.h" -using Om::Shared::ClientInterface; - -using namespace OmGtk; - - -class OSCSigEmitter : public OSCListener, public ThreadedSigClientInterface { -public: - OSCSigEmitter(size_t queue_size, int listen_port) - : Om::Shared::ClientInterface() - , OSCListener(listen_port) - , ThreadedSigClientInterface(queue_size) - { - Glib::signal_timeout().connect( - sigc::mem_fun((ThreadedSigClientInterface*)this, - &ThreadedSigClientInterface::emit_signals), - 5, G_PRIORITY_DEFAULT_IDLE); - } -}; - - -int -main(int argc, char** argv) -{ - string engine_url = "osc.udp://localhost:16180"; - int client_port = 0; - - /* **** Parse command line options **** */ - gengetopt_args_info args_info; - if (cmdline_parser (argc, argv, &args_info) != 0) - return 1; - - if (args_info.engine_url_given) - engine_url = args_info.engine_url_arg; - if (args_info.client_port_given) - client_port = args_info.client_port_arg; - - // FIXME: - client_port = 16181; - - Gnome::Canvas::init(); - Gtk::Main gtk_main(argc, argv); - - OSCSigEmitter* emitter = new OSCSigEmitter(1024, 16181); - - //CountedPtr emitter(new OSCSigEmitter(1024, 16181)); - - /* Instantiate all singletons */ - App::instantiate(); - Store::instantiate(*(SigClientInterface*)emitter); - ControlInterface* gtk_interface = App::instance().control_interface(); - assert(gtk_interface); - - //GtkClientInterface::instantiate(App::instance().control_interface(), client_port); - Controller::instantiate(engine_url); - - /* Load settings */ - App::instance().configuration()->load_settings(); - App::instance().configuration()->apply_settings(); - - #ifdef HAVE_LASH - lash_args_t* lash_args = lash_extract_args(&argc, &argv); - #endif - - //gtk_main.signal_quit().connect(sigc::ptr_fun(cleanup)); - - #ifdef HAVE_LASH - LashController* lash_controller = new LashController(lash_args); - #endif - - App::instance().connect_window()->start(CountedPtr(emitter)); - gtk_main.run(); - - return 0; -} - diff --git a/src/clients/gtk/om-icon.png b/src/clients/gtk/om-icon.png deleted file mode 100644 index b26dd942..00000000 Binary files a/src/clients/gtk/om-icon.png and /dev/null differ diff --git a/src/clients/gtk/om_gtk.glade b/src/clients/gtk/om_gtk.glade deleted file mode 100644 index abe5f254..00000000 --- a/src/clients/gtk/om_gtk.glade +++ /dev/null @@ -1,3555 +0,0 @@ - - - - - - - 1 - Om - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 640 - 480 - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - GTK_PACK_DIRECTION_LTR - GTK_PACK_DIRECTION_LTR - - - - True - _File - True - - - - - - - True - _Open (Replace)... - True - - - - - - True - gtk-open - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Open _Into (Import)... - True - - - - - - True - gtk-open - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - Save this patch - _Save - True - - - - - - True - gtk-save - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Save this patch to a specific filename - Save _As... - True - - - - - - True - gtk-save-as - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - Configure OmGtk - Confi_guration - True - - - - - - True - gtk-preferences - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - Close this window (patch will not be destroyed) - Close _Window - True - - - - - - True - gtk-close - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - Quit OmGtk (Om engine will continue running) - _Quit - True - - - - - - True - gtk-quit - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Quit OmGtk and kill the Om engine - Quit and _Kill Engine - True - - - - - - True - gtk-stop - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Patch - True - - - - - - - True - Fullscreen - True - False - - - - - - - - True - - - - - - True - View/Edit controls for this patch - _Controls - True - - - - - - True - gtk-preferences - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - View/Edit description for this patch - Descr_iption - True - - - - - True - gtk-edit - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Remove all objects from patch - Clear - True - - - - - True - gtk-clear - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Destoy this patch (remove it from the engine) - _Destroy - True - - - - - True - gtk-delete - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Insert - True - - - - - - - - True - Insert a plugin into this patch - _Plugin... - True - - - - - True - gtk-execute - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Insert a new, empty subpatch into this patchch - _New Patch... - True - - - - - - True - gtk-new - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Load a subpatch from a file and insert it into this patch - _Load Patch... - True - - - - - - True - gtk-open - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - False - Using this menu will place items randomly - right click! - Right click on canvas to manually place an object - True - - - - - True - gtk-info - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Windows - True - - - - - - - - True - View all patches in the engine as a heirarchial list - _Patch Tree - True - - - - - - True - gtk-index - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - View error messages from the engine - _Messages - True - - - - - - True - gtk-dialog-error - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Help - True - - - - - - - - True - gtk-about - True - - - - - - - - - - 0 - False - False - - - - - - True - False - 0 - - - - - - - 0 - False - False - - - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_NEVER - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - GTK_SHADOW_NONE - - - - - - - - - 0 - True - True - - - - - - - - 8 - Load Plugin - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - 640 - 480 - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 10 - - - - True - False - 10 - - - - True - False - 5 - - - - True - False - 1 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - All plugins available for loading - True - True - True - True - True - False - False - False - - - - - 0 - True - True - - - - - - True - 3 - 3 - False - 12 - 0 - - - - True - Clear filter text (show all plugins) - True - gtk-clear - True - GTK_RELIEF_NORMAL - True - - - 2 - 3 - 0 - 1 - fill - - - - - - - True - Module Name: - False - True - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 2 - 3 - fill - - - - - - - True - Close dialog - True - gtk-close - True - GTK_RELIEF_NORMAL - True - - - 2 - 3 - 2 - 3 - fill - - - - - - - True - - - 1 - 2 - 1 - 2 - fill - - - - - - True - - - 0 - 1 - 1 - 2 - fill - fill - - - - - - True - - - 2 - 3 - 1 - 2 - fill - fill - - - - - - True - False - 0 - - - - True - Name of new Module - True - True - True - 0 - - True - * - False - - - 0 - True - True - - - - - - True - True - Polyphonic - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 8 - False - False - - - - - - True - Add selected plugin to patch - True - gtk-add - True - GTK_RELIEF_NORMAL - True - - - 0 - False - False - - - - - 1 - 2 - 2 - 3 - 6 - fill - fill - - - - - - True - Search string to filter plugin list - True - True - True - 0 - - True - * - False - - - 1 - 2 - 0 - 1 - 6 - - - - - - - True - Name contains: - False - True - - - 0 - 1 - 0 - 1 - fill - fill - - - - - 0 - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - - - 8 - 320 - Create Subpatch - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - 2 - 2 - False - 0 - 0 - - - - True - Name: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - 5 - fill - expand - - - - - - True - Polyphony: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - 5 - fill - expand - - - - - - True - True - 1 - 0 - False - GTK_UPDATE_ALWAYS - False - False - 1 0 100 1 10 10 - - - 1 - 2 - 1 - 2 - 4 - fill - - - - - - - True - True - True - True - True - 0 - - True - * - True - - - 1 - 2 - 0 - 1 - 4 - - - - - - 0 - True - True - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - True - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - GTK_BUTTONBOX_END - 4 - - - - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - True - GTK_RELIEF_NORMAL - True - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-ok - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Create - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - 0 - True - True - - - - - - - - GTK_FILE_CHOOSER_ACTION_OPEN - True - False - False - False - Load Subpatch - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 10 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - True - True - True - gtk-open - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - 2 - 4 - False - 4 - 12 - - - - True - <b>Name: </b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - <b>Polyphony: </b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - Use the name stored in the patch file - True - Load from file - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 1 - 2 - 0 - 1 - fill - - - - - - - True - Use the polyphony value stored in the patch file - True - Load from file - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 1 - 2 - 1 - 2 - fill - - - - - - - True - False - 0 - - - - True - Specify a custom polyphony value for new patch - True - Specify: - True - GTK_RELIEF_NORMAL - True - False - False - True - load_subpatch_poly_from_file_radio - - - 0 - False - False - - - - - - True - False - Specify a custom polyphony value for new patch - True - 1 - 0 - False - GTK_UPDATE_ALWAYS - False - False - 1 0 1000 1 10 10 - - - 0 - False - True - - - - - 3 - 4 - 1 - 2 - fill - fill - - - - - - True - Set polyphony to the same value as the parent (containing) patch - True - Same as parent (?) - True - GTK_RELIEF_NORMAL - True - False - False - True - load_subpatch_poly_from_file_radio - - - 2 - 3 - 1 - 2 - fill - - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 2 - 3 - 0 - 1 - fill - - - - - - - True - False - 0 - - - - True - Specify the name for the new patch - True - Specify: - True - GTK_RELIEF_NORMAL - True - False - False - True - load_subpatch_name_from_file_radio - - - 0 - False - False - - - - - - True - False - Specify the name for the new patch - True - True - True - 0 - - True - * - True - - - 0 - False - True - - - - - 3 - 4 - 0 - 1 - fill - - - - - 0 - False - True - - - - - - - - GTK_FILE_CHOOSER_ACTION_OPEN - True - False - False - False - Load Patch - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - - - - False - 8 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - True - True - True - gtk-open - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - 1 - 4 - False - 4 - 12 - - - - True - <b>Polyphony: </b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - Use the same polyphony as the current patch - True - Keep current - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 1 - 2 - 0 - 1 - fill - - - - - - - True - Use the polyphony value stored in the patch file - True - Load from file - True - GTK_RELIEF_NORMAL - True - False - False - True - load_patch_poly_from_current_radio - - - 2 - 3 - 0 - 1 - fill - - - - - - - True - False - 0 - - - - True - True - Specify: - True - GTK_RELIEF_NORMAL - True - False - False - True - load_patch_poly_from_current_radio - - - 0 - False - False - - - - - - True - False - Specify a custom polyphony value for new patch - True - 1 - 0 - False - GTK_UPDATE_ALWAYS - False - False - 1 0 100 1 10 10 - - - 0 - False - True - - - - - 3 - 4 - 0 - 1 - fill - fill - - - - - 0 - False - True - - - - - - - - window1 - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - 2 - 2 - False - 0 - 0 - - - - True - False - 0 - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - GTK_SHADOW_NONE - - - - True - False - 0 - - - - - - - - - - - 0 - True - True - - - - - - True - True - 0 - - - - Apply changed controls to all voices - True - All Voices - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - - True - False - 5 - - - - True - Apply changed controls to one voice only - True - Specific Voice: - True - GTK_RELIEF_NORMAL - True - False - False - True - control_panel_all_voices_radio - - - 0 - False - False - - - - - - True - False - Voice control changes are applied to - True - 1 - 0 - True - GTK_UPDATE_ALWAYS - False - False - 1 1 100 1 10 10 - - - 0 - True - True - - - - - 0 - False - False - - - - - 5 - False - True - - - - - 0 - 1 - 0 - 1 - - - - - - True - False - 0 - - - - 1 - True - True - GTK_POLICY_ALWAYS - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - - - - 0 - True - True - - - - - - True - False - 0 - - - - True - Enable audio processing for this patch - True - Run - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - True - - - - - - True - True - False - True - - - 0 - False - False - - - - - - True - False - 0 - - - - True - Polyphony: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - ? - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 10 - True - False - - - - - - True - True - False - True - - - 0 - False - False - - - - - - True - False - 0 - - - - True - Zoom: - False - True - GTK_JUSTIFY_LEFT - False - False - 0.469999998808 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 2 - False - False - - - - - - 90 - True - True - False - GTK_POS_RIGHT - 1 - GTK_UPDATE_CONTINUOUS - False - 1.10638296604 0.25 2 0.25 0 0 - - - 0 - False - False - - - - - 0 - False - True - - - - - 0 - False - False - - - - - 0 - 1 - 1 - 2 - fill - - - - - - - - 8 - 400 - 180 - Error Messages - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 6 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - Error messages from the engine since the last time "Clear" was pressed - True - False - False - False - GTK_JUSTIFY_LEFT - GTK_WRAP_WORD - False - 5 - 5 - 0 - 5 - 5 - 0 - - - - - - 0 - True - True - - - - - - True - GTK_BUTTONBOX_END - 6 - - - - True - False - True - True - gtk-clear - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - gtk-close - True - GTK_RELIEF_NORMAL - True - - - - - 0 - False - True - - - - - - - - 8 - Configuration - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 6 - - - - True - 2 - 2 - False - 0 - 0 - - - - True - <b>Patch Search Path: </b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - True - True - True - 0 - - True - * - False - - - 1 - 2 - 0 - 1 - - - - - - - True - <i>Example: /foo/bar:/home/john/patches:/usr/share/om/patches</i> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 1 - 2 - 1 - 2 - fill - - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - 0 - True - False - - - - - - True - GTK_BUTTONBOX_END - 6 - - - - True - Save these settings for future sessions - True - gtk-save - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - Apply these settings to this session only - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - - - - - 0 - False - True - - - - - - - - 8 - 400 - 200 - Patch Description - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 6 - - - - True - False - 5 - - - - True - Author: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - False - - - 0 - True - True - - - - - 0 - False - False - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - A short description of the patch to be included in the patch file - True - True - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_WORD - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 0 - True - True - - - - - - True - GTK_BUTTONBOX_END - 5 - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - Apply these changes to be saved the next time the patch is saved - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - - - - - 0 - False - False - - - - - - - - 250 - Rename - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - 5 - True - False - 0 - - - - True - False - 0 - - - - True - New name: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - True - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - True - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 6 - False - True - - - - - - True - GTK_BUTTONBOX_END - 5 - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - True - GTK_RELIEF_NORMAL - True - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-ok - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Rename - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - 0 - False - True - - - - - - - - 6 - window1 - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - <b>Node</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - 12 - True - False - 6 - - - - True - False - 4 - - - - True - Path: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 0 - False - False - - - - - - True - False - True - Polyphonic - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - 6 - True - True - - - - - - 240 - True - <b>Plugin</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - 12 - True - 3 - 2 - False - 6 - 10 - - - - True - - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 1 - 2 - 0 - 1 - fill - - - - - - - True - Type: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - URI: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 1 - 2 - 1 - 2 - fill - - - - - - - True - Name: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 2 - 3 - fill - - - - - - - True - - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 1 - 2 - 2 - 3 - fill - - - - - - 0 - True - True - - - - - - - - True - OmGtk - Copyright (C) 2005-2006 Dave Robillard - A client for the Om modular synthesizer - Licensed under the GNU GPL, Version 2. - -See COPYING file included with Om, or http://www.gnu.org/licenses/gpl.txt for more information - False - http://om-synth.nongnu.org - - Author: - Dave Robillard <drobilla@connect.carelton.ca> - -Contributors: - Lars Luthman - DSSI enhancements, bugfixes - Mario Lang - SuperCollider bindings, bugfixes - Leonard Ritter - Python bindings - - Usability / UI Design: - Thorsten Wilms - translator-credits - om-icon.png - - - - 8 - 320 - 340 - Patches - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - 3 - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - All patches loaded in the engine - True - True - True - False - True - False - False - False - - - - - - - - 6 - Connecting to Engine - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - True - - - - True - False - 6 - - - - True - GTK_BUTTONBOX_DEFAULT_STYLE - - - - True - True - True - GTK_RELIEF_NORMAL - True - 0 - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-execute - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - _Launch Engine - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - 0 - False - False - GTK_PACK_END - - - - - - 2 - True - False - 0 - - - - True - False - 0 - - - - True - om-icon.png - 0.5 - 0.5 - 6 - 0 - - - 0 - False - False - - - - - - 5 - True - True - 0 - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - GTK_PROGRESS_LEFT_TO_RIGHT - 0 - 0.10000000149 - - PANGO_ELLIPSIZE_NONE - - - 0 - False - False - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - Connecting to engine - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 4 - False - False - - - - - 0 - True - True - - - - - - - diff --git a/src/clients/gtk/om_gtk.glade.bak b/src/clients/gtk/om_gtk.glade.bak deleted file mode 100644 index 7714d1f3..00000000 --- a/src/clients/gtk/om_gtk.glade.bak +++ /dev/null @@ -1,3555 +0,0 @@ - - - - - - - 1 - Om - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 640 - 480 - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - GTK_PACK_DIRECTION_LTR - GTK_PACK_DIRECTION_LTR - - - - True - _File - True - - - - - - - True - _Open (Replace)... - True - - - - - - True - gtk-open - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Open _Into (Import)... - True - - - - - - True - gtk-open - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - Save this patch - _Save - True - - - - - - True - gtk-save - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Save this patch to a specific filename - Save _As... - True - - - - - - True - gtk-save-as - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - Configure OmGtk - Confi_guration - True - - - - - - True - gtk-preferences - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - Close this window (patch will not be destroyed) - Close _Window - True - - - - - - True - gtk-close - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - Quit OmGtk (Om engine will continue running) - _Quit - True - - - - - - True - gtk-quit - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Quit OmGtk and kill the Om engine - Quit and _Kill Engine - True - - - - - - True - gtk-stop - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Patch - True - - - - - - - True - Fullscreen - True - False - - - - - - - - True - - - - - - True - View/Edit controls for this patch - _Controls - True - - - - - - True - gtk-preferences - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - View/Edit description for this patch - Descr_iption - True - - - - - True - gtk-edit - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Remove all objects from patch - Clear - True - - - - - True - gtk-clear - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Destoy this patch (remove it from the engine) - _Destroy - True - - - - - True - gtk-delete - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Insert - True - - - - - - - - True - Insert a plugin into this patch - _Plugin... - True - - - - - True - gtk-execute - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Insert a new, empty subpatch into this patchch - _New Patch... - True - - - - - - True - gtk-new - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Load a subpatch from a file and insert it into this patch - _Load Patch... - True - - - - - - True - gtk-open - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - False - Using this menu will place items randomly - right click! - Right click on canvas to manually place an object - True - - - - - True - gtk-info - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Windows - True - - - - - - - - True - View all patches in the engine as a heirarchial list - _Patch Tree - True - - - - - - True - gtk-index - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - View error messages from the engine - _Messages - True - - - - - - True - gtk-dialog-error - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Help - True - - - - - - - - True - gtk-about - True - - - - - - - - - - 0 - False - False - - - - - - True - False - 0 - - - - - - - 0 - False - False - - - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_NEVER - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - GTK_SHADOW_NONE - - - - - - - - - 0 - True - True - - - - - - - - 8 - Load Plugin - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - 640 - 480 - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 10 - - - - True - False - 10 - - - - True - False - 5 - - - - True - False - 1 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - All plugins available for loading - True - True - True - True - True - False - False - False - - - - - 0 - True - True - - - - - - True - 3 - 3 - False - 12 - 0 - - - - True - Clear filter text (show all plugins) - True - gtk-clear - True - GTK_RELIEF_NORMAL - True - - - 2 - 3 - 0 - 1 - fill - - - - - - - True - Module Name: - False - True - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 2 - 3 - fill - - - - - - - True - Close dialog - True - gtk-close - True - GTK_RELIEF_NORMAL - True - - - 2 - 3 - 2 - 3 - fill - - - - - - - True - - - 1 - 2 - 1 - 2 - fill - - - - - - True - - - 0 - 1 - 1 - 2 - fill - fill - - - - - - True - - - 2 - 3 - 1 - 2 - fill - fill - - - - - - True - False - 0 - - - - True - Name of new Module - True - True - True - 0 - - True - * - False - - - 0 - True - True - - - - - - True - True - Polyphonic - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 8 - False - False - - - - - - True - Add selected plugin to patch - True - gtk-add - True - GTK_RELIEF_NORMAL - True - - - 0 - False - False - - - - - 1 - 2 - 2 - 3 - 6 - fill - fill - - - - - - True - Search string to filter plugin list - True - True - True - 0 - - True - * - False - - - 1 - 2 - 0 - 1 - 6 - - - - - - - True - Name contains: - False - True - - - 0 - 1 - 0 - 1 - fill - fill - - - - - 0 - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - - - 8 - 320 - Create Subpatch - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - 2 - 2 - False - 0 - 0 - - - - True - Name: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - 5 - fill - expand - - - - - - True - Polyphony: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - 5 - fill - expand - - - - - - True - True - 1 - 0 - False - GTK_UPDATE_ALWAYS - False - False - 1 0 100 1 10 10 - - - 1 - 2 - 1 - 2 - 4 - fill - - - - - - - True - True - True - True - True - 0 - - True - * - True - - - 1 - 2 - 0 - 1 - 4 - - - - - - 0 - True - True - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - True - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - GTK_BUTTONBOX_END - 4 - - - - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - True - GTK_RELIEF_NORMAL - True - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-ok - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Create - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - 0 - True - True - - - - - - - - GTK_FILE_CHOOSER_ACTION_OPEN - True - False - False - False - Load Subpatch - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 24 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - True - True - True - gtk-open - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - 2 - 4 - False - 4 - 12 - - - - True - <b>Name: </b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - <b>Polyphony: </b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - Use the name stored in the patch file - True - Load from file - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 1 - 2 - 0 - 1 - fill - - - - - - - True - Use the polyphony value stored in the patch file - True - Load from file - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 1 - 2 - 1 - 2 - fill - - - - - - - True - False - 0 - - - - True - Specify a custom polyphony value for new patch - True - Specify: - True - GTK_RELIEF_NORMAL - True - False - False - True - load_subpatch_poly_from_file_radio - - - 0 - False - False - - - - - - True - False - Specify a custom polyphony value for new patch - True - 1 - 0 - False - GTK_UPDATE_ALWAYS - False - False - 1 0 1000 1 10 10 - - - 0 - False - True - - - - - 3 - 4 - 1 - 2 - fill - fill - - - - - - True - Set polyphony to the same value as the parent (containing) patch - True - Same as parent (?) - True - GTK_RELIEF_NORMAL - True - False - False - True - load_subpatch_poly_from_file_radio - - - 2 - 3 - 1 - 2 - fill - - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 2 - 3 - 0 - 1 - fill - - - - - - - True - False - 0 - - - - True - Specify the name for the new patch - True - Specify: - True - GTK_RELIEF_NORMAL - True - False - False - True - load_subpatch_name_from_file_radio - - - 0 - False - False - - - - - - True - False - Specify the name for the new patch - True - True - True - 0 - - True - * - True - - - 0 - False - True - - - - - 3 - 4 - 0 - 1 - fill - - - - - 0 - False - True - - - - - - - - GTK_FILE_CHOOSER_ACTION_OPEN - True - False - False - False - Load Patch - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - - - - False - 24 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - True - True - True - gtk-open - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - 1 - 4 - False - 4 - 12 - - - - True - <b>Polyphony: </b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - Use the same polyphony as the current patch - True - Keep current - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 1 - 2 - 0 - 1 - fill - - - - - - - True - Use the polyphony value stored in the patch file - True - Load from file - True - GTK_RELIEF_NORMAL - True - False - False - True - load_patch_poly_from_current_radio - - - 2 - 3 - 0 - 1 - fill - - - - - - - True - False - 0 - - - - True - True - Specify: - True - GTK_RELIEF_NORMAL - True - False - False - True - load_patch_poly_from_current_radio - - - 0 - False - False - - - - - - True - False - Specify a custom polyphony value for new patch - True - 1 - 0 - False - GTK_UPDATE_ALWAYS - False - False - 1 0 100 1 10 10 - - - 0 - False - True - - - - - 3 - 4 - 0 - 1 - fill - fill - - - - - 0 - False - True - - - - - - - - window1 - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - 2 - 2 - False - 0 - 0 - - - - True - False - 0 - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - GTK_SHADOW_NONE - - - - True - False - 0 - - - - - - - - - - - 0 - True - True - - - - - - True - True - 0 - - - - Apply changed controls to all voices - True - All Voices - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - - True - False - 5 - - - - True - Apply changed controls to one voice only - True - Specific Voice: - True - GTK_RELIEF_NORMAL - True - False - False - True - control_panel_all_voices_radio - - - 0 - False - False - - - - - - True - False - Voice control changes are applied to - True - 1 - 0 - True - GTK_UPDATE_ALWAYS - False - False - 1 1 100 1 10 10 - - - 0 - True - True - - - - - 0 - False - False - - - - - 5 - False - True - - - - - 0 - 1 - 0 - 1 - - - - - - True - False - 0 - - - - 1 - True - True - GTK_POLICY_ALWAYS - GTK_POLICY_ALWAYS - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - - - - 0 - True - True - - - - - - True - False - 0 - - - - True - Enable audio processing for this patch - True - Run - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - True - - - - - - True - True - False - True - - - 0 - False - False - - - - - - True - False - 0 - - - - True - Polyphony: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - ? - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 10 - True - False - - - - - - True - True - False - True - - - 0 - False - False - - - - - - True - False - 0 - - - - True - Zoom: - False - True - GTK_JUSTIFY_LEFT - False - False - 0.469999998808 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 2 - False - False - - - - - - 90 - True - True - False - GTK_POS_RIGHT - 1 - GTK_UPDATE_CONTINUOUS - False - 1.10638296604 0.25 2 0.25 0 0 - - - 0 - False - False - - - - - 0 - False - True - - - - - 0 - False - False - - - - - 0 - 1 - 1 - 2 - fill - - - - - - - - 8 - 400 - 180 - Error Messages - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 6 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - Error messages from the engine since the last time "Clear" was pressed - True - False - False - False - GTK_JUSTIFY_LEFT - GTK_WRAP_WORD - False - 5 - 5 - 0 - 5 - 5 - 0 - - - - - - 0 - True - True - - - - - - True - GTK_BUTTONBOX_END - 6 - - - - True - False - True - True - gtk-clear - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - gtk-close - True - GTK_RELIEF_NORMAL - True - - - - - 0 - False - True - - - - - - - - 8 - Configuration - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 6 - - - - True - 2 - 2 - False - 0 - 0 - - - - True - <b>Patch Search Path: </b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - True - True - True - 0 - - True - * - False - - - 1 - 2 - 0 - 1 - - - - - - - True - <i>Example: /foo/bar:/home/john/patches:/usr/share/om/patches</i> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 1 - 2 - 1 - 2 - fill - - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - 0 - True - False - - - - - - True - GTK_BUTTONBOX_END - 6 - - - - True - Save these settings for future sessions - True - gtk-save - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - Apply these settings to this session only - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - - - - - 0 - False - True - - - - - - - - 8 - 400 - 200 - Patch Description - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 6 - - - - True - False - 5 - - - - True - Author: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - False - - - 0 - True - True - - - - - 0 - False - False - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - A short description of the patch to be included in the patch file - True - True - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_WORD - True - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 0 - True - True - - - - - - True - GTK_BUTTONBOX_END - 5 - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - Apply these changes to be saved the next time the patch is saved - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - - - - - 0 - False - False - - - - - - - - 250 - Rename - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - 5 - True - False - 0 - - - - True - False - 0 - - - - True - New name: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 0 - - True - * - True - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - True - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 6 - False - True - - - - - - True - GTK_BUTTONBOX_END - 5 - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - True - GTK_RELIEF_NORMAL - True - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-ok - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Rename - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - 0 - False - True - - - - - - - - 6 - window1 - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - True - False - 0 - - - - True - <b>Node</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - 12 - True - False - 6 - - - - True - False - 4 - - - - True - Path: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 0 - False - False - - - - - - True - False - True - Polyphonic - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - 6 - True - True - - - - - - 240 - True - <b>Plugin</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - 12 - True - 3 - 2 - False - 6 - 10 - - - - True - - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 1 - 2 - 0 - 1 - fill - - - - - - - True - Type: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - URI: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 1 - 2 - 1 - 2 - fill - - - - - - - True - Name: - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 1 - 2 - 3 - fill - - - - - - - True - - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 1 - 2 - 2 - 3 - fill - - - - - - 0 - True - True - - - - - - - - True - OmGtk - Copyright (C) 2005-2006 Dave Robillard - A client for the Om modular synthesizer - Licensed under the GNU GPL, Version 2. - -See COPYING file included with Om, or http://www.gnu.org/licenses/gpl.txt for more information - False - http://om-synth.nongnu.org - - Author: - Dave Robillard <drobilla@connect.carelton.ca> - -Contributors: - Lars Luthman - DSSI enhancements, bugfixes - Mario Lang - SuperCollider bindings, bugfixes - Leonard Ritter - Python bindings - - Usability / UI Design: - Thorsten Wilms - translator-credits - om-icon.png - - - - 8 - 320 - 340 - Patches - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - 3 - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - All patches loaded in the engine - True - True - True - False - True - False - False - False - - - - - - - - 6 - Connecting to Engine - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER - False - True - False - om-icon.png - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - True - - - - True - False - 6 - - - - True - GTK_BUTTONBOX_DEFAULT_STYLE - - - - True - True - True - GTK_RELIEF_NORMAL - True - 0 - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-execute - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - _Launch Engine - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - 0 - False - False - GTK_PACK_END - - - - - - 2 - True - False - 0 - - - - True - False - 0 - - - - True - om-icon.png - 0.5 - 0.5 - 6 - 0 - - - 0 - False - False - - - - - - 5 - True - True - 0 - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - GTK_PROGRESS_LEFT_TO_RIGHT - 0 - 0.10000000149 - - PANGO_ELLIPSIZE_NONE - - - 0 - False - False - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - True - Connecting to engine - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 4 - False - False - - - - - 0 - True - True - - - - - - - diff --git a/src/clients/gtk/om_gtk.gladep b/src/clients/gtk/om_gtk.gladep deleted file mode 100644 index a8bd18bd..00000000 --- a/src/clients/gtk/om_gtk.gladep +++ /dev/null @@ -1,9 +0,0 @@ - - - - - OmGtk - om_gtk - C++ - FALSE - diff --git a/src/clients/gtk/om_gtk.gladep.bak b/src/clients/gtk/om_gtk.gladep.bak deleted file mode 100644 index a8bd18bd..00000000 --- a/src/clients/gtk/om_gtk.gladep.bak +++ /dev/null @@ -1,9 +0,0 @@ - - - - - OmGtk - om_gtk - C++ - FALSE - diff --git a/src/clients/gtk/singletons.cpp b/src/clients/gtk/singletons.cpp deleted file mode 100644 index 75b441e9..00000000 --- a/src/clients/gtk/singletons.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 "App.h" -#include "Store.h" -#include "Controller.h" -//#include "GtkClientInterface.h" - -namespace OmGtk -{ - App* App::_instance = 0; - Store* Store::_instance = 0; - Controller* Controller::_instance = 0; - //CountedPtr GtkClientInterface::_instance = 0; -} - diff --git a/src/clients/new/PatchLibrarian.cpp b/src/clients/new/PatchLibrarian.cpp deleted file mode 100644 index 66c013e5..00000000 --- a/src/clients/new/PatchLibrarian.cpp +++ /dev/null @@ -1,824 +0,0 @@ -/* This file is part of Om. 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 "PatchLibrarian.h" -#include -#include -#include -#include "PatchModel.h" -#include "NodeModel.h" -#include "ConnectionModel.h" -#include "PortModel.h" -#include "PresetModel.h" -#include "OSCModelEngineInterface.h" -#include "PluginModel.h" -#include "util/Path.h" -#include -#include -#include -#include // for pair, make_pair -#include -#include -#include -#include // for usleep -#include // for atof -#include - -using std::string; using std::vector; using std::pair; -using std::cerr; using std::cout; using std::endl; -using Om::Path; - -namespace LibOmClient { - - -/** Load a patch in to the engine (and client) from a patch file. - * - * The name and poly from the passed PatchModel are used. If the name is - * the empty string, the name will be loaded from the file. If the poly - * is 0, it will be loaded from file. Otherwise the given values will - * be used. - * - * @param parent_path Path of the patch to create the new patch under. - * - * @param name Name to give the new Patch. If @a name is the empty string, - * the name stored in the patch file will be used. - * - * @param poly The polyphony of the new patch if nonzero, otherwise the - * polyphony value stored in the patch file will be used. - * - * @return true on success. - */ -bool -PatchLibrarian::load_patch(EngineInterface* engine, - const string& filename, - const Path& parent_path, - string name, - uint32_t poly) -{ - cerr << "Loading patch " << filename << "" << endl; - - //const size_t temp_buf_length = 255; - //char temp_buf[temp_buf_length]; - - xmlDocPtr doc = xmlParseFile(filename.c_str()); - - if (doc == NULL ) { - cerr << "Unable to parse patch file." << endl; - return false; - } - - xmlNodePtr cur = xmlDocGetRootElement(doc); - - if (cur == NULL) { - cerr << "Document has no root element." << endl; - xmlFreeDoc(doc); - return false; - } - - if (xmlStrcmp(cur->name, (const xmlChar*) "patch")) { - cerr << "File is not an Om patch file (root node != patch)." << endl; - xmlFreeDoc(doc); - return false; - } - - cur = cur->xmlChildrenNode; - string path; - - map metadata; - - // Load Patch attributes - while (cur != NULL) { - xmlChar* const key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - if (name == "") { - assert(key); - name = (char*)key; - } - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { - if (poly == 0) { - assert(key); - poly = atoi((char*)key); // FIXME: error checking - } - /* Don't know what this tag is, add it as metadata without overwriting - * (so caller can set arbitrary metadata which will be preserved) - * FIXME: this is just plain filthy. XML is not RDF. */ - } else if (key - && xmlStrcmp(cur->name, (const xmlChar*)"connection") - && xmlStrcmp(cur->name, (const xmlChar*)"node") - && xmlStrcmp(cur->name, (const xmlChar*)"subpatch") - && xmlStrcmp(cur->name, (const xmlChar*)"filename") - && xmlStrcmp(cur->name, (const xmlChar*)"preset")) { - - metadata[(char*)cur->name] == (char*)key; - } - - xmlFree(key); - - cur = cur->next; - } - - - // Didn't find a polyphony value, set monophonic by default - if (poly == 0) poly = 1; - - - /* FIXME: This functionality needs to be implemented (elsewhere) - if (!existing) { - // Wait until the patch is created or the node creations may fail - if (wait) { - int id = m_osc_controller->get_next_request_id(); - m_osc_controller->set_wait_response_id(id); - m_osc_controller->create_patch(pm, id); - bool succeeded = m_osc_controller->wait_for_response(); - - // If creating the patch failed, bail out so we don't load all these nodes - // into an already existing patch - if (!succeeded) { - cerr << "[PatchLibrarian] Patch load failed (patch already exists)" << endl; - return ""; - } - } else { - m_osc_controller->create_patch(pm); - } - } - */ - engine->create_patch(path, poly, -1); - - - /* Set the filename metadata. (FIXME) - * This isn't so good, considering multiple clients on multiple machines, and - * absolute filesystem paths obviously aren't going to be correct. But for now - * this is all I can figure out to have Save/Save As work properly for subpatches */ - engine->set_metadata(path, "filename", filename); - -#if 0 - // Load nodes - NodeModel* nm = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"node"))) { - nm = parse_node(pm, doc, cur); - if (nm != NULL) { - m_osc_controller->add_node(nm); - m_osc_controller->set_all_metadata(nm); - for (list::const_iterator j = nm->ports().begin(); - j != nm->ports().end(); ++j) { - // FIXME: ew - snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min()); - m_osc_controller->set_metadata((*j)->path(), "user-min", temp_buf); - snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max()); - m_osc_controller->set_metadata((*j)->path(), "user-max", temp_buf); - } - nm = NULL; - usleep(10000); - } - } - cur = cur->next; - } - - // Load subpatches - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) { - load_subpatch(pm, doc, cur); - } - cur = cur->next; - } - - // Load connections - ConnectionModel* cm = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) { - cm = parse_connection(pm, doc, cur); - if (cm != NULL) { - m_osc_controller->connect(cm->src_port_path(), cm->dst_port_path()); - usleep(1000); - } - } - cur = cur->next; - } - - - // Load presets (control values) - PresetModel* preset_model = NULL; - cur = xmlDocGetRootElement(doc)->xmlChildrenNode; - while (cur != NULL) { - if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) { - preset_model = parse_preset(pm, doc, cur); - assert(preset_model != NULL); - if (preset_model->name() == "default") - m_osc_controller->set_preset(pm->path(), preset_model); - } - cur = cur->next; - } -#endif - xmlFreeDoc(doc); - xmlCleanupParser(); - - //m_osc_controller->set_all_metadata(pm); - - //if (!existing) - // m_osc_controller->enable_patch(pm->path()); - - return true; -} - - -#if 0 -/** Searches for the filename passed in the path, returning the full - * path of the file, or the empty string if not found. - * - * This function tries to be as friendly a black box as possible - if the path - * passed is an absolute path and the file is found there, it will return - * that path, etc. - * - * additional_path is a list (colon delimeted as usual) of additional - * directories to look in. ie the directory the parent patch resides in would - * be a good idea to pass as additional_path, in the case of a subpatch. - */ -string -PatchLibrarian::find_file(const string& filename, const string& additional_path) -{ - string search_path = additional_path + ":" + m_patch_path; - - // Try to open the raw filename first - std::ifstream is(filename.c_str(), std::ios::in); - if (is.good()) { - is.close(); - return filename; - } - - string directory; - string full_patch_path = ""; - - while (search_path != "") { - directory = search_path.substr(0, search_path.find(':')); - if (search_path.find(':') != string::npos) - search_path = search_path.substr(search_path.find(':')+1); - else - search_path = ""; - - full_patch_path = directory +"/"+ filename; - - std::ifstream is; - is.open(full_patch_path.c_str(), std::ios::in); - - if (is.good()) { - is.close(); - return full_patch_path; - } else { - cerr << "[PatchLibrarian] Could not find patch file " << full_patch_path << endl; - } - } - - return ""; -} - - -/** Save a patch from a PatchModel to a filename. - * - * The filename passed is the true filename the patch will be saved to (with no prefixing or anything - * like that), and the patch_model's filename member will be set accordingly. - * - * This will break if: - * - The filename does not have an extension (ie contain a ".") - * - The patch_model has no (Om) path - */ -void -PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool recursive) -{ - assert(filename != ""); - assert(patch_model->path() != ""); - - cout << "Saving patch " << patch_model->path() << " to " << filename << endl; - - patch_model->filename(filename); - - string dir = filename.substr(0, filename.find_last_of("/")); - - NodeModel* nm = NULL; - PatchModel* spm = NULL; // subpatch model - - xmlDocPtr xml_doc = NULL; - xmlNodePtr xml_root_node = NULL; - xmlNodePtr xml_node = NULL; - xmlNodePtr xml_child_node = NULL; - xmlNodePtr xml_grandchild_node = NULL; - - xml_doc = xmlNewDoc((xmlChar*)"1.0"); - xml_root_node = xmlNewNode(NULL, (xmlChar*)"patch"); - xmlDocSetRootElement(xml_doc, xml_root_node); - - const size_t temp_buf_length = 255; - char temp_buf[temp_buf_length]; - - string patch_name; - if (patch_model->path() != "/") { - patch_name = patch_model->name(); - } else { - patch_name = filename; - if (patch_name.find("/") != string::npos) - patch_name = patch_name.substr(patch_name.find_last_of("/") + 1); - if (patch_name.find(".") != string::npos) - patch_name = patch_name.substr(0, patch_name.find_last_of(".")); - } - - assert(patch_name.length() > 0); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"name", - (xmlChar*)patch_name.c_str()); - - snprintf(temp_buf, temp_buf_length, "%zd", patch_model->poly()); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); - - // Write metadata - for (map::const_iterator i = patch_model->metadata().begin(); - i != patch_model->metadata().end(); ++i) { - // Dirty hack, don't save coordinates in patch file - if ((*i).first != "module-x" && (*i).first != "module-y" - && (*i).first != "filename") - xml_node = xmlNewChild(xml_root_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - - assert((*i).first != "node"); - assert((*i).first != "subpatch"); - assert((*i).first != "name"); - assert((*i).first != "polyphony"); - assert((*i).first != "preset"); - } - - // Save nodes and subpatches - for (NodeModelMap::const_iterator i = patch_model->nodes().begin(); i != patch_model->nodes().end(); ++i) { - nm = i->second; - - if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch - spm = (PatchModel*)i->second; - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->name().c_str()); - - string ref_filename; - // No path - if (spm->filename() == "") { - ref_filename = spm->name() + ".om"; - spm->filename(dir +"/"+ ref_filename); - // Absolute path - } else if (spm->filename().substr(0, 1) == "/") { - // Attempt to make it a relative path, if it's undernath this patch's dir - if (dir.substr(0, 1) == "/" && spm->filename().substr(0, dir.length()) == dir) { - ref_filename = spm->filename().substr(dir.length()+1); - } else { // FIXME: not good - ref_filename = spm->filename().substr(spm->filename().find_last_of("/")+1); - spm->filename(dir +"/"+ ref_filename); - } - } else { - ref_filename = spm->filename(); - } - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"filename", (xmlChar*)ref_filename.c_str()); - - snprintf(temp_buf, temp_buf_length, "%zd", spm->poly()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); - - // Write metadata - for (map::const_iterator i = nm->metadata().begin(); - i != nm->metadata().end(); ++i) { - // Dirty hack, don't save metadata that would be in patch file - if ((*i).first != "polyphony" && (*i).first != "filename" - && (*i).first != "author" && (*i).first != "description") - xml_child_node = xmlNewChild(xml_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - } - - if (recursive) - save_patch(spm, spm->filename(), true); - - } else { // Normal node - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"node", NULL); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)nm->name().c_str()); - - if (nm->plugin() == NULL) break; - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphonic", - (xmlChar*)((nm->polyphonic()) ? "true" : "false")); - - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"type", - (xmlChar*)nm->plugin()->type_string()); - /* - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-label", - (xmlChar*)(nm->plugin()->plug_label().c_str())); - - if (nm->plugin()->type() != PluginModel::Internal) { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"library-name", - (xmlChar*)(nm->plugin()->lib_name().c_str())); - }*/ - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-uri", - (xmlChar*)(nm->plugin()->uri().c_str())); - - // Write metadata - for (map::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) { - // DSSI _hack_ (FIXME: fix OSC to be more like this and not smash DSSI into metadata?) - if ((*i).first.substr(0, 16) == "dssi-configure--") { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-configure", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"key", (xmlChar*)(*i).first.substr(16).c_str()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"value", (xmlChar*)(*i).second.c_str()); - } else if ((*i).first == "dssi-program") { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-program", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"bank", (xmlChar*)(*i).second.substr(0, (*i).second.find("/")).c_str()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, - (xmlChar*)"program", (xmlChar*)(*i).second.substr((*i).second.find("/")+1).c_str()); - } else { - xml_child_node = xmlNewChild(xml_node, NULL, - (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); - } - } - - PortModel* pm = NULL; - // Write port metadata, if necessary - for (list::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) { - pm = (*i); - if (pm->is_input() && pm->user_min() != pm->min_val() || pm->user_max() != pm->max_val()) { - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port", NULL); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", pm->user_min()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-min", (xmlChar*)temp_buf); - snprintf(temp_buf, temp_buf_length, "%f", pm->user_max()); - xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-max", (xmlChar*)temp_buf); - } - } - } - } - - // Save connections - - const list& cl = patch_model->connections(); - const ConnectionModel* c = NULL; - - for (list::const_iterator i = cl.begin(); i != cl.end(); ++i) { - c = (*i); - xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"connection", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-node", - (xmlChar*)c->src_port_path().parent().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-port", - (xmlChar*)c->src_port_path().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-node", - (xmlChar*)c->dst_port_path().parent().name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-port", - (xmlChar*)c->dst_port_path().name().c_str()); - } - - // Save control values (ie presets eventually, right now just current control vals) - - xmlNodePtr xml_preset_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"preset", NULL); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"name", (xmlChar*)"default"); - - PortModel* pm = NULL; - - // Save node port controls - for (NodeModelMap::const_iterator n = patch_model->nodes().begin(); n != patch_model->nodes().end(); ++n) { - nm = n->second; - for (PortModelList::const_iterator p = nm->ports().begin(); p != nm->ports().end(); ++p) { - pm = *p; - if (pm->is_input() && pm->is_control()) { - float val = pm->value(); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"node-name", - (xmlChar*)nm->name().c_str()); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", val); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", - (xmlChar*)temp_buf); - } - } - } - - // Save patch port controls - for (PortModelList::const_iterator p = patch_model->ports().begin(); - p != patch_model->ports().end(); ++p) { - pm = *p; - if (pm->is_input() && pm->is_control()) { - float val = pm->value(); - xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", - (xmlChar*)pm->path().name().c_str()); - snprintf(temp_buf, temp_buf_length, "%f", val); - xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", - (xmlChar*)temp_buf); - } - } - - xmlSaveFormatFile(filename.c_str(), xml_doc, 1); // 1 == pretty print - - xmlFreeDoc(xml_doc); - xmlCleanupParser(); -} - - -/** Build a NodeModel given a pointer to a Node in a patch file. - */ -NodeModel* -PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) -{ - NodeModel* nm = new NodeModel("/UNINITIALIZED"); // FIXME: ew - PluginModel* plugin = new PluginModel(); - - xmlChar* key; - xmlNodePtr cur = node->xmlChildrenNode; - - bool found_name = false; - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - nm->set_path(parent->base_path() + (char*)key); - found_name = true; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) { - nm->polyphonic(!strcmp((char*)key, "true")); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) { - plugin->set_type((const char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"library-name"))) { - plugin->lib_name((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-label"))) { - plugin->plug_label((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-uri"))) { - plugin->uri((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"port"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string path; - float user_min = 0.0; - float user_max = 0.0; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"name"))) { - path = nm->base_path() + (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-min"))) { - user_min = atof((char*)key); - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-max"))) { - user_max = atof((char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - - // FIXME: nasty assumptions - PortModel* pm = new PortModel(path, - PortModel::CONTROL, PortModel::INPUT, PortModel::NONE, - 0.0, user_min, user_max); - nm->add_port(pm); - - // DSSI hacks. Stored in the patch files as special elements, but sent to - // the engine as normal metadata with specially formatted key/values. Not - // sure if this is the best way to go about this, but it's the least damaging - // right now - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-program"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string bank; - string program; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"bank"))) { - bank = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"program"))) { - program = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - child = child->next; - } - nm->set_metadata("dssi-program", bank +"/"+ program); - - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-configure"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string dssi_key; - string dssi_value; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"key"))) { - dssi_key = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { - dssi_value = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - nm->set_metadata(string("dssi-configure--").append(dssi_key), dssi_value); - - } else { // Don't know what this tag is, add it as metadata - if (key != NULL) - nm->set_metadata((const char*)cur->name, (const char*)key); - } - xmlFree(key); - key = NULL; - - cur = cur->next; - } - - if (nm->path() == "") { - cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl; - cerr << "[PatchLibrarian] Node ignored." << endl; - delete nm; - return NULL; - } else { - nm->plugin(plugin); - return nm; - } -} - - -void -PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr subpatch) -{ - xmlChar *key; - xmlNodePtr cur = subpatch->xmlChildrenNode; - - PatchModel* pm = new PatchModel("/UNINITIALIZED", 1); // FIXME: ew - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - if (parent == NULL) - pm->set_path(string("/") + (const char*)key); - else - pm->set_path(parent->base_path() + (const char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { - pm->poly(atoi((const char*)key)); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"filename"))) { - pm->filename((const char*)key); - } else { // Don't know what this tag is, add it as metadata - if (key != NULL && strlen((const char*)key) > 0) - pm->set_metadata((const char*)cur->name, (const char*)key); - } - xmlFree(key); - key = NULL; - - cur = cur->next; - } - - // This needs to be done after setting the path above, to prevent - // NodeModel::set_path from calling it's parent's rename_node with - // an invalid (nonexistant) name - pm->set_parent(parent); - - load_patch(pm, false); -} - - -/** Build a ConnectionModel given a pointer to a connection in a patch file. - */ -ConnectionModel* -PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) -{ - //cerr << "[PatchLibrarian] Parsing connection..." << endl; - - xmlChar *key; - xmlNodePtr cur = node->xmlChildrenNode; - - string source_node, source_port, dest_node, dest_port; - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-node"))) { - source_node = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-port"))) { - source_port = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-node"))) { - dest_node = (char*)key; - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-port"))) { - dest_port = (char*)key; - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - cur = cur->next; - } - - if (source_node == "" || source_port == "" || dest_node == "" || dest_port == "") { - cerr << "[PatchLibrarian] Malformed patch file (connection tag has empty children)" << endl; - cerr << "[PatchLibrarian] Connection ignored." << endl; - return NULL; - } - - // FIXME: temporary compatibility, remove any slashes from port names - // remove this soon once patches have migrated - string::size_type slash_index; - while ((slash_index = source_port.find("/")) != string::npos) - source_port[slash_index] = '-'; - - while ((slash_index = dest_port.find("/")) != string::npos) - dest_port[slash_index] = '-'; - - ConnectionModel* cm = new ConnectionModel(parent->base_path() + source_node +"/"+ source_port, - parent->base_path() + dest_node +"/"+ dest_port); - - return cm; -} - - -/** Build a PresetModel given a pointer to a preset in a patch file. - */ -PresetModel* -PatchLibrarian::parse_preset(const PatchModel* patch, xmlDocPtr doc, const xmlNodePtr node) -{ - xmlNodePtr cur = node->xmlChildrenNode; - xmlChar* key; - - PresetModel* pm = new PresetModel(patch->base_path()); - - while (cur != NULL) { - key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - - if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { - assert(key != NULL); - pm->name((char*)key); - } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"control"))) { - xmlNodePtr child = cur->xmlChildrenNode; - - string node_name = "", port_name = ""; - float val = 0.0; - - while (child != NULL) { - key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); - - if ((!xmlStrcmp(child->name, (const xmlChar*)"node-name"))) { - node_name = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"port-name"))) { - port_name = (char*)key; - } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { - val = atof((char*)key); - } - - xmlFree(key); - key = NULL; // Avoid a (possible?) double free - - child = child->next; - } - - if (port_name == "") { - string msg = "Unable to parse control in patch file ( node = "; - msg.append(node_name).append(", port = ").append(port_name).append(")"); - m_client_hooks->error(msg); - } else { - // FIXME: temporary compatibility, remove any slashes from port name - // remove this soon once patches have migrated - string::size_type slash_index; - while ((slash_index = port_name.find("/")) != string::npos) - port_name[slash_index] = '-'; - pm->add_control(node_name, port_name, val); - } - } - xmlFree(key); - key = NULL; - cur = cur->next; - } - if (pm->name() == "") { - m_client_hooks->error("Preset in patch file has no name."); - pm->name("Unnamed"); - } - - return pm; -} -#endif - - -} // namespace LibOmClient diff --git a/src/clients/new/PatchLibrarian.h b/src/clients/new/PatchLibrarian.h deleted file mode 100644 index ac69f0f5..00000000 --- a/src/clients/new/PatchLibrarian.h +++ /dev/null @@ -1,66 +0,0 @@ -/* This file is part of Om. 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 PATCHLIBRARIAN_H -#define PATCHLIBRARIAN_H - -#include -#include -#include "util/Path.h" -#include "EngineInterface.h" -using std::string; -using Om::Path; -using Om::Shared::EngineInterface; - -namespace LibOmClient { - - -/** Loads patch files, sending the necessary messages to an EngineInterface - * to recreate the patch. - * - * Because this only uses EngineInterface, this same code can be used to load - * patches client side or server side. - * - * \ingroup libomclient - */ -class PatchLibrarian -{ -public: - - //static void save_patch(PatchModel* patch_model, const string& filename, bool recursive); - - static bool - PatchLibrarian::load_patch(EngineInterface* engine, - const string& filename, - const Path& parent_path = "/", - string name = "", - uint32_t poly = 0); - -private: - PatchLibrarian() {} - - /* - static NodeModel* parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - static ConnectionModel* parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - static PresetModel* parse_preset(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - static void load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); - */ -}; - - -} // namespace LibOmClient - -#endif // PATCHLIBRARIAN_H diff --git a/src/clients/new/patch_loader/Makefile.am b/src/clients/new/patch_loader/Makefile.am deleted file mode 100644 index 1448ac92..00000000 --- a/src/clients/new/patch_loader/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -EXTRA_DIST = README - -om_patch_loader_CXXFLAGS = -I$(top_srcdir)/src/clients -I$(top_srcdir)/src/common/util -I$(top_srcdir)/src/common/interface -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) -om_patch_loader_LDADD = ../libomclient.a $(LOSC_LIBS) $(LXML2_LIBS) - -bin_PROGRAMS = om_patch_loader - -om_patch_loader_DEPENDENCIES = ../libomclient.a - -om_patch_loader_SOURCES = \ - patch_loader.cpp \ - cmdline.h \ - cmdline.c diff --git a/src/clients/new/patch_loader/README b/src/clients/new/patch_loader/README deleted file mode 100644 index 9f3b6f4b..00000000 --- a/src/clients/new/patch_loader/README +++ /dev/null @@ -1,5 +0,0 @@ -This is a stand-alone patch loader for Om. It has no user interface, it -just launches, loads the patch(es) passed as a parameter, and exits. - -Useful for loading patches from scripts, other apps, etc. or just using -Om patches without loading the GUI. diff --git a/src/clients/new/patch_loader/cmdline.c b/src/clients/new/patch_loader/cmdline.c deleted file mode 100644 index 0606cb7b..00000000 --- a/src/clients/new/patch_loader/cmdline.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - File autogenerated by gengetopt version 2.10 - generated with the following command: - gengetopt -u - - The developers of gengetopt consider the fixed text that goes in all - gengetopt output files to be in the public domain: - we make no copyright claims on it. -*/ - - -#include -#include -#include - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "getopt.h" - -#include "cmdline.h" - -void -cmdline_parser_print_version (void) -{ - printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); -} - -void -cmdline_parser_print_help (void) -{ - cmdline_parser_print_version (); - printf("\n" - "Usage: %s [OPTIONS]... [FILES]...\n", CMDLINE_PARSER_PACKAGE); - printf(" -h --help Print help and exit\n"); - printf(" -V --version Print version and exit\n"); - printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n"); - printf(" -pINT --client-port=INT Client port to listen on\n"); -} - - -static char *gengetopt_strdup (const char *s); - -/* gengetopt_strdup() */ -/* strdup.c replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) -{ - char *result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; -} - -int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) -{ - int c; /* Character of the parsed option. */ - int missing_required_options = 0; - - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->engine_url_given = 0 ; - args_info->client_port_given = 0 ; -#define clear_args() { \ - args_info->engine_url_arg = NULL; \ -} - - clear_args(); - - args_info->inputs = NULL; - args_info->inputs_num = 0; - - optarg = 0; - optind = 1; - opterr = 1; - optopt = '?'; - - while (1) - { - int option_index = 0; - char *stop_char; - - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "engine-url", 1, NULL, 'u' }, - { "client-port", 1, NULL, 'p' }, - { NULL, 0, NULL, 0 } - }; - - stop_char = 0; - c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index); - - if (c == -1) break; /* Exit from `while (1)' loop. */ - - switch (c) - { - case 'h': /* Print help and exit. */ - clear_args (); - cmdline_parser_print_help (); - exit (EXIT_SUCCESS); - - case 'V': /* Print version and exit. */ - clear_args (); - cmdline_parser_print_version (); - exit (EXIT_SUCCESS); - - case 'u': /* Om engine URL to connect to. */ - if (args_info->engine_url_given) - { - fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->engine_url_given = 1; - args_info->engine_url_arg = gengetopt_strdup (optarg); - break; - - case 'p': /* Client port to listen on. */ - if (args_info->client_port_given) - { - fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->client_port_given = 1; - args_info->client_port_arg = strtol (optarg,&stop_char,0); - break; - - - case 0: /* Long option with no short option */ - - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - exit (EXIT_FAILURE); - - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); - abort (); - } /* switch */ - } /* while */ - - - if ( missing_required_options ) - exit (EXIT_FAILURE); - - if (optind < argc) - { - int i = 0 ; - - args_info->inputs_num = argc - optind ; - args_info->inputs = - (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ; - while (optind < argc) - args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind++]) ; - } - - return 0; -} diff --git a/src/clients/new/patch_loader/cmdline.ggo b/src/clients/new/patch_loader/cmdline.ggo deleted file mode 100644 index 5acd6737..00000000 --- a/src/clients/new/patch_loader/cmdline.ggo +++ /dev/null @@ -1,7 +0,0 @@ -# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) - -package "om_patch_loader - A command line patch loading client for Om" - -option "engine-url" u "Om engine URL to connect to" string no -option "client-port" p "Client port to listen on" int no - diff --git a/src/clients/new/patch_loader/cmdline.h b/src/clients/new/patch_loader/cmdline.h deleted file mode 100644 index b417c664..00000000 --- a/src/clients/new/patch_loader/cmdline.h +++ /dev/null @@ -1,47 +0,0 @@ -/* cmdline.h */ - -/* File autogenerated by gengetopt version 2.10 */ - -#ifndef CMDLINE_H -#define CMDLINE_H - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef CMDLINE_PARSER_PACKAGE -#define CMDLINE_PARSER_PACKAGE "om_patch_loader - A command line patch loading client for the Om realtime modular synthesizer" -#endif - -#ifndef CMDLINE_PARSER_VERSION -#define CMDLINE_PARSER_VERSION VERSION -#endif - -struct gengetopt_args_info -{ - char * engine_url_arg; /* Om engine URL to connect to. */ - int client_port_arg; /* Client port to listen on. */ - - int help_given ; /* Whether help was given. */ - int version_given ; /* Whether version was given. */ - int engine_url_given ; /* Whether engine-url was given. */ - int client_port_given ; /* Whether client-port was given. */ - - char **inputs ; /* unamed options */ - unsigned inputs_num ; /* unamed options number */ -} ; - -int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); - -void cmdline_parser_print_help(void); -void cmdline_parser_print_version(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CMDLINE_H */ diff --git a/src/clients/new/patch_loader/patch_loader.cpp b/src/clients/new/patch_loader/patch_loader.cpp deleted file mode 100644 index 8884e85b..00000000 --- a/src/clients/new/patch_loader/patch_loader.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* This file is part of Om. 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 -#include -#include "cmdline.h" // generated by gengetopt -#include "util/Path.h" -#include "OSCEngineInterface.h" -#include "PatchLibrarian.h" - -using std::cout; using std::cerr; using std::endl; -using Om::Path; - -using namespace LibOmClient; - - -int -main(int argc, char** argv) -{ - const char* engine_url = NULL; - int client_port = 0; - - /* Parse command line options */ - gengetopt_args_info args_info; - if (cmdline_parser (argc, argv, &args_info) != 0) - return 1; - - if (args_info.engine_url_given) { - engine_url = args_info.engine_url_arg; - } else { - cout << "[Main] No engine URL specified. Attempting to use osc.udp://localhost:16180" << endl; - engine_url = "osc.udp://localhost:16180"; - } - - if (args_info.client_port_given) - client_port = args_info.client_port_arg; - else - client_port = 0; // will choose a free port automatically - - OSCEngineInterface engine(engine_url); - - /* Connect to engine */ - if (!engine.attach()) { - cerr << "Unable to connect to engine" << endl; - return 1; - } - - engine.activate(); - engine.register_client(); - - /*int id = engine.get_next_request_id(); - engine.set_wait_response_id(id); - engine.load_plugins(id); - engine.wait_for_response(); - */ - engine.load_plugins(); - - // Load patches - for (uint i=0; i < args_info.inputs_num; ++i) - PatchLibrarian::load_patch(&engine, args_info.inputs[i]); - - return 0; -} diff --git a/src/clients/patch_loader/Makefile.am b/src/clients/patch_loader/Makefile.am deleted file mode 100644 index 15e0c503..00000000 --- a/src/clients/patch_loader/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -EXTRA_DIST = README - -om_patch_loader_CXXFLAGS = -I$(top_srcdir)/src/clients -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) -om_patch_loader_LDADD = ../libomclient.a $(LOSC_LIBS) $(LXML2_LIBS) - -bin_PROGRAMS = om_patch_loader - -om_patch_loader_DEPENDENCIES = ../libomclient.a - -om_patch_loader_SOURCES = \ - patch_loader.cpp \ - cmdline.h \ - cmdline.c diff --git a/src/clients/patch_loader/README b/src/clients/patch_loader/README deleted file mode 100644 index 9f3b6f4b..00000000 --- a/src/clients/patch_loader/README +++ /dev/null @@ -1,5 +0,0 @@ -This is a stand-alone patch loader for Om. It has no user interface, it -just launches, loads the patch(es) passed as a parameter, and exits. - -Useful for loading patches from scripts, other apps, etc. or just using -Om patches without loading the GUI. diff --git a/src/clients/patch_loader/cmdline.c b/src/clients/patch_loader/cmdline.c deleted file mode 100644 index 0606cb7b..00000000 --- a/src/clients/patch_loader/cmdline.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - File autogenerated by gengetopt version 2.10 - generated with the following command: - gengetopt -u - - The developers of gengetopt consider the fixed text that goes in all - gengetopt output files to be in the public domain: - we make no copyright claims on it. -*/ - - -#include -#include -#include - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "getopt.h" - -#include "cmdline.h" - -void -cmdline_parser_print_version (void) -{ - printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); -} - -void -cmdline_parser_print_help (void) -{ - cmdline_parser_print_version (); - printf("\n" - "Usage: %s [OPTIONS]... [FILES]...\n", CMDLINE_PARSER_PACKAGE); - printf(" -h --help Print help and exit\n"); - printf(" -V --version Print version and exit\n"); - printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n"); - printf(" -pINT --client-port=INT Client port to listen on\n"); -} - - -static char *gengetopt_strdup (const char *s); - -/* gengetopt_strdup() */ -/* strdup.c replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) -{ - char *result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; -} - -int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) -{ - int c; /* Character of the parsed option. */ - int missing_required_options = 0; - - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->engine_url_given = 0 ; - args_info->client_port_given = 0 ; -#define clear_args() { \ - args_info->engine_url_arg = NULL; \ -} - - clear_args(); - - args_info->inputs = NULL; - args_info->inputs_num = 0; - - optarg = 0; - optind = 1; - opterr = 1; - optopt = '?'; - - while (1) - { - int option_index = 0; - char *stop_char; - - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "engine-url", 1, NULL, 'u' }, - { "client-port", 1, NULL, 'p' }, - { NULL, 0, NULL, 0 } - }; - - stop_char = 0; - c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index); - - if (c == -1) break; /* Exit from `while (1)' loop. */ - - switch (c) - { - case 'h': /* Print help and exit. */ - clear_args (); - cmdline_parser_print_help (); - exit (EXIT_SUCCESS); - - case 'V': /* Print version and exit. */ - clear_args (); - cmdline_parser_print_version (); - exit (EXIT_SUCCESS); - - case 'u': /* Om engine URL to connect to. */ - if (args_info->engine_url_given) - { - fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->engine_url_given = 1; - args_info->engine_url_arg = gengetopt_strdup (optarg); - break; - - case 'p': /* Client port to listen on. */ - if (args_info->client_port_given) - { - fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->client_port_given = 1; - args_info->client_port_arg = strtol (optarg,&stop_char,0); - break; - - - case 0: /* Long option with no short option */ - - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - exit (EXIT_FAILURE); - - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); - abort (); - } /* switch */ - } /* while */ - - - if ( missing_required_options ) - exit (EXIT_FAILURE); - - if (optind < argc) - { - int i = 0 ; - - args_info->inputs_num = argc - optind ; - args_info->inputs = - (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ; - while (optind < argc) - args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind++]) ; - } - - return 0; -} diff --git a/src/clients/patch_loader/cmdline.ggo b/src/clients/patch_loader/cmdline.ggo deleted file mode 100644 index 5acd6737..00000000 --- a/src/clients/patch_loader/cmdline.ggo +++ /dev/null @@ -1,7 +0,0 @@ -# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) - -package "om_patch_loader - A command line patch loading client for Om" - -option "engine-url" u "Om engine URL to connect to" string no -option "client-port" p "Client port to listen on" int no - diff --git a/src/clients/patch_loader/cmdline.h b/src/clients/patch_loader/cmdline.h deleted file mode 100644 index b417c664..00000000 --- a/src/clients/patch_loader/cmdline.h +++ /dev/null @@ -1,47 +0,0 @@ -/* cmdline.h */ - -/* File autogenerated by gengetopt version 2.10 */ - -#ifndef CMDLINE_H -#define CMDLINE_H - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef CMDLINE_PARSER_PACKAGE -#define CMDLINE_PARSER_PACKAGE "om_patch_loader - A command line patch loading client for the Om realtime modular synthesizer" -#endif - -#ifndef CMDLINE_PARSER_VERSION -#define CMDLINE_PARSER_VERSION VERSION -#endif - -struct gengetopt_args_info -{ - char * engine_url_arg; /* Om engine URL to connect to. */ - int client_port_arg; /* Client port to listen on. */ - - int help_given ; /* Whether help was given. */ - int version_given ; /* Whether version was given. */ - int engine_url_given ; /* Whether engine-url was given. */ - int client_port_given ; /* Whether client-port was given. */ - - char **inputs ; /* unamed options */ - unsigned inputs_num ; /* unamed options number */ -} ; - -int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); - -void cmdline_parser_print_help(void); -void cmdline_parser_print_version(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CMDLINE_H */ diff --git a/src/clients/patch_loader/new_patch_loader.cpp b/src/clients/patch_loader/new_patch_loader.cpp deleted file mode 100644 index 8884e85b..00000000 --- a/src/clients/patch_loader/new_patch_loader.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* This file is part of Om. 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 -#include -#include "cmdline.h" // generated by gengetopt -#include "util/Path.h" -#include "OSCEngineInterface.h" -#include "PatchLibrarian.h" - -using std::cout; using std::cerr; using std::endl; -using Om::Path; - -using namespace LibOmClient; - - -int -main(int argc, char** argv) -{ - const char* engine_url = NULL; - int client_port = 0; - - /* Parse command line options */ - gengetopt_args_info args_info; - if (cmdline_parser (argc, argv, &args_info) != 0) - return 1; - - if (args_info.engine_url_given) { - engine_url = args_info.engine_url_arg; - } else { - cout << "[Main] No engine URL specified. Attempting to use osc.udp://localhost:16180" << endl; - engine_url = "osc.udp://localhost:16180"; - } - - if (args_info.client_port_given) - client_port = args_info.client_port_arg; - else - client_port = 0; // will choose a free port automatically - - OSCEngineInterface engine(engine_url); - - /* Connect to engine */ - if (!engine.attach()) { - cerr << "Unable to connect to engine" << endl; - return 1; - } - - engine.activate(); - engine.register_client(); - - /*int id = engine.get_next_request_id(); - engine.set_wait_response_id(id); - engine.load_plugins(id); - engine.wait_for_response(); - */ - engine.load_plugins(); - - // Load patches - for (uint i=0; i < args_info.inputs_num; ++i) - PatchLibrarian::load_patch(&engine, args_info.inputs[i]); - - return 0; -} diff --git a/src/clients/patch_loader/patch_loader.cpp b/src/clients/patch_loader/patch_loader.cpp deleted file mode 100644 index e8579ed7..00000000 --- a/src/clients/patch_loader/patch_loader.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* This file is part of Om. 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 "OSCModelEngineInterface.h" -#include "PatchLibrarian.h" -#include "PatchModel.h" -#include "util/Path.h" -#include -#include -#include "cmdline.h" // generated by gengetopt - -using std::cout; using std::endl; -using Om::Path; - -using namespace LibOmClient; - -int main(int argc, char** argv) -{ - const char* engine_url = NULL; - int client_port = 0; - - /* **** Parse command line options **** */ - - gengetopt_args_info args_info; - if (cmdline_parser (argc, argv, &args_info) != 0) - return 1; - - if (args_info.engine_url_given) { - engine_url = args_info.engine_url_arg; - } else { - cout << "[Main] No engine URL specified. Attempting to use osc.udp://localhost:16180" << endl; - engine_url = "osc.udp://localhost:16180"; - } - - if (args_info.client_port_given) - client_port = args_info.client_port_arg; - - - /* **** Mr. Spock.. Engage **** */ - - - OSCModelEngineInterface osc_controller(engine_url); - PatchLibrarian librarian(&osc_controller); - - /* Connect to engine */ - osc_controller.attach(client_port); - osc_controller.activate(); - //osc_controller.register_client(NULL); // FIXME - - //int id = osc_controller.get_next_request_id(); - //osc_controller.set_wait_response_id(id); - //osc_controller.load_plugins(id); - //osc_controller.wait_for_response(); - /* FIXME: Make this work like this: - * osc_controller.load_plugins(); - * osc_controller.wait_for_response(); - */ - - // Load patches - for (uint i=0; i < args_info.inputs_num; ++i) { - PatchModel* pm = new PatchModel("", 0); - pm->filename(args_info.inputs[i]); - librarian.load_patch(pm, true); - delete pm; - } - - return 0; -} diff --git a/src/clients/python/Makefile.am b/src/clients/python/Makefile.am deleted file mode 100644 index 017b1f4b..00000000 --- a/src/clients/python/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -SUBDIRS = scripts - -EXTRA_DIST = omecho.py omsynth.py OSC.py - diff --git a/src/clients/python/OSC.py b/src/clients/python/OSC.py deleted file mode 100755 index 74eb5880..00000000 --- a/src/clients/python/OSC.py +++ /dev/null @@ -1,374 +0,0 @@ -#!/usr/bin/python -# -# Open SoundControl for Python -# Copyright (C) 2002 Daniel Holth, Clinton McChesney -# Modified by Leonard Ritter -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# For questions regarding this module contact -# Daniel Holth or visit -# http://www.stetson.edu/~ProctoLogic/ - -import socket -import struct -import math -import sys -import string - - -def hexDump(bytes): - """Useful utility; prints the string in hexadecimal""" - for i in range(len(bytes)): - sys.stdout.write("%2x " % (ord(bytes[i]))) - if (i+1) % 8 == 0: - print repr(bytes[i-7:i+1]) - - if(len(bytes) % 8 != 0): - print string.rjust("", 11), repr(bytes[i-7:i+1]) - - -class OSCMessage: - """Builds typetagged OSC messages.""" - def __init__(self): - self.address = "" - self.typetags = "," - self.message = "" - - def setAddress(self, address): - self.address = address - - def setMessage(self, message): - self.message = message - - def setTypetags(self, typetags): - self.typetags = typetags - - def clear(self): - self.address = "" - self.clearData() - - def clearData(self): - self.typetags = "," - self.message = "" - - def append(self, argument, typehint = None): - """Appends data to the message, - updating the typetags based on - the argument's type. - If the argument is a blob (counted string) - pass in 'b' as typehint.""" - - if typehint == 'b': - binary = OSCBlob(argument) - else: - binary = OSCArgument(argument) - - self.typetags = self.typetags + binary[0] - self.rawAppend(binary[1]) - - def rawAppend(self, data): - """Appends raw data to the message. Use append().""" - self.message = self.message + data - - def getBinary(self): - """Returns the binary message (so far) with typetags.""" - address = OSCArgument(self.address)[1] - typetags = OSCArgument(self.typetags)[1] - return address + typetags + self.message - - def __repr__(self): - return self.getBinary() - -def readString(data): - length = string.find(data,"\0") - nextData = int(math.ceil((length+1) / 4.0) * 4) - return (data[0:length], data[nextData:]) - - -def readBlob(data): - length = struct.unpack(">i", data[0:4])[0] - nextData = int(math.ceil((length) / 4.0) * 4) + 4 - return (data[4:length+4], data[nextData:]) - - -def readInt(data): - if(len(data)<4): - print "Error: too few bytes for int", data, len(data) - rest = data - integer = 0 - else: - integer = struct.unpack(">i", data[0:4])[0] - rest = data[4:] - - return (integer, rest) - - - -def readLong(data): - """Tries to interpret the next 8 bytes of the data - as a 64-bit signed integer.""" - high, low = struct.unpack(">ll", data[0:8]) - big = (long(high) << 32) + low - rest = data[8:] - return (big, rest) - - - -def readFloat(data): - if(len(data)<4): - print "Error: too few bytes for float", data, len(data) - rest = data - float = 0 - else: - float = struct.unpack(">f", data[0:4])[0] - rest = data[4:] - - return (float, rest) - - -def OSCBlob(next): - """Convert a string into an OSC Blob, - returning a (typetag, data) tuple.""" - - if type(next) == type(""): - length = len(next) - padded = math.ceil((len(next)) / 4.0) * 4 - binary = struct.pack(">i%ds" % (padded), length, next) - tag = 'b' - else: - tag = '' - binary = '' - - return (tag, binary) - - -def OSCArgument(next): - """Convert some Python types to their - OSC binary representations, returning a - (typetag, data) tuple.""" - - if type(next) == type(""): - OSCstringLength = math.ceil((len(next)+1) / 4.0) * 4 - binary = struct.pack(">%ds" % (OSCstringLength), next) - tag = "s" - elif type(next) == type(42.5): - binary = struct.pack(">f", next) - tag = "f" - elif type(next) == type(13): - binary = struct.pack(">i", next) - tag = "i" - else: - binary = "" - tag = "" - - return (tag, binary) - - -def parseArgs(args): - """Given a list of strings, produces a list - where those strings have been parsed (where - possible) as floats or integers.""" - parsed = [] - for arg in args: - print arg - arg = arg.strip() - interpretation = None - try: - interpretation = float(arg) - if string.find(arg, ".") == -1: - interpretation = int(interpretation) - except: - # Oh - it was a string. - interpretation = arg - pass - parsed.append(interpretation) - return parsed - - - -def decodeOSC(data): - """Converts a typetagged OSC message to a Python list.""" - table = {"i":readInt, "f":readFloat, "s":readString, "b":readBlob} - decoded = [] - address, rest = readString(data) - typetags = "" - - if address == "#bundle": - time, rest = readLong(rest) - decoded.append(address) - decoded.append(time) - while len(rest)>0: - length, rest = readInt(rest) - decoded.append(decodeOSC(rest[:length])) - rest = rest[length:] - - elif len(rest)>0: - typetags, rest = readString(rest) - decoded.append(address) - decoded.append(typetags) - if(typetags[0] == ","): - for tag in typetags[1:]: - value, rest = table[tag](rest) - decoded.append(value) - else: - print "Oops, typetag lacks the magic ," - - # return only the data - return address,decoded[2:] - - -class CallbackManager: - """This utility class maps OSC addresses to callables. - - The CallbackManager calls its callbacks with a list - of decoded OSC arguments, including the address and - the typetags as the first two arguments.""" - - def __init__(self): - self.callbacks = {} - self.addCallback(self.unbundler, "#bundle") - - def handle(self, data, source = None): - """Given OSC data, tries to call the callback with the - right address.""" - decoded = decodeOSC(data) - self.dispatch(decoded) - - def dispatch(self, message): - """Sends decoded OSC data to an appropriate calback""" - try: - address = message[0] - self.callbacks[address](message) - except KeyError, e: - # address not found - print "no handler for '%s'" % address - pass - except None, e: - print "Exception in", address, "callback :", e - - return - - def addCallback(self, callback, name): - """Adds a callback to our set of callbacks, - or removes the callback with name if callback - is None.""" - if callback == None: - del self.callbacks[name] - else: - self.callbacks[name] = callback - - def unbundler(self, messages): - """Dispatch the messages in a decoded bundle.""" - # first two elements are #bundle and the time tag, rest are messages. - for message in messages[2:]: - self.dispatch(message) - - -if __name__ == "__main__": - hexDump("Welcome to the OSC testing program.") - print - message = OSCMessage() - message.setAddress("/foo/play") - message.append(44) - message.append(11) - message.append(4.5) - message.append("the white cliffs of dover") - hexDump(message.getBinary()) - - print "Making and unmaking a message.." - - strings = OSCMessage() - strings.append("Mary had a little lamb") - strings.append("its fleece was white as snow") - strings.append("and everywhere that Mary went,") - strings.append("the lamb was sure to go.") - strings.append(14.5) - strings.append(14.5) - strings.append(-400) - - raw = strings.getBinary() - - hexDump(raw) - - print "Retrieving arguments..." - data = raw - for i in range(6): - text, data = readString(data) - print text - - number, data = readFloat(data) - print number - - number, data = readFloat(data) - print number - - number, data = readInt(data) - print number - - hexDump(raw) - print decodeOSC(raw) - print decodeOSC(message.getBinary()) - - print "Testing Blob types." - - blob = OSCMessage() - blob.append("","b") - blob.append("b","b") - blob.append("bl","b") - blob.append("blo","b") - blob.append("blob","b") - blob.append("blobs","b") - blob.append(42) - - hexDump(blob.getBinary()) - - print decodeOSC(blob.getBinary()) - - def printingCallback(stuff): - sys.stdout.write("Got: ") - for i in stuff: - sys.stdout.write(str(i) + " ") - sys.stdout.write("\n") - - print "Testing the callback manager." - - c = CallbackManager() - c.add(printingCallback, "/print") - - c.handle(message.getBinary()) - message.setAddress("/print") - c.handle(message.getBinary()) - - print1 = OSCMessage() - print1.setAddress("/print") - print1.append("Hey man, that's cool.") - print1.append(42) - print1.append(3.1415926) - - c.handle(print1.getBinary()) - - bundle = OSCMessage() - bundle.setAddress("") - bundle.append("#bundle") - bundle.append(0) - bundle.append(0) - bundle.append(print1.getBinary(), 'b') - bundle.append(print1.getBinary(), 'b') - - bundlebinary = bundle.message - - print "sending a bundle to the callback manager" - c.handle(bundlebinary) diff --git a/src/clients/python/omecho.py b/src/clients/python/omecho.py deleted file mode 100644 index c0d2d3b1..00000000 --- a/src/clients/python/omecho.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/python -# -# Python bindings for Om -# Copyright (C) 2005 Leonard Ritter -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import omsynth -import os,time,sys - -def main(om): - om.setEnvironment(omsynth.Environment()) - om.engine.activate() - om.engine.register_client(om.getAddressAsString()) - om.request.all_objects(om.getAddressAsString()) - - om.request.all_objects() - time.sleep(3) - om.getEnvironment().printPatch() - om.getEnvironment().printConnections() - print "omecho will now monitor and mirror changes in the structure" - print "hit return to exit when youre done" - sys.stdin.readline() - om.engine.unregister_client(om.getAddressAsString()) - os._exit(0) - -if __name__ == "__main__": - omsynth.startClient(main) diff --git a/src/clients/python/omsynth.py b/src/clients/python/omsynth.py deleted file mode 100644 index d7cfa5ab..00000000 --- a/src/clients/python/omsynth.py +++ /dev/null @@ -1,635 +0,0 @@ -#!/usr/bin/python -# -# Python bindings for Om -# Copyright (C) 2005 Leonard Ritter -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os,sys,thread,time - -from OSC import OSCMessage, decodeOSC - -from twisted.internet.protocol import DatagramProtocol -from twisted.internet import reactor - -OM_CALL_TIMEOUT = 5 -OM_CALL_POLLTIME = 0.1 - -class TreeElement: - def __init__(self,environment,parent,name): - self.environment = environment - self.parent = parent - self.name = name - self.metadata = {} - - def __del__(self): - print "'%s': gone" % self.name - - def removeChild(self, child): - pass - - def remove(self): - self.parent.removeChild(self.name) - self.parent = None - del self - - def getParent(self): - return self.parent - - def getName(self): - return self.name - - def getPath(self): - if self.parent: - return self.parent.getPath() + "/" + self.name - else: - return self.name - - def getDepth(self): - if self.parent: - return self.parent.getDepth() + 1 - else: - return 0 - - def setMetaData(self,key,value): - if (not self.metadata.has_key(value)) or (self.metadata[key] != value): - print "||| '%s': '%s' = '%s'" % (self.getPath(), key, value) - self.metadata[key] = value - -class Port(TreeElement): - def __init__(self,environment,parent,name): - TreeElement.__init__(self,environment,parent,name) - self.porttype = "" - self.direction = "" - self.hint = "" - self.defaultvalue = 0.0 - self.minvalue = 0.0 - self.maxvalue = 0.0 - self.value = 0.0 - self.connections = {} - print "*** '%s': new port" % self.getPath() - - def remove(self): - for connection in self.getConnections(): - connection.remove() - TreeElement.remove(self) - - def getConnections(self): - return self.connections - - def addConnection(self,target,connection): - self.connections[target] = connection - - def removeConnection(self,target): - del self.connections[target] - - def setPortType(self,porttype): - if self.porttype != porttype: - print "*** '%s': changing porttype from '%s' to '%s'" % (self.getPath(), self.porttype, porttype) - self.porttype = porttype - - def setDirection(self,direction): - if self.direction != direction: - print "*** '%s': changing direction from '%s' to '%s'" % (self.getPath(), self.direction, direction) - self.direction = direction - - def setHint(self,hint): - if self.hint != hint: - print "*** '%s': changing hint from '%s' to '%s'" % (self.getPath(), self.hint, hint) - self.hint = hint - - def setDefaultValue(self,defaultvalue): - if self.defaultvalue != defaultvalue: - print "*** '%s': changing defaultvalue from '%.3f' to '%.3f'" % (self.getPath(), self.defaultvalue, defaultvalue) - self.defaultvalue = defaultvalue - - def setMinValue(self,minvalue): - if self.minvalue != minvalue: - print "*** '%s': changing minvalue from '%.3f' to '%.3f'" % (self.getPath(), self.minvalue, minvalue) - self.minvalue = minvalue - - def setMaxValue(self,maxvalue): - if self.maxvalue != maxvalue: - print "*** '%s': changing maxvalue from '%.3f' to '%.3f'" % (self.getPath(), self.maxvalue, maxvalue) - self.maxvalue = maxvalue - - def setValue(self,value): - if self.value != value: - print "*** '%s': changing value from '%.3f' to '%.3f'" % (self.getPath(), self.value, value) - self.value = value - -class Node(TreeElement): - def __init__(self,environment,parent,name): - TreeElement.__init__(self,environment,parent,name) - self.ports = {} - self.polyphonic = 0 - self.plugintype = "" - self.libname = "" - self.pluginlabel = "" - print "+++ '%s': new node" % self.getPath() - - def remove(self): - for port in self.getPorts(): - port.remove() - TreeElement.remove(self) - - def removeChild(self, child): - del self.ports[child] - - def getPorts(self): - return self.ports.values() - - def setPluginLabel(self,pluginlabel): - if pluginlabel != self.pluginlabel: - print "+++ '%s': changing pluginlabel from '%s' to '%s'" % (self.getPath(), self.pluginlabel, pluginlabel) - self.pluginlabel = pluginlabel - - def setLibName(self,libname): - if libname != self.libname: - print "+++ '%s': changing libname from '%s' to '%s'" % (self.getPath(), self.libname, libname) - self.libname = libname - - def setPluginType(self,plugintype): - if plugintype != self.plugintype: - print "+++ '%s': changing plugintype from '%s' to '%s'" % (self.getPath(), self.plugintype, plugintype) - self.plugintype = plugintype - - def setPolyphonic(self,polyphonic): - if polyphonic != self.polyphonic: - print "+++ '%s': changing polyphony from %i to %i" % (self.getPath(), self.polyphonic, polyphonic) - self.polyphonic = polyphonic - - def hasPort(self,name): - return self.ports.has_key(name) - - def getPort(self,name,mustexist=False): - if not self.hasPort(name): - if mustexist: - return None - self.ports[name] = self.environment.getPortClass()(self.environment,self,name) - return self.ports[name] - -class Patch(Node): - def __init__(self,environment,parent,name): - Node.__init__(self,environment,parent,name) - self.nodes = {} - self.patches = {} - self.poly = 0 - self.enabled = False - print "### '%s': new patch" % self.getPath() - - def remove(self): - for patch in self.getPatches(): - patch.remove() - for node in self.getNodes(): - node.remove() - Node.remove(self) - - def removeChild(self, child): - if self.hasNode(child): - del self.nodes[child] - elif self.hasPatch(child): - del self.patches[child] - else: - Node.removeChild(self,child) - - def getPatches(self): - return self.patches.values() - - def getNodes(self): - return self.nodes.values() - - def getEnabled(self): - return self.enabled - - def setEnabled(self,enabled): - if enabled != self.enabled: - print "### '%s': changing enabled from %s to %s" % (self.getPath(), str(self.enabled), str(enabled)) - enabled = self.enabled - - def getPoly(self): - return self.poly - - def setPoly(self,poly): - if poly != self.poly: - print "### '%s': changing polyphony from %i to %i" % (self.getPath(), self.poly, poly) - self.poly = poly - - def hasNode(self,name): - return self.nodes.has_key(name) - - def getNode(self,name,mustexist=False): - if not self.hasNode(name): - if mustexist: - return None - self.nodes[name] = self.environment.getNodeClass()(self.environment,self,name) - return self.nodes[name] - - def hasPatch(self,name): - return self.patches.has_key(name) - - def getPatch(self,name,mustexist=False): - if not self.hasPatch(name): - if mustexist: - return None - self.patches[name] = self.environment.getPatchClass()(self.environment,self,name) - return self.patches[name] - -class Connection: - def __init__(self,environment,srcport,dstport): - self.environment = environment - self.srcport = srcport - self.dstport = dstport - self.srcport.addConnection(self.dstport,self) - self.dstport.addConnection(self.srcport,self) - print ">>> '%s'->'%s': new connection" % (self.srcport.getPath(),self.dstport.getPath()) - - def __del__(self): - print "connection gone" - - def remove(self): - self.srcport.removeConnection(self.dstport) - self.dstport.removeConnection(self.srcport) - del self - - def getSrcPort(self): - return self.srcport - - def getDstPort(self): - return self.dstport - - def getPortPair(self): - return self.srcport, self.dstport - -class Environment: - def __init__(self): - self.omPatch = self.getPatchClass()(self,None,"") - self.enabled = False - self.connections = {} - - def getConnectionClass(self): - return Connection - - def getPatchClass(self): - return Patch - - def getNodeClass(self): - return Node - - def getPortClass(self): - return Port - - def getConnection(self,srcportpath,dstportpath,mustexist=False): - srcport = self.getPort(srcportpath,True) - if not srcport: - return None - dstport = self.getPort(dstportpath,True) - if not dstport: - return None - if not self.connections.has_key((srcport,dstport)): - if mustexist: - return None - self.connections[(srcport,dstport)] = self.getConnectionClass()(self,srcport,dstport) - return self.connections[(srcport,dstport)] - - def getConnections(self): - return self.connections.values() - - def getPatch(self,path,mustexist=False): - elements = path.split("/") - currentPatch = None - for element in elements: - if element == "": - currentPatch = self.omPatch - else: - currentPatch = currentPatch.getPatch(element,mustexist) - if not currentPatch: - break - return currentPatch - - def getNode(self,path,mustexist=False): - elements = path.split("/") - basepath = "/".join(elements[:-1]) - nodename = elements[-1] - patch = self.getPatch(basepath,True) - if patch: - return patch.getNode(nodename,mustexist) - return None - - def getPort(self,path,mustexist=False): - elements = path.split("/") - basepath = "/".join(elements[:-1]) - portname = elements[-1] - node = self.getNode(basepath,True) - if node: - return node.getPort(portname,mustexist) - patch = self.getPatch(basepath,True) - if patch: - return patch.getPort(portname,mustexist) - return None - - def getObject(self,path): - patch = self.getPatch(path,True) - if patch: - return patch - node = self.getNode(path,True) - if node: - return node - return self.getPort(path,True) - - def printPatch(self,patch=None): - if not patch: - patch = self.omPatch - print patch.getDepth()*' ' + "### " + patch.getPath() - for node in patch.getNodes(): - print node.getDepth()*' ' + "+++ " + node.getPath() - for port in node.getPorts(): - print port.getDepth()*' ' + "*** " + port.getPath() - for port in patch.getPorts(): - print port.getDepth()*' ' + "*** " + port.getPath() - for subpatch in patch.getPatches(): - self.printPatch(subpatch) - - def printConnections(self): - for connection in self.getConnections(): - print ">>> %s -> %s" % (connection.getSrcPort().getPath(), connection.getDstPort().getPath()) - - #~ /om/engine_enabled - Notification engine's DSP has been enabled. - def __om__engine_enabled(self): - self.enabled = True - - #~ /om/engine_disabled - Notification engine's DSP has been disabled. - def __om__engine_disabled(self): - self.enabled = False - - #~ /om/new_node - Notification of a new node's creation. - #~ * path (string) - Path of the new node - #~ * polyphonic (integer-boolean) - Node is polyphonic (1 for yes, 0 for no) - #~ * type (string) - Type of plugin (LADSPA, DSSI, Internal, Patch) - #~ * lib-name (string) - Name of library if a plugin (ie cmt.so) - #~ * plug-label (string) - Label of plugin in library (ie adsr_env) - - #~ * New nodes are sent as a blob. The first message in the blob will be this one (/om/new_node), followed by a series of /om/new_port commands, followed by /om/new_node_end. - def __om__new_node(self,path,polyphonic,plugintype,libname,pluginlabel): - node = self.getNode(path) - node.setPolyphonic(polyphonic) - node.setPluginType(plugintype) - node.setLibName(libname) - node.setPluginLabel(pluginlabel) - - def __om__new_node_end(self): - pass - - #~ /om/node_removal - Notification of a node's destruction. - #~ * path (string) - Path of node (which no longer exists) - def __om__node_removal(self,path): - node = self.getNode(path) - node.remove() - - #~ /om/new_port - Notification of a node's destruction. - - #~ * path (string) - Path of new port - #~ * type (string) - Type of port (CONTROL or AUDIO) - #~ * direction (string) - Direction of data flow (INPUT or OUTPUT) - #~ * hint (string) - Hint (INTEGER, LOGARITHMIC, TOGGLE, or NONE) - #~ * default-value (float) - Default (initial) value - #~ * min-value (float) - Suggested minimum value - #~ * min-value (float) - Suggested maximum value - - #~ * Note that in the event of loading a patch, this message could be followed immediately by a control change, meaning the default-value is not actually the current value of the port (ahem, Lachlan). - #~ * The minimum and maximum values are suggestions only, they are not enforced in any way, and going outside them is perfectly fine. Also note that the port ranges in om_gtk are not these ones! Those ranges are set as metadata. - def __om__new_port(self,path,porttype,direction,hint,defaultvalue,minvalue,maxvalue): - port = self.getPort(path) - port.setPortType(porttype) - port.setDirection(direction) - port.setHint(hint) - port.setDefaultValue(defaultvalue) - port.setMinValue(minvalue) - port.setMaxValue(maxvalue) - - #~ /om/port_removal - Notification of a port's destruction. - #~ * path (string) - Path of port (which no longer exists) - def __om__port_removal(self,path): - port = self.getPort(path) - port.remove() - - #~ /om/patch_destruction - Notification of a patch's destruction. - #~ * path (string) - Path of patch (which no longer exists) - def __om__patch_destruction(self,path): - patch = self.getPatch(path) - patch.remove() - - #~ /om/patch_enabled - Notification a patch's DSP processing has been enabled. - #~ * path (string) - Path of enabled patch - def __om__patch_enabled(self,path): - patch = self.getPatch(path) - patch.setEnabled(True) - - #~ /om/patch_disabled - Notification a patch's DSP processing has been disabled. - #~ * path (string) - Path of disabled patch - def __om__patch_disabled(self,path): - patch = self.getPatch(path) - patch.setEnabled(False) - - #~ /om/new_connection - Notification a new connection has been made. - #~ * src-path (string) - Path of the source port - #~ * dst-path (string) - Path of the destination port - def __om__new_connection(self,srcpath,dstpath): - self.getConnection(srcpath,dstpath) - - #~ /om/disconnection - Notification a connection has been unmade. - #~ * src-path (string) - Path of the source port - #~ * dst-path (string) - Path of the destination port - def __om__disconnection(self,srcpath,dstpath): - connection = self.getConnection(srcpath,dstpath) - portpair = connection.getPortPair() - connection.remove() - del self.connections[portpair] - - #~ /om/metadata/update - Notification of a piece of metadata. - #~ * path (string) - Path of the object associated with metadata (can be a node, patch, or port) - #~ * key (string) - #~ * value (string) - def __om__metadata__update(self,path,key,value): - object = self.getObject(path) - object.setMetaData(key,value) - - #~ /om/control_change - Notification the value of a port has changed - #~ * path (string) - Path of port - #~ * value (float) - New value of port - #~ * This will only send updates for values set by clients of course - not values changing because of connections to other ports! - def __om__control_change(self,path,value): - port = self.getPort(path) - port.setValue(value) - - #~ /om/new_patch - Notification of a new patch - #~ * path (string) - Path of new patch - #~ * poly (int) - Polyphony of new patch (not a boolean like new_node) - def __om__new_patch(self,path,poly): - patch = self.getPatch(path) - patch.setPoly(poly) - -class SocketError: - pass - -class Call: - pass - -class ClientProxy: - def __init__(self, om, name, is_async = False): - self.name = name - self.om = om - self.is_async = is_async - - def __call__(self, *args): - if (self.is_async): - self.om.sendMsg(self.name, *args) - return True - - result = self.om.sendMsgBlocking(self.name, *args) - if not result: - return None - if result[0] == "/om/response/ok": - return True - print "ERROR: %s" % result[1][1] - return False - - def __getattr__(self, name): - if (name[:2] == "__") and (name[-2:] == "__"): # special function - raise AttributeError, name - if name in self.__dict__: - raise AttributeError, name - if name == 'async': - return ClientProxy(self.om, self.name, True) - else: - return ClientProxy(self.om, self.name + '/' + name) - -class Client(DatagramProtocol, ClientProxy): - def __init__(self): - ClientProxy.__init__(self, self, "/om") - - def startProtocol(self): - self.transport.connect("127.0.0.1", 16180) - host = self.transport.getHost() - self.host = host.host - self.port = host.port - self.environment = None - self.handlers = {} - self.calls = {} - #print "opened port at %s" % (str((self.host,self.port))) - self.nextPacketNumber = 1 - - def setEnvironment(self, environment): - self.handlers = {} - self.environment = environment - for name in dir(self.environment): - element = getattr(self.environment,name) - if (type(element).__name__ == 'instancemethod') and (element.__name__[:6] == "__om__"): - handlername = element.__name__.replace("__","/") - print "registering handler for '%s'" % handlername - self.handlers[handlername] = element - - def getEnvironment(self): - return self.environment - - def connectionRefused(self): - print "Noone listening, aborting." - os._exit(-1) - - def messageReceived(self, (msg, args)): - if msg == "/om/error": - print "ERROR: %r" % args - return - if msg == "/om/response/ok": - omcall = self.calls[args[0]] - omcall.result = (msg,args) - omcall.done = True - return - if msg == "/om/response/error": - omcall = self.calls[args[0]] - omcall.result = (msg,args) - omcall.done = True - return - if msg == "#bundle": - for arg in args: - self.messageReceived(arg) - return - if self.handlers.has_key(msg): - try: - self.handlers[msg](*args) - except: - a,b,c = sys.exc_info() - sys.excepthook(a,b,c) - print "with '%s'" % repr((msg,args)) - return - print "no handler for '%s'" % repr((msg,args)) - - def datagramReceived(self, data, (host, port)): - self.messageReceived(decodeOSC(data)) - - def getPacketNumber(self): - packetNumber = self.nextPacketNumber - self.nextPacketNumber = (self.nextPacketNumber + 1) - return packetNumber - - def sendMsg(self,msg,*args): - packetNumber = self.getPacketNumber() - print "Sending %r (#%i)..." % (msg,packetNumber) - omcall = Call() - omcall.result = None - omcall.done = False - self.calls[packetNumber] = omcall - message = OSCMessage() - message.setAddress(msg) - message.append(packetNumber) - for arg in args: - message.append(arg) - self.transport.write(message.getBinary()) - time.sleep(0.01) - return True - - def sendMsgBlocking(self,msg,*args): - packetNumber = self.getPacketNumber() - print "Sending %r (#%i)..." % (msg,packetNumber) - omcall = Call() - omcall.result = None - omcall.done = False - self.calls[packetNumber] = omcall - message = OSCMessage() - message.setAddress(msg) - message.append(packetNumber) - for arg in args: - message.append(arg) - self.transport.write(message.getBinary()) - now = time.time() - while not omcall.done: - time.sleep(OM_CALL_POLLTIME) - distance = time.time() - now - if distance > OM_CALL_TIMEOUT: - print "timeout" - break - del self.calls[packetNumber] - return omcall.result - - def getAddressAsString(self): - return "osc.udp://%s:%d" % (self.host, self.port) - - - -def startClient(func): - om = Client() - reactor.listenUDP(0, om) - thread.start_new_thread(func,(om,)) - reactor.run() diff --git a/src/clients/python/scripts/Makefile.am b/src/clients/python/scripts/Makefile.am deleted file mode 100644 index 3e070601..00000000 --- a/src/clients/python/scripts/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -EXTRA_DIST = sillysinepatch.py - diff --git a/src/clients/python/scripts/flatten.py b/src/clients/python/scripts/flatten.py deleted file mode 100755 index eaf8084d..00000000 --- a/src/clients/python/scripts/flatten.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/python - -############################################################################### -# -# flatten.py - a python script that merges all subpatches in an Om patch -# into the parent patch -# -# Copyright (C) 2005 Lars Luthman -# -# 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 -# -############################################################################### - -import omsynth -import os,time,sys - - -def getPatchBounds(patch): - """Returns the smallest rectangle that contains all modules in the patch.""" - min_x = None - min_y = None - max_x = None - max_y = None - for node in patch.getNodes(): - x = node.metadata['module-x'] - y = node.metadata['module-y'] - if (x != None): - if (min_x == None or float(x) < min_x): - min_x = float(x) - if (max_x == None or float(x) > max_x): - max_x = float(x) - if (y != None): - if (min_y == None or float(y) < min_y): - min_y = float(y) - if (max_y == None or float(y) > max_y): - max_y = float(y) - if min_x == None: - min_x = 0 - max_x = 0 - if min_y == None: - min_y = 0 - max_y = 0 - - return (min_x, min_y, max_x, max_y) - - -def cloneNode(om, node, patch): - """Copy a node into a patch, return the new node's name.""" - - # create a node with a free name in the parent - names = [] - for node2 in patch.getNodes(): - names.append(node2.getName()) - for patch2 in patch.getPatches(): - names.append(patch2.getName()) - names.sort() - name = node.getName() - for name2 in names: - if name2 == name: - name = name + '_' - om.synth.create_node.async(patch.getPath() + '/' + name, - node.plugintype, node.libname, - node.pluginlabel, node.polyphonic) - - # copy port values - for port in node.getPorts(): - path = '%s/%s/%s' % (patch.getPath(), name, port.getName()) - om.synth.set_port_value_slow.async(path, port.value) - om.metadata.set.async(path, 'user-min', '%f' % port.minvalue) - om.metadata.set.async(path, 'user-max', '%f' % port.maxvalue) - return name - - -def flatten(om, patch): - """Merge all subpatches into the parent patch.""" - - # something is wrong, we don't have a patch - if patch == None: - return - - # iterate over all subpatches - for subpatch in patch.getPatches(): - flatten(om, subpatch) - lookup = {} - - # copy all nodes from the subpatch to the parent patch - for node in subpatch.getNodes(): - lookup[node.getName()] = cloneNode(om, node, patch) - - # copy all connections - for node in subpatch.getNodes(): - for port in node.getPorts(): - if port.direction == 'OUTPUT': - for target in port.getConnections().keys(): - targetname = '%s/%s' % (lookup[target.getParent().getName()], target.getName()) - om.synth.connect.async(patch.getPath() + '/' + - lookup[node.getName()] + '/' + - port.getName(), - patch.getPath() + '/' + - targetname) - - # make external connections - for node in subpatch.getNodes(): - if node.libname == '': - lbl = node.pluginlabel - - if lbl == 'audio_input' or lbl == 'control_input': - port1 = node.getPort('in') - for port2 in port1.getConnections().keys(): - dst = '%s/%s/%s' % (patch.getPath(), lookup[port2.getParent().getName()], port2.getName()) - port4 = subpatch.getPort(node.getName()) - conns = port4.getConnections().keys() - if len(conns) == 0: - portValue = port4.value - om.synth.set_port_value_slow.async(dst, portValue) - else: - for port3 in port4.getConnections().keys(): - src = port3.getPath() - om.synth.connect.async(src, dst) - - if lbl == 'audio_output' or lbl == 'control_output': - port2 = node.getPort('out', True) - for port1 in port2.getConnections().keys(): - src = '%s/%s/%s' % (patch.getPath(), lookup[port1.getParent().getName()], port1.getName()) - port3 = subpatch.getPort(node.getName()) - for port4 in port3.getConnections().keys(): - dst = port4.getPath() - om.synth.connect.async(src, dst) - - # destroy all input and output nodes from the subpatch - for node in subpatch.getNodes(): - if node.libname == '': - lbl = node.pluginlabel - if (lbl == 'audio_input' or lbl == 'control_input' or - lbl == 'audio_output' or lbl == 'control_output'): - om.synth.destroy_node.async('%s/%s' % (patch.getPath(), - lookup[node.getName()])) - - # calculate where to move all the new nodes - (min_x, min_y, max_x, max_y) = getPatchBounds(subpatch) - sub_x = subpatch.metadata['module-x'] - if sub_x == None: - sub_x = 0 - sub_y = subpatch.metadata['module-y'] - if sub_y == None: - sub_y = 0 - x_offset = float(sub_x) - if min_x != None: - x_offset = float(sub_x) - min_x - y_offset = float(sub_y) - if min_y != None: - y_offset = float(sub_y) - min_y - - # move the new nodes - for node in subpatch.getNodes(): - x = float(node.metadata['module-x']) - if x == None: - x = 0 - om.metadata.set.async('%s/%s' % (patch.getPath(), - lookup[node.getName()]), - 'module-x', '%f' % (x + x_offset)) - y = float(node.metadata['module-y']) - if y == None: - y = 0 - om.metadata.set.async('%s/%s' % (patch.getPath(), - lookup[node.getName()]), - 'module-y', '%f' % (y + y_offset)) - - # move the old nodes in the patch - x_offset = 0 - if min_x != None and max_x != None: - x_offset = max_x - min_x - y_offset = 0 - if min_y != None and max_y != None: - y_offset = max_y - min_y - for node in patch.getNodes(): - if node.getName() not in lookup.values(): - x = node.metadata['module-x'] - if x != None and float(x) > float(sub_x): - om.metadata.set.async(node.getPath(), 'module-x', - '%f' % (float(x) + x_offset)) - y = node.metadata['module-y'] - if y != None and float(y) > float(sub_y): - om.metadata.set.async(node.getPath(), 'module-y', - '%f' % (float(y) + y_offset)) - # destroy the subpatch - om.synth.destroy_patch(subpatch.getPath()) - - -def main(om): - om.setEnvironment(omsynth.Environment()) - om.engine.activate.async() - om.engine.load_plugins.async() - om.request.all_objects(om.getAddressAsString()) - - # wait for all the data to arrive (there should be a cleaner way) - time.sleep(3) - - patch = om.getEnvironment().getPatch(sys.argv[1], True); - flatten(om, patch) - - os._exit(0) - - -if len(sys.argv) > 1: - if sys.argv[1] == "--name": - print "Flatten patch" - os._exit(0) - elif sys.argv[1] == "--shortdesc": - print "Merge the contents of all subpatches into the parent patch"; - os._exit(0) - elif sys.argv[1] == "--signature": - print "%p"; - os._exit(0) - else: - omsynth.startClient(main) - -else: - print "Which patch do you want to flatten?" - os._exit(0) diff --git a/src/clients/python/scripts/sillysinepatch.py b/src/clients/python/scripts/sillysinepatch.py deleted file mode 100644 index ac51a080..00000000 --- a/src/clients/python/scripts/sillysinepatch.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/python -# -# Python bindings for Om -# Copyright (C) 2005 Leonard Ritter -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import omsynth -import os,time,sys - -def main(om): - om.setEnvironment(omsynth.Environment()) - om.engine.activate() - om.engine.load_plugins() - om.engine.register_client(om.getAddressAsString()) - om.request.all_objects(om.getAddressAsString()) - om.synth.create_patch("/silly_sine", 1) - om.synth.create_node("/silly_sine/output", "Internal", "", "audio_output", 0) - om.synth.create_node("/silly_sine/sine", "LADSPA", "cmt.so", "sine_fcac", 0) - om.synth.set_port_value("/silly_sine/sine/Frequency", 440.0) - om.synth.set_port_value("/silly_sine/sine/Amplitude", 1.0) - om.synth.connect("/silly_sine/sine/Output", "/silly_sine/output/out") - om.synth.enable_patch("/silly_sine") - om.engine.enable() - om.engine.unregister_client(om.getAddressAsString()) - os._exit(0) - -if __name__ == "__main__": - omsynth.startClient(main) diff --git a/src/clients/supercollider/Makefile.am b/src/clients/supercollider/Makefile.am deleted file mode 100644 index 69661c73..00000000 --- a/src/clients/supercollider/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -EXTRA_DIST = Om.sc example.sc - diff --git a/src/clients/supercollider/Om.sc b/src/clients/supercollider/Om.sc deleted file mode 100644 index cb366d58..00000000 --- a/src/clients/supercollider/Om.sc +++ /dev/null @@ -1,746 +0,0 @@ -// TODO: -// * Keep track of established connections. -Om : Model { - classvar <>program = "om", <>patchLoader = "om_patch_loader"; - classvar <>oscURL, uiClass; - var loadIntoJack = true; - var allocator, requestResponders, requestHandlers, notificationResponders; - var creatingNode, newNodeEnd; - var OmInternalNode, - \LADSPA -> OmLADSPANode, - \DSSI -> OmDSSINode - ]; - uiClass = OmEmacsUI - } - *new { | netaddr | - ^super.new.init(netaddr) - } - gui { ^uiClass.new(this) } - init { |netaddr| - addr = netaddr ? NetAddr("127.0.0.1", 16180); - onNewPatch = IdentityDictionary.new; - allocator = StackNumberAllocator(0,1024); - requestHandlers = IdentityDictionary.new; - requestResponders = [ - "response/ok" -> {|id| - requestHandlers.removeAt(id).value; allocator.free(id) }, - "response/error" -> {|id,text| - requestHandlers.removeAt(id); - allocator.free(id); - ("Om"+text).error } - ].collect({|a| - var func = a.value; - OSCresponder(addr, "/om/"++a.key, {|time,resp,msg| - func.value(*msg[1..]) - }) - }); - notificationResponders = [ - "new_patch" -> {|path,poly| - var func = onNewPatch.removeAt(path); - if (func.notNil) { - func.value(this.getPatch(path,false).prSetPoly(poly)) - } - }, - "metadata/update" -> {|path,key,value| - this.getObject(path).metadata.prSetMetadata(key, value) }, - "new_node" -> {|path,poly,type,lib,label| - var patchPath, nodeName, patch, node; - var lastSlash = path.asString.inject(nil,{|last,char,i| - if(char==$/,i,last) - }); - if (lastSlash.notNil) { - patchPath = path.asString.copyFromStart(lastSlash-1); - nodeName = path.asString.copyToEnd(lastSlash+1); - patch = this.getPatch(patchPath); - if (patch.notNil) { - if (patch.hasNode(nodeName).not) { - node = nodeTypeMap[type].new - (nodeName, patch, poly, label, lib); - creatingNode = node; - patch.nodes[nodeName.asSymbol] = node; - patch.changed(\newNode, node); - } { - if (patch.getNode(nodeName).class != nodeTypeMap[type]) { - ("Om sent an existng node with differing type"+path).warn - } - } - } { - ("Om tried to create node in non-existing patch"+patchPath).warn - } - } { - ("Invalid path in node creation"+path).warn - } - }, - "new_node_end" -> { - newNodeEnd.value(creatingNode); - newNodeEnd = nil; - creatingNode = nil }, - "new_port" -> {|path,type,dir,hint,def,min,max| - var basePath, portName, parent, port; - var lastSlash = path.asString.inject(nil,{|last,char,i| - if(char==$/,i,last) - }); - if (lastSlash.notNil) { - basePath = path.asString.copyFromStart(lastSlash-1); - portName = path.asString.copyToEnd(lastSlash+1); - parent = this.getNode(basePath) ? this.getPatch(basePath); - if (parent.notNil) { - if (parent.hasPort(portName).not) { - port = OmPort.new(portName, parent, type, dir, hint, def, min, max); - parent.ports[portName.asSymbol] = port; - parent.changed(\newPort, port) - } { - if (parent.getPort(portName).porttype != type) { - ("Om tried to create an already existing port with differing type" - +path).warn - } - } - } { - ("Om tried to create port on non-existing object"+basePath).warn - } - } { - ("Invalid path in port creation"+path).warn - } - }, - "control_change" -> {|path,value| - this.getPort(path).prSetValue(value) }, - "patch_enabled" -> {|path| this.getPatch(path).prSetEnabled(true) }, - "patch_disabled" -> {|path| this.getPatch(path).prSetEnabled(false) }, - "plugin" -> {|lib,label,name,type| - plugins.add(Event.new(4,nil,pluginParentEvent).putAll( - (type:type, lib:lib, label:label, name:name))) }, - "node_removal" -> {|path| - var node = this.getNode(path); - if (node.notNil) { - node.parent.nodes.removeAt(node.name.asSymbol).free - } { - ("Om attempting to remove non-existing node"+path).warn - } - }, - "port_removal" -> {|path| - var port = this.getPort(path); - if (port.notNil) { - port.parent.ports.removeAt(port.name.asSymbol).free - } { - ("Om attempting to remove non-existing port"+path).warn - } - }, - "patch_destruction" -> {|path| - var patch = this.getPatch(path); - if (patch.notNil) { - patch.parent.patches.removeAt(patch.name.asSymbol).free - } { - ("Om attempting to remove non-existing patch"+path).warn - } - }, - "program_add" -> {|path,bank,program,name| - var node = this.getNode(path); - if (node.respondsTo(\prProgramAdd)) { - node.prProgramAdd(bank,program,name) - } { - ("Om tried to add program info to"+node).warn - } - } - ].collect({|a| - var func = a.value; - OSCresponder(addr, "/om/"++a.key, {|time,resp,msg| - func.value(*msg[1..]) - }) - }); - pluginParentEvent = Event.new(2,nil,nil).putAll(( - engine:this, - new:{|self,path,poly=1,handler|self.engine.createNode(path?("/"++self.name),self.type,self.lib,self.label,poly,created:handler)} - )); - } - *waitForBoot {|func| ^this.new.waitForBoot(func) } - waitForBoot {|func| - var r, id = 727; - requestHandlers[id] = { - r.stop; - booting=false; - this.changed(\running, true); - func.value(this) - }; - if (booting.not) {this.boot}; - r = Routine.run { - 50.do { - 0.1.wait; - addr.sendMsg("/om/ping", id) - }; - requestHandlers.removeAt(id); - "Om engine boot failed".error; - } - } - getPatch {|path, mustExist=true| - var elements, currentPatch; - if (path.class == Array) { elements = path - } { elements = path.asString.split($/) }; - elements.do{|elem| - if (elem=="") { - currentPatch = root - } { - currentPatch = currentPatch.getPatch(elem,mustExist); - if (currentPatch.isNil) { ^nil } - } - }; - ^currentPatch; - } - getNode {|path| - var basePath, nodeName, patch; - if (path.class == Array) { basePath = path - } { basePath = path.asString.split($/) }; - nodeName = basePath.pop; - patch = this.getPatch(basePath,true); - if (patch.notNil) { - ^patch.getNode(nodeName) - }; - ^nil - } - getPort {|path| - var basePath, portName, node, patch; - basePath = path.asString.split($/); - portName = basePath.pop; - node = this.getNode(basePath.copy); - if (node.notNil) { ^node.getPort(portName) }; - patch = this.getPatch(basePath,true); - if (patch.notNil) { ^patch.getPort(portName) }; - ^nil - } - getObject {|path| - var patch,node,port; - patch = this.getPatch(path,true); - if (patch.notNil) { ^patch }; - node = this.getNode(path); - if (node.notNil) { ^node }; - port = this.getPort(path,true); - if (port.notNil) { ^port }; - ^nil - } - at {|path|^this.getObject(path.asString)} - *boot {|func| - ^Om.new.waitForBoot {|e| - e.activate { - e.register { - e.loadPlugins { - e.requestPlugins { - e.requestAllObjects { - func.value(e) - } - } - } - } - } - } - } - boot { - requestResponders.do({|resp| resp.add}); - booting = true; - if (addr.addr == 2130706433) { - if (loadIntoJack) { - ("jack_load"+"-i"+addr.port+"Om"+"om").unixCmd - } { - (program+"-p"+addr.port).unixCmd - } - } { - "You have to manually boot Om now".postln - } - } - loadPatch {|patchPath| (patchLoader + patchPath).unixCmd } - activate { | handler | - this.sendReq("engine/activate", { - root = OmPatch("",nil,this); - this.changed(\newPatch, root); - handler.value - }) - } - register { | handler | - this.sendReq("engine/register_client", { - registered=true; - notificationResponders.do({|resp| resp.add}); - this.changed(\registered, registered); - handler.value(this) - }) - } - unregister { | handler | - this.sendReq("engine/unregister_client", { - registered=false; - notificationResponders.do({|resp| resp.remove}); - this.changed(\registered, registered); - handler.value(this) - }) - } - registered_ {|flag| - if (flag and: registered.not) { - this.register - } { - if (flag.not and: registered) { - this.unregister - } - } - } - loadPlugins { | handler | this.sendReq("engine/load_plugins", handler) } - requestPlugins {|handler| - var startTime = Main.elapsedTime; - plugins = Set.new; - this.sendReq("request/plugins", { - ("Received info about"+plugins.size+"plugins in"+(Main.elapsedTime-startTime)+"seconds").postln; - this.changed(\plugins, plugins); - handler.value(this); - }) - } - requestAllObjects { |handler| - this.sendReq("request/all_objects", handler) - } - createPatch { | path, poly=1, handler | - onNewPatch[path.asSymbol] = handler; - this.sendReq("synth/create_patch", nil, path.asString, poly.asInteger) - } - createNode { | path, type='LADSPA', lib, label, poly=1, created, handler | - newNodeEnd = created; - this.sendReq("synth/create_node",handler,path,type,lib,label,poly) - } - createAudioInput { | path, handler | - this.createNode(path,"Internal","","audio_input",0,handler) - } - createAudioOutput {|path,handler| - this.createNode(path,"Internal","","audio_output",0,handler) - } - createMIDIInput {|path,handler| - this.createNode(path,"Internal","","midi_input",1,handler) - } - createMIDIOutput {|path,handler| - this.createNode(path,"Internal","","midi_output",1,handler) - } - createNoteIn {|path| this.createNode(path,"Internal","","note_in") } - connect {|fromPath,toPath,handler| - this.sendReq("synth/connect",handler,fromPath.asString,toPath.asString) - } - disconnect { | fromPath, toPath, handler | - this.sendReq("synth/disconnect",handler,fromPath.asString,toPath.asString) - } - disconnectAll { | path, handler | - this.sendReq("synth/disconnect_all",handler,path); - } - sendReq { | path, handler...args | - var id = allocator.alloc; - requestHandlers[id] = handler; - addr.sendMsg("/om/"++path, id, *args) - } - quit { - if (loadIntoJack) { - ("jack_unload"+"Om").unixCmd; - booting=false; - requestResponders.do(_.remove); - notificationResponders.do(_.remove); - this.changed(\running, false); - } { - this.sendReq("engine/quit", { - booting=false; - requestResponders.do(_.remove); - notificationResponders.do(_.remove); - this.changed(\running, false); - }) - } - } - ping {| n=1, func | - var id, result, start; - id = allocator.alloc; - result = 0; - requestHandlers[id] = { - var end; - end = Main.elapsedTime; - result=max((end-start).postln,result); - n=n-1; - if (n > 0) { - start = Main.elapsedTime; - addr.sendMsg("/om/ping", id) - } { - allocator.free(id); - func.value(result) - } - }; - start = Main.elapsedTime; - addr.sendMsg("/om/ping", id) - } - setPortValue {|path, val| this.getPort(path.asString).value=val } - jackConnect {|path, jackPort| - this.getPort(path).jackConnect(jackPort) - } - noteOn {|path, note, vel| - var patch,node; - patch = this.getPatch(path,true); - if (patch.notNil) { patch.noteOn(note,vel) }; - node = this.getNode(path); - if (node.notNil) { node.noteOn(note,vel) }; - } - noteOff {|path, note| - var patch,node; - patch = this.getPatch(path,true); - if (patch.notNil) { patch.noteOff(note) }; - node = this.getNode(path); - if (node.notNil) { node.noteOff(note) }; - } - matchPlugins{ | label, lib, name, type | - ^plugins.select{ |p| - label.matchItem(p.label) and: { - lib.matchItem(p.lib) and: { - name.matchItem(p.name) and: { - type.matchItem(p.type) - } - } - } - } - } - dssiMsg {|path,reqType="program" ...args| - addr.sendMsg("/dssi"++path++$/++reqType,*args) - } -} - -OmMetadata { - var object, dict; - *new {|obj|^super.new.metadataInit(obj)} - metadataInit {|obj| - dict=Dictionary.new; - object=obj - } - put {|key,val| - object.engine.sendReq("metadata/set", nil, - object.path, key.asString, val.asString) - } - at {|key|^dict.at(key.asSymbol)} - prSetMetadata {|key,val| - dict.put(key,val); - object.changed(\metadata, key, val) - } -} - -OmObject : Model { - var diff --git a/src/clients/supercollider/example.sc b/src/clients/supercollider/example.sc deleted file mode 100644 index 6186e433..00000000 --- a/src/clients/supercollider/example.sc +++ /dev/null @@ -1,27 +0,0 @@ -// Boot Om (inside SC) and the scsynth server -( -o=Om.boot { - o.loadPatch("/home/mlang/src/om-synth/src/clients/patches/303.om"); - s.boot; -} -) -// Connect patch output to one SC input -o.jackConnect("/303/output", "SuperCollider:in_3"); -// Play this input on the default output bus (most simple postprocessor) -{AudioIn.ar(3).dup}.play; -// A simple 303 pattern -( -Tempo.bpm=170; -Ppar([ - Pbind(\type, \om, \target, o.getPatch("/303",true), - \dur, 1/1, \octave,2,\degree, Pseq([Pshuf([0,2,4,6],16)],2)), - Pbind(\type, \om, \target, o.getPatch("/303",true), - \dur, Prand([Pshuf([1/2,1/4,1/4],4),Pshuf([1/3,1/3,1/6,1/6],4)],inf), - \legato, Prand((0.5,0.55..0.9),inf), - \octave,3,\degree, Pseq([Pshuf([0,2,4,6],2)],40)), - Pbind(\type, \om, \omcmd, \setPortValue, - \target, o.getPort("/303/cutoff",true), - \dur, 1/10, \portValue, Pseq((0,0.005..1).mirror,2)), - Pbind(\type, \om, \omcmd, \setPortValue, - \target, o.getPort("/303/resonance",true), \portValue, 1)]).play(quant:4) -) diff --git a/src/libs/client/ConnectionModel.cpp b/src/libs/client/ConnectionModel.cpp new file mode 100644 index 00000000..1c7541b9 --- /dev/null +++ b/src/libs/client/ConnectionModel.cpp @@ -0,0 +1,54 @@ +/* This file is part of Om. 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 "ConnectionModel.h" +#include "PortModel.h" + +namespace LibOmClient { + + +ConnectionModel::ConnectionModel(const Path& src_port, const Path& dst_port) +: m_src_port_path(src_port), + m_dst_port_path(dst_port), + m_src_port(NULL), + m_dst_port(NULL) +{ + // Be sure connection is within one patch + assert(m_src_port_path.parent().parent() + == m_dst_port_path.parent().parent()); +} + + +const Path& +ConnectionModel::src_port_path() const +{ + if (m_src_port == NULL) + return m_src_port_path; + else + return m_src_port->path(); +} + + +const Path& +ConnectionModel::dst_port_path() const +{ + if (m_dst_port == NULL) + return m_dst_port_path; + else + return m_dst_port->path(); +} + +} // namespace LibOmClient diff --git a/src/libs/client/ConnectionModel.h b/src/libs/client/ConnectionModel.h new file mode 100644 index 00000000..ef909850 --- /dev/null +++ b/src/libs/client/ConnectionModel.h @@ -0,0 +1,70 @@ +/* This file is part of Om. 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 CONNECTIONMODEL_H +#define CONNECTIONMODEL_H + +#include +#include "util/Path.h" +#include +using std::string; +using Om::Path; + +namespace LibOmClient { + +class PortModel; + + +/** Class to represent a port->port connection in the engine. + * + * This can either have pointers to the connection ports' models, or just + * paths as strings. LibOmClient passes just strings (by necessity), but + * clients can set the pointers then they don't have to worry about port + * renaming, as the connections will always return the port's path, even + * if it changes. + * + * \ingroup libomclient + */ +class ConnectionModel +{ +public: + ConnectionModel(const Path& src_port, const Path& dst_port); + + PortModel* src_port() const { return m_src_port; } + PortModel* dst_port() const { return m_dst_port; } + + void set_src_port(PortModel* port) { m_src_port = port; m_src_port_path = ""; } + void set_dst_port(PortModel* port) { m_dst_port = port; m_dst_port_path = ""; } + + void src_port_path(const string& s) { m_src_port_path = s; } + void dst_port_path(const string& s) { m_dst_port_path = s; } + + const Path& src_port_path() const; + const Path& dst_port_path() const; + const Path patch_path() const { return src_port_path().parent().parent(); } + +private: + Path m_src_port_path; ///< Only used if m_src_port == NULL + Path m_dst_port_path; ///< Only used if m_dst_port == NULL + PortModel* m_src_port; + PortModel* m_dst_port; +}; + + +} // namespace LibOmClient + +#endif // CONNECTIONMODEL_H diff --git a/src/libs/client/ControlModel.h b/src/libs/client/ControlModel.h new file mode 100644 index 00000000..872dcca2 --- /dev/null +++ b/src/libs/client/ControlModel.h @@ -0,0 +1,53 @@ +/* This file is part of Om. 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 alongCont + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONTROLMODEL_H +#define CONTROLMODEL_H + +#include +#include "util/Path.h" + +namespace LibOmClient { + + +/** A single port's control setting (in a preset). + * + * \ingroup libomclient + */ +class ControlModel +{ +public: + ControlModel(const Path& port_path, float value) + : m_port_path(port_path), + m_value(value) + { + assert(m_port_path.find("//") == string::npos); + } + + const Path& port_path() const { return m_port_path; } + void port_path(const string& p) { m_port_path = p; } + float value() const { return m_value; } + void value(float v) { m_value = v; } + +private: + Path m_port_path; + float m_value; +}; + + +} // namespace LibOmClient + +#endif // CONTROLMODEL diff --git a/src/libs/client/DirectSigClientInterface.h b/src/libs/client/DirectSigClientInterface.h new file mode 100644 index 00000000..12672a48 --- /dev/null +++ b/src/libs/client/DirectSigClientInterface.h @@ -0,0 +1,112 @@ +/* This file is part of Om. Copyright (C) 2006 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 DIRECTSIGCLIENTINTERFACE_H +#define DIRECTSIGCLIENTINTERFACE_H + +#include +#include +#include +#include "SigClientInterface.h" +using std::string; + +namespace LibOmClient { + + +/** A direct (nonthreaded) LibSigC++ signal emitting interface for clients to use. + * + * The signals from SigClientInterface will be emitted in the same thread as the + * ClientInterface functions are called. You can not set this directly as an + * in-engine client interface and connect the signals to GTK. + * + * For maximum performance of a monolithic single-client GUI app, it would be + * nice if the post processing thread in the engine could actually be the GTK + * thread, then you could use this directly and minimize queueing of events and + * thread/scheduling overhead. + * + * sed would have the copyright to this code if it was a legal person. + */ +class DirectSigClientInterface : virtual public SigClientInterface +{ +public: + DirectSigClientInterface(); + +private: + + // ClientInterface function implementations to drive SigClientInterface signals + + virtual void bundle_begin() + { emit_bundle_begin(); } + + virtual void bundle_end() + { emit_bundle_end(); } + + virtual void error(const string& msg) + { emit_error(msg); } + + virtual void num_plugins(uint32_t num) + { emit_num_plugins(num); } + + virtual void new_plugin(const string& type, const string& uri, const string& name) + { emit_new_plugin(type, uri, name); } + + virtual void new_patch(const string& path, uint32_t poly) + { emit_new_patch(path, poly); } + + virtual void new_node(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports) + { emit_new_node(plugin_type, plugin_uri, node_path, is_polyphonic, num_ports); } + + virtual void new_port(const string& path, const string& data_type, bool is_output) + { emit_new_port(path, data_type, is_output); } + + virtual void patch_enabled(const string& path) + { emit_patch_enabled(path); } + + virtual void patch_disabled(const string& path) + { emit_patch_disabled(path); } + + virtual void patch_cleared(const string& path) + { emit_patch_cleared(path); } + + virtual void object_renamed(const string& old_path, const string& new_path) + { emit_object_renamed(old_path, new_path); } + + virtual void object_destroyed(const string& path) + { emit_object_destroyed(path); } + + virtual void connection(const string& src_port_path, const string& dst_port_path) + { emit_connection(src_port_path, dst_port_path); } + + virtual void disconnection(const string& src_port_path, const string& dst_port_path) + { emit_disconnection(src_port_path, dst_port_path); } + + virtual void metadata_update(const string& subject_path, const string& predicate, const string& value) + { emit_metadata_update(subject_path, predicate, value); } + + virtual void control_change(const string& port_path, float value) + { emit_control_change(port_path, value); } + + virtual void program_add(const string& node_path, uint32_t bank, uint32_t program, const string& program_name) + { emit_program_add(node_path, bank, program, program_name); } + + virtual void program_remove(const string& node_path, uint32_t bank, uint32_t program) + { emit_program_remove(node_path, bank, program); } +}; + + +} // namespace LibOmClient + +#endif diff --git a/src/libs/client/Makefile.am b/src/libs/client/Makefile.am new file mode 100644 index 00000000..24e6a3bb --- /dev/null +++ b/src/libs/client/Makefile.am @@ -0,0 +1,51 @@ +AM_CXXFLAGS = -I$(top_srcdir)/src/common -fno-exceptions -fno-rtti + +SUBDIRS = . python supercollider + +if BUILD_CONSOLE_CLIENTS +noinst_LIBRARIES = libomclient.a + +libomclient_a_CXXFLAGS = -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LIBGLADEMM_CFLAGS) $(GNOMECANVASMM_CFLAGS) $(JACK_CFLAGS) $(LXML2_CFLAGS) + +libomclient_a_SOURCES = \ + ClientInterface.h \ + OSCEngineInterface.h \ + OSCEngineInterface.cpp \ + OSCModelEngineInterface.h \ + OSCModelEngineInterface.cpp \ + OSCListener.h \ + OSCListener.cpp \ + SigClientInterface.h \ + DirectSigClientInterface.h \ + ThreadedSigClientInterface.h \ + ThreadedSigClientInterface.cpp \ + ModelEngineInterface.h \ + ModelClientInterface.h \ + ModelClientInterface.cpp \ + PresetModel.h \ + ControlModel.h \ + ObjectController.h \ + ObjectModel.h \ + ObjectModel.cpp \ + NodeModel.h \ + NodeModel.cpp \ + PortModel.h \ + PatchModel.h \ + PatchModel.cpp \ + PluginModel.h \ + PatchLibrarian.h \ + PatchLibrarian.cpp \ + ConnectionModel.h \ + ConnectionModel.cpp \ + $(top_srcdir)/src/common/util/Path.h \ + $(top_srcdir)/src/common/interface/ClientInterface.h \ + $(top_srcdir)/src/common/interface/EngineInterface.h + +SUBDIRS += patch_loader patches demolition + +endif # BUILD_CONSOLE_CLIENTS + +if BUILD_GTK_CLIENT +SUBDIRS += gtk +endif + diff --git a/src/libs/client/ModelClientInterface.cpp b/src/libs/client/ModelClientInterface.cpp new file mode 100644 index 00000000..46754161 --- /dev/null +++ b/src/libs/client/ModelClientInterface.cpp @@ -0,0 +1,135 @@ +/* This file is part of Om. 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 "ModelClientInterface.h" +#include "PatchModel.h" +#include "ConnectionModel.h" +#include "PresetModel.h" +#include "NodeModel.h" +#include "PluginModel.h" + +namespace LibOmClient { + + +void +ModelClientInterface::new_plugin_model(PluginModel* pi) +{ +} + + +void +ModelClientInterface::new_patch_model(PatchModel* pm) +{ +} + + +void +ModelClientInterface::new_node_model(NodeModel* nm) +{ +} + + +void +ModelClientInterface::new_port_model(PortModel* port_info) +{ +} + + +void +ModelClientInterface::connection_model(ConnectionModel* cm) +{ +} + + + +/* Implementations of ClientInterface functions to drive + * the above functions: + */ + + + +void +ModelClientInterface::new_plugin(const string& type, + const string& uri, + const string& name) +{ + PluginModel* plugin = new PluginModel(type, uri); + plugin->name(name); + new_plugin_model(plugin); +} + + + +void +ModelClientInterface::new_patch(const string& path, uint32_t poly) +{ + PatchModel* pm = new PatchModel(path, poly); + PluginModel* pi = new PluginModel(PluginModel::Patch); + pm->plugin(pi); + new_patch_model(pm); +} + + + +void +ModelClientInterface::new_node(const string& plugin_type, + const string& plugin_uri, + const string& node_path, + bool is_polyphonic, + uint32_t num_ports) +{ + cerr << "FIXME: NEW NODE\n"; + + PluginModel* plugin = new PluginModel(plugin_type, plugin_uri); + + NodeModel* nm = new NodeModel(node_path); + nm->plugin(plugin); + + new_node_model(nm); +} + + + +void +ModelClientInterface::new_port(const string& path, + const string& type, + bool is_output) +{ + PortModel::Type ptype = PortModel::CONTROL; + if (type != "AUDIO") ptype = PortModel::AUDIO; + else if (type != "CONTROL") ptype = PortModel::CONTROL; + else if (type != "MIDI") ptype = PortModel::MIDI; + else cerr << "[ModelClientInterface] WARNING: Unknown port type received (" << type << ")" << endl; + + PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; + + PortModel* port_model = new PortModel(path, ptype, pdir); + new_port_model(port_model); +} + + + +void +ModelClientInterface::connection(const string& src_port_path, + const string& dst_port_path) +{ + connection_model(new ConnectionModel(src_port_path, dst_port_path)); +} + + + + +} // namespace LibOmClient diff --git a/src/libs/client/ModelClientInterface.h b/src/libs/client/ModelClientInterface.h new file mode 100644 index 00000000..1f5ea09d --- /dev/null +++ b/src/libs/client/ModelClientInterface.h @@ -0,0 +1,87 @@ +/* This file is part of Om. 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 MODELCLIENTINTERFACE_H +#define MODELCLIENTINTERFACE_H + +#include +#include +using std::string; using std::auto_ptr; +#include "interface/ClientInterface.h" + +namespace LibOmClient { + +class PatchModel; +class NodeModel; +class ConnectionModel; +class PortModel; +class PluginModel; + + +/** A client interface that creates Model objects to represent the engine's state. + * + * This calls it's own methods with the models as parameters; clients can inherit + * this and implement a class with a similar interface to ClientInterface except + * with model classes passed where appropriate instead of primitives. + * + * \ingroup libomclient + */ +class ModelClientInterface : virtual public Om::Shared::ClientInterface +{ +public: + ModelClientInterface(Om::Shared::ClientInterface& extend) + : Om::Shared::ClientInterface(extend) + {} + + virtual ~ModelClientInterface() {} + + // FIXME: make these auto_ptr's + + virtual void new_plugin_model(PluginModel* pi); + virtual void new_patch_model(PatchModel* pm); + virtual void new_node_model(NodeModel* nm); + virtual void new_port_model(PortModel* port_info); + virtual void connection_model(ConnectionModel* cm); + + // ClientInterface functions to drive the above: + + virtual void new_plugin(const string& type, + const string& uri, + const string& name); + + virtual void new_patch(const string& path, uint32_t poly); + + virtual void new_node(const string& plugin_type, + const string& plugin_uri, + const string& node_path, + bool is_polyphonic, + uint32_t num_ports); + + virtual void new_port(const string& path, + const string& data_type, + bool is_output); + + virtual void connection(const string& src_port_path, + const string& dst_port_path); + +protected: + ModelClientInterface() {} +}; + + +} // namespace LibOmClient + +#endif // MODELCLIENTINTERFACE_H diff --git a/src/libs/client/ModelEngineInterface.h b/src/libs/client/ModelEngineInterface.h new file mode 100644 index 00000000..aa041aef --- /dev/null +++ b/src/libs/client/ModelEngineInterface.h @@ -0,0 +1,58 @@ +/* This file is part of Om. 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 MODELENGINEINTERFACE_H +#define MODELENGINEINTERFACE_H + +#include +#include +#include "interface/EngineInterface.h" +using std::string; + +/** \defgroup libomclient Client Library + */ + +namespace LibOmClient { + +class NodeModel; +class PresetModel; +class PatchModel; +class OSCListener; +class ModelClientInterface; + + +/** Model-based engine command interface. + * + * \ingroup libomclient + */ +class ModelEngineInterface +{ +public: + virtual ~ModelEngineInterface() {} + + virtual void create_patch_from_model(const PatchModel* pm) = 0; + virtual void create_node_from_model(const NodeModel* nm) = 0; + + virtual void set_all_metadata(const NodeModel* nm) = 0; + virtual void set_preset(const string& patch_path, const PresetModel* pm) = 0; + +protected: + ModelEngineInterface() {} +}; + +} // namespace LibOmClient + +#endif // MODELENGINEINTERFACE_H diff --git a/src/libs/client/NodeModel.cpp b/src/libs/client/NodeModel.cpp new file mode 100644 index 00000000..efdae494 --- /dev/null +++ b/src/libs/client/NodeModel.cpp @@ -0,0 +1,117 @@ +/* This file is part of Om. 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 "NodeModel.h" +#include "PatchModel.h" +#include + +namespace LibOmClient { + + +NodeModel::NodeModel(const Path& path) +: ObjectModel(path), + m_polyphonic(false), + m_plugin(NULL), + m_x(0.0f), + m_y(0.0f) +{ +} + +NodeModel::~NodeModel() +{ + for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) + delete(*i); +} + + +void +NodeModel::remove_port(const string& port_path) +{ + for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) { + if ((*i)->path() == port_path) { + m_ports.erase(i); + break; + } + } +} + + +void +NodeModel::clear() +{ + for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) + delete (*i); + + m_ports.clear(); + + assert(m_ports.empty()); +} + + +void +NodeModel::set_path(const Path& p) +{ + const string old_path = m_path; + + ObjectModel::set_path(p); + + for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) + (*i)->set_path(m_path + "/" + (*i)->name()); + + if (parent_patch() != NULL && old_path.length() > 0) + parent_patch()->rename_node(old_path, p); +} + + +void +NodeModel::add_port(PortModel* pm) +{ + assert(pm->name() != ""); + assert(pm->path().length() > m_path.length()); + assert(pm->path().substr(0, m_path.length()) == m_path); + assert(pm->parent() == NULL); + assert(get_port(pm->name()) == NULL); + + m_ports.push_back(pm); + pm->set_parent(this); +} + + +PortModel* +NodeModel::get_port(const string& port_name) +{ + assert(port_name.find("/") == string::npos); + for (PortModelList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) + if ((*i)->name() == port_name) + return (*i); + return NULL; +} + + +void +NodeModel::add_program(int bank, int program, const string& name) +{ + m_banks[bank][program] = name; +} +void +NodeModel::remove_program(int bank, int program) +{ + m_banks[bank].erase(program); + if (m_banks[bank].size() == 0) + m_banks.erase(bank); +} + +} diff --git a/src/libs/client/NodeModel.h b/src/libs/client/NodeModel.h new file mode 100644 index 00000000..af4171ed --- /dev/null +++ b/src/libs/client/NodeModel.h @@ -0,0 +1,93 @@ +/* This file is part of Om. 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 NODEMODEL_H +#define NODEMODEL_H + +#include +#include +#include +#include +#include "ObjectModel.h" +#include "PortModel.h" +#include "util/Path.h" + +using std::string; using std::map; using std::find; +using std::cout; using std::cerr; using std::endl; + +namespace LibOmClient { + +class PatchModel; +class PluginModel; + + +/** Node model class, used by the client to store engine's state. + * + * \ingroup libomclient + */ +class NodeModel : public ObjectModel +{ +public: + NodeModel(const Path& node_path); + virtual ~NodeModel(); + + PortModel* get_port(const string& port_name); + void add_port(PortModel* pm); + void remove_port(const string& port_path); + + virtual void clear(); + + const map >& get_programs() const { return m_banks; } + void add_program(int bank, int program, const string& name); + void remove_program(int bank, int program); + + const PluginModel* plugin() const { return m_plugin; } + void plugin(const PluginModel* const pi) { m_plugin = pi; } + + virtual void set_path(const Path& p); + + int num_ports() const { return m_ports.size(); } + const PortModelList& ports() const { return m_ports; } + virtual bool polyphonic() const { return m_polyphonic; } + void polyphonic(bool b) { m_polyphonic = b; } + float x() const { return m_x; } + void x(float a) { m_x = a; } + float y() const { return m_y; } + void y(float a) { m_y = a; } + + PatchModel* parent_patch() const { return (PatchModel*)m_parent; } + +protected: + bool m_polyphonic; + PortModelList m_ports; ///< List of ports (instead of map to preserve order) + const PluginModel* m_plugin; ///< The plugin this node is an instance of + float m_x; ///< Just metadata, here as an optimization for OmGtk + float m_y; ///< Just metadata, here as an optimization for OmGtk + map > m_banks; ///< DSSI banks + +private: + // Prevent copies (undefined) + NodeModel(const NodeModel& copy); + NodeModel& operator=(const NodeModel& copy); +}; + + +typedef map NodeModelMap; + + +} // namespace LibOmClient + +#endif // NODEMODEL_H diff --git a/src/libs/client/OSCEngineInterface.cpp b/src/libs/client/OSCEngineInterface.cpp new file mode 100644 index 00000000..5ac598f1 --- /dev/null +++ b/src/libs/client/OSCEngineInterface.cpp @@ -0,0 +1,332 @@ +/* This file is part of Om. Copyright (C) 2006 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 "OSCEngineInterface.h" +#include "interface/ClientKey.h" + +namespace LibOmClient { + +/** Note the sending port is implicitly set by liblo, lo_send by default sends + * from the most recently created server, so create the OSC listener before + * this to have it all happen on the same port. Yeah, this is a big magic :/ + */ +OSCEngineInterface::OSCEngineInterface(const string& engine_url) +: _engine_url(engine_url) +, _engine_addr(lo_address_new_from_url(engine_url.c_str())) +, _id(0) +{ +} + + +OSCEngineInterface::~OSCEngineInterface() +{ + lo_address_free(_engine_addr); +} + + +/* *** EngineInterface implementation below here *** */ + + +/** Register with the engine via OSC. + * + * Note that this does not actually use 'key', since the engine creates + * it's own key for OSC clients (namely the incoming URL), for NAT + * traversal. It is a parameter to remain compatible with EngineInterface. + */ +void +OSCEngineInterface::register_client(ClientKey key, CountedPtr client) +{ + // FIXME: use parameters.. er, somehow. + assert(_engine_addr); + lo_send(_engine_addr, "/om/engine/register_client", "i", next_id()); +} + + +void +OSCEngineInterface::unregister_client(ClientKey key) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/engine/unregister_client", "i", next_id()); +} + + + +// Engine commands +void +OSCEngineInterface::load_plugins() +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/engine/load_plugins", "i", next_id()); +} + + +void +OSCEngineInterface::activate() +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/engine/activate", "i", next_id()); +} + + +void +OSCEngineInterface::deactivate() +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/engine/deactivate", "i", next_id()); +} + + +void +OSCEngineInterface::quit() +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/engine/quit", "i", next_id()); +} + + + +// Object commands + +void +OSCEngineInterface::create_patch(const string& path, + uint32_t poly) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/create_patch", "isi", + next_id(), + path.c_str(), + poly); +} + + +void +OSCEngineInterface::create_node(const string& path, + const string& plugin_type, + const string& plugin_uri, + bool polyphonic) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/create_node", "isssi", + next_id(), + path.c_str(), + plugin_type.c_str(), + plugin_uri.c_str(), + (polyphonic ? 1 : 0)); +} + + +void +OSCEngineInterface::rename(const string& old_path, + const string& new_name) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/rename", "iss", + next_id(), + old_path.c_str(), + new_name.c_str()); +} + + +void +OSCEngineInterface::destroy(const string& path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/destroy", "is", + next_id(), + path.c_str()); +} + + +void +OSCEngineInterface::clear_patch(const string& patch_path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/clear_patch", "is", + next_id(), + patch_path.c_str()); +} + + +void +OSCEngineInterface::enable_patch(const string& patch_path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/enable_patch", "is", + next_id(), + patch_path.c_str()); +} + + +void +OSCEngineInterface::disable_patch(const string& patch_path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/disable_patch", "is", + next_id(), + patch_path.c_str()); +} + + +void +OSCEngineInterface::connect(const string& src_port_path, + const string& dst_port_path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/connect", "iss", + next_id(), + src_port_path.c_str(), + dst_port_path.c_str()); +} + + +void +OSCEngineInterface::disconnect(const string& src_port_path, + const string& dst_port_path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/disconnect", "iss", + next_id(), + src_port_path.c_str(), + dst_port_path.c_str()); +} + + +void +OSCEngineInterface::disconnect_all(const string& node_path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/disconnect_all", "is", + next_id(), + node_path.c_str()); +} + + +void +OSCEngineInterface::set_port_value(const string& port_path, + float val) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/set_port_value", "isf", + next_id(), + port_path.c_str(), + val); +} + + +void +OSCEngineInterface::set_port_value(const string& port_path, + uint32_t voice, + float val) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/set_port_value", "isif", + next_id(), + port_path.c_str(), + voice, + val); +} + + +void +OSCEngineInterface::set_port_value_queued(const string& port_path, + float val) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/set_port_value_queued", "isf", + next_id(), + port_path.c_str(), + val); +} + + +void +OSCEngineInterface::set_program(const string& node_path, + uint32_t bank, + uint32_t program) +{ + assert(_engine_addr); + lo_send(_engine_addr, + (string("/dssi") + node_path + "/program").c_str(), + "ii", + bank, + program); +} + + +void +OSCEngineInterface::midi_learn(const string& node_path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/midi_learn", "is", + next_id(), + node_path.c_str()); +} + + +void +OSCEngineInterface::set_metadata(const string& obj_path, + const string& predicate, + const string& value) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/metadata/set", "isss", + next_id(), + obj_path.c_str(), + predicate.c_str(), + value.c_str()); +} + + +// Requests // + +void +OSCEngineInterface::ping() +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/ping", "i", next_id()); +} + + +void +OSCEngineInterface::request_port_value(const string& port_path) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/request/port_value", "is", + next_id(), + port_path.c_str()); +} + + +void +OSCEngineInterface::request_plugins() +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/request/plugins", "i", next_id()); +} + + +void +OSCEngineInterface::request_all_objects() +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/request/all_objects", "i", next_id()); +} + + + +} // namespace LibOmClient + + diff --git a/src/libs/client/OSCEngineInterface.h b/src/libs/client/OSCEngineInterface.h new file mode 100644 index 00000000..63157da1 --- /dev/null +++ b/src/libs/client/OSCEngineInterface.h @@ -0,0 +1,139 @@ +/* This file is part of Om. Copyright (C) 2006 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 OSCENGINEINTERFACE_H +#define OSCENGINEINTERFACE_H + +#include +#include +#include +#include "interface/EngineInterface.h" +using std::string; +using Om::Shared::EngineInterface; +using Om::Shared::ClientInterface; +using Om::Shared::ClientKey; + + +namespace LibOmClient { + +/* OSC (via liblo) interface to the engine. + * + * Clients can use this opaquely as an EngineInterface* to control the engine + * over OSC (whether over a network or not, etc). + * + * \ingroup libomclient + */ +class OSCEngineInterface : public EngineInterface +{ +public: + OSCEngineInterface(const string& engine_url); + + ~OSCEngineInterface(); + + string engine_url() { return _engine_url; } + + inline size_t next_id() + { if (_id != -1) { _id = (_id == -2) ? 0 : _id+1; } return _id; } + + void enable_responses() { _id = 0; } + void disable_responses() { _id = -1; } + + + /* *** EngineInterface implementation below here *** */ + + // Client registration + void register_client(ClientKey key, CountedPtr client); + void unregister_client(ClientKey key); + + + // Engine commands + void load_plugins(); + void activate(); + void deactivate(); + void quit(); + + + // Object commands + + void create_patch(const string& path, + uint32_t poly); + + void create_node(const string& path, + const string& plugin_type, + const string& plugin_uri, + bool polyphonic); + + void rename(const string& old_path, + const string& new_name); + + void destroy(const string& path); + + void clear_patch(const string& patch_path); + + void enable_patch(const string& patch_path); + + void disable_patch(const string& patch_path); + + void connect(const string& src_port_path, + const string& dst_port_path); + + void disconnect(const string& src_port_path, + const string& dst_port_path); + + void disconnect_all(const string& node_path); + + void set_port_value(const string& port_path, + float val); + + void set_port_value(const string& port_path, + uint32_t voice, + float val); + + void set_port_value_queued(const string& port_path, + float val); + + void set_program(const string& node_path, + uint32_t bank, + uint32_t program); + + void midi_learn(const string& node_path); + + void set_metadata(const string& obj_path, + const string& predicate, + const string& value); + + // Requests // + + void ping(); + + void request_port_value(const string& port_path); + + void request_plugins(); + + void request_all_objects(); + +protected: + string _engine_url; + lo_address _engine_addr; + int _client_port; + int32_t _id; +}; + + +} // namespace LibOmClient + +#endif // OSCENGINEINTERFACE_H + diff --git a/src/libs/client/OSCListener.cpp b/src/libs/client/OSCListener.cpp new file mode 100644 index 00000000..503be47d --- /dev/null +++ b/src/libs/client/OSCListener.cpp @@ -0,0 +1,413 @@ +/* This file is part of Om. 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 "OSCListener.h" +//#include "NodeModel.h" +//#include "PluginModel.h" +#include +#include +#include +#include +using std::cerr; using std::cout; using std::endl; + +namespace LibOmClient { + + +/** Construct a OSCListener with a user-provided ModelClientInterface object for notification + * of engine events. + */ +OSCListener::OSCListener(int listen_port) +: _listen_port(listen_port), + _st(NULL)//, +// _receiving_node(false), +// _receiving_node_model(NULL), +// _receiving_node_num_ports(0), +// _num_received_ports(0) +{ + start(); +} + + +OSCListener::~OSCListener() +{ + stop(); +} + + +void +OSCListener::start() +{ + if (_st != NULL) + return; + + if (_listen_port == 0) { + _st = lo_server_thread_new(NULL, error_cb); + _listen_port = lo_server_thread_get_port(_st); + } else { + char port_str[8]; + snprintf(port_str, 8, "%d", _listen_port); + _st = lo_server_thread_new(port_str, error_cb); + } + + if (_st == NULL) { + cerr << "[OSCListener] Could not start OSC listener. Aborting." << endl; + exit(EXIT_FAILURE); + } else { + cout << "[OSCListener] Started OSC listener on port " << lo_server_thread_get_port(_st) << endl; + } + + // FIXME + lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL); + + //lo_server_thread_add_method(_st, "/om/response/ok", "i", om_response_ok_cb, this); + //lo_server_thread_add_method(_st, "/om/response/error", "is", om_responseerror_cb, this); + + setup_callbacks(); + + // Display any uncaught messages to the console + //lo_server_thread_add_method(_st, NULL, NULL, unknown_cb, NULL); + + lo_server_thread_start(_st); +} + + +void +OSCListener::stop() +{ + if (_st != NULL) { + //unregister_client(); + lo_server_thread_free(_st); + _st = NULL; + } +} + + +int +OSCListener::generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) +{ + printf("[OSCMsg] %s (%s)\t", path, types); + + for (int i=0; i < argc; ++i) { + lo_arg_pp(lo_type(types[i]), argv[i]); + printf("\t"); + } + printf("\n"); + + /*for (int i=0; i < argc; ++i) { + printf(" '%c' ", types[i]); + lo_arg_pp(lo_type(types[i]), argv[i]); + printf("\n"); + } + printf("\n");*/ + + return 1; // not handled +} + + +void +OSCListener::error_cb(int num, const char* msg, const char* path) +{ + cerr << "Got error from server: " << msg << endl; +} + + + +int +OSCListener::unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) +{ + string msg = "Received unknown OSC message: "; + msg += path; + + cerr << msg << endl; + + return 0; +} + + +void +OSCListener::setup_callbacks() +{ + lo_server_thread_add_method(_st, "/om/num_plugins", "i", num_plugins_cb, this); + lo_server_thread_add_method(_st, "/om/plugin", "sss", plugin_cb, this); + lo_server_thread_add_method(_st, "/om/new_patch", "si", new_patch_cb, this); + lo_server_thread_add_method(_st, "/om/destroyed", "s", destroyed_cb, this); + lo_server_thread_add_method(_st, "/om/patch_enabled", "s", patch_enabled_cb, this); + lo_server_thread_add_method(_st, "/om/patch_disabled", "s", patch_disabled_cb, this); + lo_server_thread_add_method(_st, "/om/patch_cleared", "s", patch_cleared_cb, this); + lo_server_thread_add_method(_st, "/om/object_renamed", "ss", object_renamed_cb, this); + lo_server_thread_add_method(_st, "/om/new_connection", "ss", connection_cb, this); + lo_server_thread_add_method(_st, "/om/disconnection", "ss", disconnection_cb, this); + lo_server_thread_add_method(_st, "/om/new_node", "sssii", new_node_cb, this); + lo_server_thread_add_method(_st, "/om/new_port", "ssi", new_port_cb, this); + lo_server_thread_add_method(_st, "/om/metadata/update", "sss", metadata_update_cb, this); + lo_server_thread_add_method(_st, "/om/control_change", "sf", control_change_cb, this); + lo_server_thread_add_method(_st, "/om/program_add", "siis", program_add_cb, this); + lo_server_thread_add_method(_st, "/om/program_remove", "sii", program_remove_cb, this); +} + + +/** Catches errors that aren't a direct result of a client request. + */ +int +OSCListener::m_error_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + cerr << "ERROR: " << argv[0]->s << endl; + // FIXME + //error((char*)argv[0]); + return 0; +} + + +int +OSCListener::m_new_patch_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + new_patch(&argv[0]->s, argv[1]->i); // path, poly + return 0; +} + + +int +OSCListener::m_destroyed_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + object_destroyed((const char*)&argv[0]->s); + return 0; +} + + +int +OSCListener::m_patch_enabled_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + patch_enabled((const char*)&argv[0]->s); + return 0; +} + + +int +OSCListener::m_patch_disabled_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + patch_disabled((const char*)&argv[0]->s); + return 0; +} + + +int +OSCListener::m_patch_cleared_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + patch_cleared((const char*)&argv[0]->s); + return 0; +} + + +int +OSCListener::m_object_renamed_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + object_renamed((const char*)&argv[0]->s, (const char*)&argv[1]->s); + return 0; +} + + +int +OSCListener::m_connection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* const src_port_path = &argv[0]->s; + const char* const dst_port_path = &argv[1]->s; + + connection(src_port_path, dst_port_path); + + return 0; +} + + +int +OSCListener::m_disconnection_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* src_port_path = &argv[0]->s; + const char* dst_port_path = &argv[1]->s; + + disconnection(src_port_path, dst_port_path); + + return 0; +} + + +/** Notification of a new node creation. + */ +int +OSCListener::m_new_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* type = &argv[0]->s; + const char* uri = &argv[1]->s; + const char* node_path = &argv[2]->s; + const int32_t poly = argv[3]->i; + const int32_t num_ports = argv[4]->i; + + new_node(type, uri, node_path, poly, num_ports); + + /*_receiving_node_model = new NodeModel(node_path); + _receiving_node_model->polyphonic((poly == 1)); + _receiving_node_num_ports = num_ports; + + PluginModel* pi = new PluginModel(type, uri); + _receiving_node_model->plugin(pi); + + _receiving_node = true; + _num_received_ports = 0; + */ + return 0; +} + + +/** Notification of a new port creation. + */ +int +OSCListener::m_new_port_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* port_path = &argv[0]->s; + const char* type = &argv[1]->s; + bool is_output = (argv[2]->i == 1); + /*const char* direction = &argv[2]->s; + const char* hint = &argv[3]->s; + float default_val = argv[4]->f; + float min_val = argv[5]->f; + float max_val = argv[6]->f;*/ + + new_port(port_path, type, is_output); +#if 0 + PortModel::Type ptype = PortModel::CONTROL; + if (!strcmp(type, "AUDIO")) ptype = PortModel::AUDIO; + else if (!strcmp(type, "CONTROL")) ptype = PortModel::CONTROL; + else if (!strcmp(type, "MIDI")) ptype = PortModel::MIDI; + else cerr << "[OSCListener] WARNING: Unknown port type received (" << type << ")" << endl; + +#if 0 + PortModel::Direction pdir = PortModel::INPUT; + if (!strcmp(direction, "INPUT")) pdir = PortModel::INPUT; + else if (!strcmp(direction, "OUTPUT")) pdir = PortModel::OUTPUT; + else cerr << "[OSCListener] WARNING: Unknown port direction received (" << direction << ")" << endl; +#endif + PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT; + +/* + PortModel::Hint phint = PortModel::NONE; + if (!strcmp(hint, "LOGARITHMIC")) phint = PortModel::LOGARITHMIC; + else if (!strcmp(hint, "INTEGER")) phint = PortModel::INTEGER; + else if (!strcmp(hint, "TOGGLE")) phint = PortModel::TOGGLE; + + PortModel* port_model = new PortModel(port_path, ptype, pdir, phint, default_val, min_val, max_val); +*/ + PortModel* port_model = new PortModel(port_path, ptype, pdir); + if (m_receiving_node) { + assert(m_receiving_node_model); + m_receiving_node_model->add_port(port_model); + ++m_num_received_ports; + + // If transmission is done, send new node to client + if (m_num_received_ports == m_receiving_node_num_ports) { + new_node_model(m_receiving_node_model); + m_receiving_node = false; + m_receiving_node_model = NULL; + m_num_received_ports = 0; + } + } else { + new_port_model(port_model); + } + +#endif + return 0; +} + + +/** Notification of a new or updated piece of metadata. + */ +int +OSCListener::m_metadata_update_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* obj_path = &argv[0]->s; + const char* key = &argv[1]->s; + const char* value = &argv[2]->s; + + metadata_update(obj_path, key, value); + + return 0; +} + + +int +OSCListener::m_control_change_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* const port_path = &argv[0]->s; + const float value = argv[1]->f; + + control_change(port_path, value); + + return 0; +} + + +/** Number of plugins in engine, should precede /om/plugin messages in response + * to a /om/send_plugins + */ +int +OSCListener::m_num_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + /** Not worth it implementing a ModelClientInterface callback for this (?) + * Or I'm just lazy. FIXME? */ + num_plugins(argv[0]->i); + + return 0; +} + + +/** A plugin info response from the server, in response to a /send_plugins + */ +int +OSCListener::m_plugin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + assert(argc == 3 && !strcmp(types, "sss")); + new_plugin(&argv[0]->s, &argv[1]->s, &argv[2]->s); // type, uri + + return 0; +} + + +int +OSCListener::m_program_add_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* node_path = &argv[0]->s; + int32_t bank = argv[1]->i; + int32_t program = argv[2]->i; + const char* name = &argv[3]->s; + + program_add(node_path, bank, program, name); + + return 0; +} + + +int +OSCListener::m_program_remove_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* node_path = &argv[0]->s; + int32_t bank = argv[1]->i; + int32_t program = argv[2]->i; + + program_remove(node_path, bank, program); + + return 0; +} + + +} // namespace LibOmClient diff --git a/src/libs/client/OSCListener.h b/src/libs/client/OSCListener.h new file mode 100644 index 00000000..d0b9cc1c --- /dev/null +++ b/src/libs/client/OSCListener.h @@ -0,0 +1,116 @@ +/* This file is part of Om. 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 OSCLISTENER_H +#define OSCLISTENER_H + +#include +#include +#include "interface/ClientInterface.h" + +namespace LibOmClient { + +//class NodeModel; +//class PresetModel; + +/* Some boilerplate killing macros... */ +#define LO_HANDLER_ARGS const char* path, const char* types, lo_arg** argv, int argc, lo_message msg + +/* Defines a static handler to be passed to lo_add_method, which is a trivial + * wrapper around a non-static method that does the real work. Makes a whoole + * lot of ugly boiler plate go away */ +#define LO_HANDLER(name) \ +int m_##name##_cb (LO_HANDLER_ARGS);\ +inline static int name##_cb(LO_HANDLER_ARGS, void* osc_listener)\ +{ return ((OSCListener*)osc_listener)->m_##name##_cb(path, types, argv, argc, msg); } + + +/** Callbacks for "notification band" OSC messages. + * + * Receives all notification of engine state, but not replies on the "control + * band". See OSC namespace documentation for details. + * + * Right now this class and Comm share the same lo_server_thread and the barrier + * between them is a bit odd, but eventually this class will be able to listen + * on a completely different port (ie have it's own lo_server_thread) to allow + * things like listening to the notification band over TCP while sending commands + * on the control band over UDP. + * + * \ingroup libomclient + */ +class OSCListener : virtual public Om::Shared::ClientInterface +{ +public: + OSCListener(int listen_port); + ~OSCListener(); + + void start(); + void stop(); + + int listen_port() { return _listen_port; } + string listen_url() { return lo_server_thread_get_url(_st); } + +private: + // Prevent copies + OSCListener(const OSCListener& copy); + OSCListener& operator=(const OSCListener& copy); + + void setup_callbacks(); + + static void error_cb(int num, const char* msg, const char* path); + static int generic_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data); + static int unknown_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* osc_receiver); + /* + inline static int om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm); + int m_om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data); + inline static int om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm); + int m_om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data); +*/ + int _listen_port; + lo_server_thread _st; + + // Used for receiving nodes - multiple messages are received before + // sending an event to the client (via ModelClientInterface) + //bool _receiving_node; + //NodeModel* _receiving_node_model; + //int32_t _receiving_node_num_ports; + //int32_t _num_received_ports; + + LO_HANDLER(error); + LO_HANDLER(num_plugins); + LO_HANDLER(plugin); + LO_HANDLER(plugin_list_end); + LO_HANDLER(new_patch); + LO_HANDLER(destroyed); + LO_HANDLER(patch_enabled); + LO_HANDLER(patch_disabled); + LO_HANDLER(patch_cleared); + LO_HANDLER(object_renamed); + LO_HANDLER(connection); + LO_HANDLER(disconnection); + LO_HANDLER(new_node); + LO_HANDLER(new_port); + LO_HANDLER(metadata_update); + LO_HANDLER(control_change); + LO_HANDLER(program_add); + LO_HANDLER(program_remove); +}; + + +} // namespace LibOmClient + +#endif // OSCLISTENER_H diff --git a/src/libs/client/OSCModelEngineInterface.cpp b/src/libs/client/OSCModelEngineInterface.cpp new file mode 100644 index 00000000..9e648141 --- /dev/null +++ b/src/libs/client/OSCModelEngineInterface.cpp @@ -0,0 +1,364 @@ +/* This file is part of Om. 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 "OSCModelEngineInterface.h" +#include +#include +#include +#include +#include +#include +#include "OSCListener.h" +#include "PatchModel.h" +#include "ConnectionModel.h" +#include "PresetModel.h" +#include "ControlModel.h" +#include "NodeModel.h" +#include "PluginModel.h" + +using std::cerr; using std::cout; using std::endl; + +namespace LibOmClient { + + +/** Construct a OSCModelEngineInterface with a user-provided ModelClientInterface object for notification + * of engine events. + */ +OSCModelEngineInterface::OSCModelEngineInterface(const string& engine_url) +: OSCEngineInterface(engine_url), + m_request_id(0), + m_is_attached(false), + m_is_registered(false) + /*m_blocking(false), + m_waiting_for_response(false), + m_wait_response_id(0), + m_response_received(false), + m_wait_response_was_affirmative(false), + m_response_semaphore(0)*/ +{ +} + + +OSCModelEngineInterface::~OSCModelEngineInterface() +{ + detach(); +} + + +/** Attempt to connect to the Om engine and notify it of our existance. + * + * Passing a client_port of 0 will automatically choose a free port. If the + * @a block parameter is true, this function will not return until a connection + * has successfully been made. + */ +void +OSCModelEngineInterface::attach(bool block) +{ + cerr << "FIXME: listen thread\n"; + //start_listen_thread(_client_port); + + /*if (engine_url == "") { + string local_url = m_osc_listener->listen_url().substr( + 0, m_osc_listener->listen_url().find_last_of(":")); + local_url.append(":16180"); + _engine_addr = lo_address_new_from_url(local_url.c_str()); + } else { + _engine_addr = lo_address_new_from_url(engine_url.c_str()); + } + */ + _engine_addr = lo_address_new_from_url(_engine_url.c_str()); + + if (_engine_addr == NULL) { + cerr << "Unable to connect, aborting." << endl; + exit(EXIT_FAILURE); + } + + char* lo_url = lo_address_get_url(_engine_addr); + cout << "[OSCModelEngineInterface] Attempting to contact engine at " << lo_url << " ..." << endl; + + this->ping(); + + m_is_attached = true; // FIXME + + /*if (block) { + set_wait_response_id(request_id); + + while (1) { + if (m_response_semaphore.try_wait() != 0) { + cout << "."; + cout.flush(); + ping(request_id); + usleep(100000); + } else { + cout << " connected." << endl; + m_waiting_for_response = false; + break; + } + } + } + */ + + free(lo_url); +} + +void +OSCModelEngineInterface::detach() +{ + m_is_attached = false; +} + +#if 0 +void +OSCModelEngineInterface::start_listen_thread(int client_port) +{ + if (m_st != NULL) + return; + + if (client_port == 0) { + m_st = lo_server_thread_new(NULL, error_cb); + } else { + char port_str[8]; + snprintf(port_str, 8, "%d", client_port); + m_st = lo_server_thread_new(port_str, error_cb); + } + + if (m_st == NULL) { + cerr << "[OSCModelEngineInterface] Could not start OSC listener. Aborting." << endl; + exit(EXIT_FAILURE); + } else { + cout << "[OSCModelEngineInterface] Started OSC listener on port " << lo_server_thread_get_port(m_st) << endl; + } + + lo_server_thread_add_method(m_st, NULL, NULL, generic_cb, NULL); + + lo_server_thread_add_method(m_st, "/om/response/ok", "i", om_response_ok_cb, this); + lo_server_thread_add_method(m_st, "/om/response/error", "is", om_response_error_cb, this); + + + m_osc_listener = new OSCListener(m_st, m_client_hooks); + m_osc_listener->setup_callbacks(); + + // Display any uncaught messages to the console + lo_server_thread_add_method(m_st, NULL, NULL, unknown_cb, NULL); + + lo_server_thread_start(m_st); +} +#endif + +///// OSC Commands ///// + + + +/** Load a node. + */ +void +OSCModelEngineInterface::create_node_from_model(const NodeModel* nm) +{ + assert(_engine_addr); + + // Load by URI + if (nm->plugin()->uri().length() > 0) { + lo_send(_engine_addr, "/om/synth/create_node", "isssi", next_id(), + nm->path().c_str(), + nm->plugin()->type_string(), + nm->plugin()->uri().c_str(), + (nm->polyphonic() ? 1 : 0)); + // Load by libname, label + } else { + //assert(nm->plugin()->lib_name().length() > 0); + assert(nm->plugin()->plug_label().length() > 0); + lo_send(_engine_addr, "/om/synth/create_node", "issssi", next_id(), + nm->path().c_str(), + nm->plugin()->type_string(), + nm->plugin()->lib_name().c_str(), + nm->plugin()->plug_label().c_str(), + (nm->polyphonic() ? 1 : 0)); + } +} + + +/** Create a patch. + */ +void +OSCModelEngineInterface::create_patch_from_model(const PatchModel* pm) +{ + assert(_engine_addr); + lo_send(_engine_addr, "/om/synth/create_patch", "isi", next_id(), pm->path().c_str(), pm->poly()); +} + + +/** Notify LASH restoring is finished */ +/* +void +OSCModelEngineInterface::lash_restore_finished() +{ + assert(_engine_addr != NULL); + int id = m_request_id++; + lo_send(_engine_addr, "/om/lash/restore_finished", "i", id); +} +*/ +#if 0 +/** Set/add a piece of metadata. + */ +void +OSCModelEngineInterface::set_metadata(const string& obj_path, + const string& key, const string& value) +{ + assert(_engine_addr != NULL); + int id = m_request_id++; + + // Deal with the "special" DSSI metadata strings + if (key.substr(0, 16) == "dssi-configure--") { + string path = "/dssi" + obj_path + "/configure"; + string dssi_key = key.substr(16); + lo_send(_engine_addr, path.c_str(), "ss", dssi_key.c_str(), value.c_str()); + } else if (key == "dssi-program") { + string path = "/dssi" + obj_path + "/program"; + string dssi_bank_str = value.substr(0, value.find("/")); + int dssi_bank = atoi(dssi_bank_str.c_str()); + string dssi_program_str = value.substr(value.find("/")+1); + int dssi_program = atoi(dssi_program_str.c_str()); + lo_send(_engine_addr, path.c_str(), "ii", dssi_bank, dssi_program); + } + + // Normal metadata + lo_send(_engine_addr, "/om/metadata/set", "isss", id, + obj_path.c_str(), key.c_str(), value.c_str()); +} +#endif + +/** Set all pieces of metadata in a NodeModel. + */ +void +OSCModelEngineInterface::set_all_metadata(const NodeModel* nm) +{ + assert(_engine_addr != NULL); + + for (map::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) + set_metadata(nm->path(), (*i).first, (*i).second.c_str()); +} + + +/** Set a preset by setting all relevant controls for a patch. + */ +void +OSCModelEngineInterface::set_preset(const string& patch_path, const PresetModel* const pm) +{ + assert(patch_path.find("//") == string::npos); + for (list::const_iterator i = pm->controls().begin(); i != pm->controls().end(); ++i) { + set_port_value_queued((*i).port_path(), (*i).value()); + usleep(1000); + } +} + + +///// Requests ///// + + +#if 0 +/** Sets the response ID to be waited for on the next call to wait_for_response() + */ + +void +OSCModelEngineInterface::set_wait_response_id(int id) +{ + assert(!m_waiting_for_response); + m_wait_response_id = id; + m_response_received = false; + m_waiting_for_response = true; +} + + +/** Waits for the response set by set_wait_response() from the server. + * + * Returns whether or not the response was positive (ie a success message) + * or negative (ie an error) + */ +bool +OSCModelEngineInterface::wait_for_response() +{ + cerr << "[OSCModelEngineInterface] Waiting for response " << m_wait_response_id << ": "; + bool ret = true; + + assert(m_waiting_for_response); + assert(!m_response_received); + + while (!m_response_received) + m_response_semaphore.wait(); + + cerr << " received." << endl; + + m_waiting_for_response = false; + ret = m_wait_response_was_affirmative; + + return ret; +} +#endif + +///// Static OSC callbacks ////// + + +//// End static callbacks, member callbacks below //// + +/* +int +OSCModelEngineInterface::m_om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data) +{ + assert(argc == 1 && !strcmp(types, "i")); + + // FIXME + if (!m_is_attached) + m_is_attached = true; + + if (m_waiting_for_response) { + const int request_id = argv[0]->i; + + if (request_id == m_wait_response_id) { + m_response_received = true; + m_wait_response_was_affirmative = true; + m_response_semaphore.post(); + } + } + + return 0; +} + + +int +OSCModelEngineInterface::m_om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data) +{ + assert(argc == 2 && !strcmp(types, "is")); + + const int request_id = argv[0]->i; + const char* msg = &argv[1]->s; + + if (m_waiting_for_response) { + if (request_id == m_wait_response_id) { + m_response_received = true; + m_wait_response_was_affirmative = false; + m_response_semaphore.post(); + } + } + + cerr << "ERROR: " << msg << endl; + //if (m_client_hooks != NULL) + // m_client_hooks->error(msg); + + return 0; +} +*/ + +} // namespace LibOmClient diff --git a/src/libs/client/OSCModelEngineInterface.h b/src/libs/client/OSCModelEngineInterface.h new file mode 100644 index 00000000..4400a1b4 --- /dev/null +++ b/src/libs/client/OSCModelEngineInterface.h @@ -0,0 +1,117 @@ +/* This file is part of Om. 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 OSCCONTROLLER_H +#define OSCCONTROLLER_H + +#include +#include +#include "util/Semaphore.h" +#include "interface/EngineInterface.h" +#include "OSCEngineInterface.h" +#include "ModelEngineInterface.h" +using std::string; + +/** \defgroup libomclient Client Library + */ + +namespace LibOmClient { + +class NodeModel; +class PresetModel; +class PatchModel; +class OSCListener; +class ModelClientInterface; + + +/** Old model-based OSC engine command interface. + * + * This is an old class from before when the well-defined interfaces between + * engine and client were defined. I've wrapped it around OSCEngineInterface + * so all the common functions are implemented there, and implemented the + * remaining functions using those, for compatibility. Hopefully something + * better gets figured out and this can go away completely, but for now this + * gets the existing clients working through EngineInterface in the easiest + * way possible. This class needs to die. + * + * Old comment: + * Handles all OSC communication on the "control band". For the time being, + * manages the OSCListener which handles the "notification band", but this + * will change in the future (for complete separation). See OSC namespace + * documentation for more details. + * + * \ingroup libomclient + */ +class OSCModelEngineInterface : public OSCEngineInterface, public ModelEngineInterface +{ +public: + //OSCModelEngineInterface(ModelClientInterface* const client_hooks, const string& engine_url); + OSCModelEngineInterface(const string& engine_url); + ~OSCModelEngineInterface(); + + void attach(bool block = true); + void detach(); + + bool is_attached() { return m_is_attached; } + + // FIXME: reimplement + void set_wait_response_id(int32_t id) {} + bool wait_for_response() { return false; } + int get_next_request_id() { return m_request_id++; } + + /* *** Model alternatives to EngineInterface functions below *** */ + + void create_patch_from_model(const PatchModel* pm); + void create_node_from_model(const NodeModel* nm); + + void set_all_metadata(const NodeModel* nm); + void set_preset(const string& patch_path, const PresetModel* const pm); + +protected: + void start_listen_thread(); + + int m_request_id; + + bool m_is_attached; + bool m_is_registered; + /* + bool m_blocking; + bool m_waiting_for_response; + int m_wait_response_id; + bool m_response_received; + bool m_wait_response_was_affirmative; + + Semaphore m_response_semaphore; + */ +private: + // Prevent copies + OSCModelEngineInterface(const OSCModelEngineInterface& copy); + OSCModelEngineInterface& operator=(const OSCModelEngineInterface& copy); +}; +/* +inline int +OSCModelEngineInterface::om_response_ok_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm) { + return ((OSCModelEngineInterface*)comm)->m_om_response_ok_cb(path, types, argv, argc, data); +} + +inline int +OSCModelEngineInterface::om_response_error_cb(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* comm) { + return ((OSCModelEngineInterface*)comm)->m_om_response_error_cb(path, types, argv, argc, data); +} +*/ +} // namespace LibOmClient + +#endif // OSCCONTROLLER_H diff --git a/src/libs/client/ObjectController.h b/src/libs/client/ObjectController.h new file mode 100644 index 00000000..c79ac24d --- /dev/null +++ b/src/libs/client/ObjectController.h @@ -0,0 +1,43 @@ +/* This file is part of Om. 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 OBJECTCONTROLLER_H +#define OBJECTCONTROLLER_H + +namespace LibOmClient { + + +/** A trivial base class for controllers of an ObjectModel. + * + * This is so ObjectModels can have pointers to app-specified controllers, + * and the pointer relationships in models (ie PatchModel has pointers to + * all it's NodeModel children, etc) can be used to find controllers of + * Models, rather than having a parallel structure of pointers in the + * app's controllers. + * + * \ingroup libomclient + */ +class ObjectController +{ +public: + virtual ~ObjectController() {} +}; + + +} // namespace LibOmClient + + +#endif // OBJECTCONTROLLER_H diff --git a/src/libs/client/ObjectModel.cpp b/src/libs/client/ObjectModel.cpp new file mode 100644 index 00000000..cb196f8a --- /dev/null +++ b/src/libs/client/ObjectModel.cpp @@ -0,0 +1,64 @@ +/* This file is part of Om. 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 "ObjectModel.h" + +namespace LibOmClient { + + +ObjectModel::ObjectModel(const string& path) +: m_path(path), + m_parent(NULL), + m_controller(NULL) +{ +} + + +/** Get a piece of metadata for this objeect. + * + * @return Metadata value with key @a key, empty string otherwise. + */ +string +ObjectModel::get_metadata(const string& key) const +{ + map::const_iterator i = m_metadata.find(key); + if (i != m_metadata.end()) + return (*i).second; + else + return ""; +} + + +/** The base path for children of this Object. + * + * (This is here to avoid needing special cases for the root patch everywhere). + */ +string +ObjectModel::base_path() const +{ + return (path() == "/") ? "/" : path() + "/"; +} + + +void +ObjectModel::set_controller(ObjectController* c) +{ + assert(m_controller == NULL); + m_controller = c; +} + +} // namespace LibOmClient + diff --git a/src/libs/client/ObjectModel.h b/src/libs/client/ObjectModel.h new file mode 100644 index 00000000..be58a00f --- /dev/null +++ b/src/libs/client/ObjectModel.h @@ -0,0 +1,84 @@ +/* This file is part of Om. 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 OBJECTMODEL_H +#define OBJECTMODEL_H + +#include +#include +#include +#include +#include +#include +#include "util/Path.h" + +using std::string; using std::map; using std::find; +using std::cout; using std::cerr; using std::endl; +using Om::Path; + +namespace LibOmClient { + +class ObjectController; + + +/** Base class for all OmObject models (NodeModel, PatchModel, PortModel). + * + * \ingroup libomclient + */ +class ObjectModel +{ +public: + ObjectModel(const string& path); + ObjectModel() : m_path("/UNINITIALIZED"), m_parent(NULL) {} // FIXME: remove + + virtual ~ObjectModel() {} + + const map& metadata() const { return m_metadata; } + string get_metadata(const string& key) const; + void set_metadata(const string& key, const string& value) + { assert(value.length() > 0); m_metadata[key] = value; } + + inline const Path& path() const { return m_path; } + virtual void set_path(const Path& p) { m_path = p; } + + ObjectModel* parent() const { return m_parent; } + virtual void set_parent(ObjectModel* p) { m_parent = p; } + + ObjectController* controller() const { return m_controller; } + + void set_controller(ObjectController* c); + + // Convenience functions + string base_path() const; + const string name() const { return m_path.name(); } + +protected: + Path m_path; + ObjectModel* m_parent; + ObjectController* m_controller; + + map m_metadata; + +private: + // Prevent copies (undefined) + ObjectModel(const ObjectModel& copy); + ObjectModel& operator=(const ObjectModel& copy); +}; + + +} // namespace LibOmClient + +#endif // OBJECTMODEL_H diff --git a/src/libs/client/PatchLibrarian.cpp b/src/libs/client/PatchLibrarian.cpp new file mode 100644 index 00000000..65323435 --- /dev/null +++ b/src/libs/client/PatchLibrarian.cpp @@ -0,0 +1,834 @@ +/* This file is part of Om. 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 "PatchLibrarian.h" +#include +#include +#include +#include "PatchModel.h" +#include "NodeModel.h" +#include "ModelClientInterface.h" +#include "ConnectionModel.h" +#include "PortModel.h" +#include "PresetModel.h" +#include "OSCModelEngineInterface.h" +#include "PluginModel.h" +#include "util/Path.h" +#include +#include +#include +#include // for pair, make_pair +#include +#include +#include +#include // for usleep +#include // for atof +#include + +using std::string; using std::vector; using std::pair; +using std::cerr; using std::cout; using std::endl; + +namespace LibOmClient { + + +/** Searches for the filename passed in the path, returning the full + * path of the file, or the empty string if not found. + * + * This function tries to be as friendly a black box as possible - if the path + * passed is an absolute path and the file is found there, it will return + * that path, etc. + * + * additional_path is a list (colon delimeted as usual) of additional + * directories to look in. ie the directory the parent patch resides in would + * be a good idea to pass as additional_path, in the case of a subpatch. + */ +string +PatchLibrarian::find_file(const string& filename, const string& additional_path) +{ + string search_path = additional_path + ":" + m_patch_path; + + // Try to open the raw filename first + std::ifstream is(filename.c_str(), std::ios::in); + if (is.good()) { + is.close(); + return filename; + } + + string directory; + string full_patch_path = ""; + + while (search_path != "") { + directory = search_path.substr(0, search_path.find(':')); + if (search_path.find(':') != string::npos) + search_path = search_path.substr(search_path.find(':')+1); + else + search_path = ""; + + full_patch_path = directory +"/"+ filename; + + std::ifstream is; + is.open(full_patch_path.c_str(), std::ios::in); + + if (is.good()) { + is.close(); + return full_patch_path; + } else { + cerr << "[PatchLibrarian] Could not find patch file " << full_patch_path << endl; + } + } + + return ""; +} + + +/** Save a patch from a PatchModel to a filename. + * + * The filename passed is the true filename the patch will be saved to (with no prefixing or anything + * like that), and the patch_model's filename member will be set accordingly. + * + * This will break if: + * - The filename does not have an extension (ie contain a ".") + * - The patch_model has no (Om) path + */ +void +PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool recursive) +{ + assert(filename != ""); + assert(patch_model->path() != ""); + + cout << "Saving patch " << patch_model->path() << " to " << filename << endl; + + patch_model->filename(filename); + + string dir = filename.substr(0, filename.find_last_of("/")); + + NodeModel* nm = NULL; + PatchModel* spm = NULL; // subpatch model + + xmlDocPtr xml_doc = NULL; + xmlNodePtr xml_root_node = NULL; + xmlNodePtr xml_node = NULL; + xmlNodePtr xml_child_node = NULL; + xmlNodePtr xml_grandchild_node = NULL; + + xml_doc = xmlNewDoc((xmlChar*)"1.0"); + xml_root_node = xmlNewNode(NULL, (xmlChar*)"patch"); + xmlDocSetRootElement(xml_doc, xml_root_node); + + const size_t temp_buf_length = 255; + char temp_buf[temp_buf_length]; + + string patch_name; + if (patch_model->path() != "/") { + patch_name = patch_model->name(); + } else { + patch_name = filename; + if (patch_name.find("/") != string::npos) + patch_name = patch_name.substr(patch_name.find_last_of("/") + 1); + if (patch_name.find(".") != string::npos) + patch_name = patch_name.substr(0, patch_name.find_last_of(".")); + } + + assert(patch_name.length() > 0); + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"name", + (xmlChar*)patch_name.c_str()); + + snprintf(temp_buf, temp_buf_length, "%zd", patch_model->poly()); + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); + + // Write metadata + for (map::const_iterator i = patch_model->metadata().begin(); + i != patch_model->metadata().end(); ++i) { + // Dirty hack, don't save coordinates in patch file + if ((*i).first != "module-x" && (*i).first != "module-y" + && (*i).first != "filename") + xml_node = xmlNewChild(xml_root_node, NULL, + (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); + + assert((*i).first != "node"); + assert((*i).first != "subpatch"); + assert((*i).first != "name"); + assert((*i).first != "polyphony"); + assert((*i).first != "preset"); + } + + // Save nodes and subpatches + for (NodeModelMap::const_iterator i = patch_model->nodes().begin(); i != patch_model->nodes().end(); ++i) { + nm = i->second; + + if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch + spm = (PatchModel*)i->second; + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL); + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->name().c_str()); + + string ref_filename; + // No path + if (spm->filename() == "") { + ref_filename = spm->name() + ".om"; + spm->filename(dir +"/"+ ref_filename); + // Absolute path + } else if (spm->filename().substr(0, 1) == "/") { + // Attempt to make it a relative path, if it's undernath this patch's dir + if (dir.substr(0, 1) == "/" && spm->filename().substr(0, dir.length()) == dir) { + ref_filename = spm->filename().substr(dir.length()+1); + } else { // FIXME: not good + ref_filename = spm->filename().substr(spm->filename().find_last_of("/")+1); + spm->filename(dir +"/"+ ref_filename); + } + } else { + ref_filename = spm->filename(); + } + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"filename", (xmlChar*)ref_filename.c_str()); + + snprintf(temp_buf, temp_buf_length, "%zd", spm->poly()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); + + // Write metadata + for (map::const_iterator i = nm->metadata().begin(); + i != nm->metadata().end(); ++i) { + // Dirty hack, don't save metadata that would be in patch file + if ((*i).first != "polyphony" && (*i).first != "filename" + && (*i).first != "author" && (*i).first != "description") + xml_child_node = xmlNewChild(xml_node, NULL, + (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); + } + + if (recursive) + save_patch(spm, spm->filename(), true); + + } else { // Normal node + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"node", NULL); + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)nm->name().c_str()); + + if (nm->plugin() == NULL) break; + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphonic", + (xmlChar*)((nm->polyphonic()) ? "true" : "false")); + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"type", + (xmlChar*)nm->plugin()->type_string()); + /* + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-label", + (xmlChar*)(nm->plugin()->plug_label().c_str())); + + if (nm->plugin()->type() != PluginModel::Internal) { + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"library-name", + (xmlChar*)(nm->plugin()->lib_name().c_str())); + }*/ + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-uri", + (xmlChar*)(nm->plugin()->uri().c_str())); + + // Write metadata + for (map::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) { + // DSSI _hack_ (FIXME: fix OSC to be more like this and not smash DSSI into metadata?) + if ((*i).first.substr(0, 16) == "dssi-configure--") { + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-configure", NULL); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, + (xmlChar*)"key", (xmlChar*)(*i).first.substr(16).c_str()); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, + (xmlChar*)"value", (xmlChar*)(*i).second.c_str()); + } else if ((*i).first == "dssi-program") { + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-program", NULL); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, + (xmlChar*)"bank", (xmlChar*)(*i).second.substr(0, (*i).second.find("/")).c_str()); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, + (xmlChar*)"program", (xmlChar*)(*i).second.substr((*i).second.find("/")+1).c_str()); + } else { + xml_child_node = xmlNewChild(xml_node, NULL, + (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); + } + } + + PortModel* pm = NULL; + // Write port metadata, if necessary + for (list::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) { + pm = (*i); + if (pm->is_input() && pm->user_min() != pm->min_val() || pm->user_max() != pm->max_val()) { + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port", NULL); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"name", + (xmlChar*)pm->path().name().c_str()); + snprintf(temp_buf, temp_buf_length, "%f", pm->user_min()); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-min", (xmlChar*)temp_buf); + snprintf(temp_buf, temp_buf_length, "%f", pm->user_max()); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-max", (xmlChar*)temp_buf); + } + } + } + } + + // Save connections + + const list& cl = patch_model->connections(); + const ConnectionModel* c = NULL; + + for (list::const_iterator i = cl.begin(); i != cl.end(); ++i) { + c = (*i); + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"connection", NULL); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-node", + (xmlChar*)c->src_port_path().parent().name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-port", + (xmlChar*)c->src_port_path().name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-node", + (xmlChar*)c->dst_port_path().parent().name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-port", + (xmlChar*)c->dst_port_path().name().c_str()); + } + + // Save control values (ie presets eventually, right now just current control vals) + + xmlNodePtr xml_preset_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"preset", NULL); + xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"name", (xmlChar*)"default"); + + PortModel* pm = NULL; + + // Save node port controls + for (NodeModelMap::const_iterator n = patch_model->nodes().begin(); n != patch_model->nodes().end(); ++n) { + nm = n->second; + for (PortModelList::const_iterator p = nm->ports().begin(); p != nm->ports().end(); ++p) { + pm = *p; + if (pm->is_input() && pm->is_control()) { + float val = pm->value(); + xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"node-name", + (xmlChar*)nm->name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", + (xmlChar*)pm->path().name().c_str()); + snprintf(temp_buf, temp_buf_length, "%f", val); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", + (xmlChar*)temp_buf); + } + } + } + + // Save patch port controls + for (PortModelList::const_iterator p = patch_model->ports().begin(); + p != patch_model->ports().end(); ++p) { + pm = *p; + if (pm->is_input() && pm->is_control()) { + float val = pm->value(); + xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", + (xmlChar*)pm->path().name().c_str()); + snprintf(temp_buf, temp_buf_length, "%f", val); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", + (xmlChar*)temp_buf); + } + } + + xmlSaveFormatFile(filename.c_str(), xml_doc, 1); // 1 == pretty print + + xmlFreeDoc(xml_doc); + xmlCleanupParser(); +} + + +/** Load a patch in to the engine (and client) from a patch file. + * + * The name and poly from the passed PatchModel are used. If the name is + * the empty string, the name will be loaded from the file. If the poly + * is 0, it will be loaded from file. Otherwise the given values will + * be used. + * + * If @a wait is set, the patch will be checked for existence before + * loading everything in to it (to prevent messing up existing patches + * that exist at the path this one should load as). + * + * If the @a existing parameter is true, the patch will be loaded into a + * currently existing patch (ie a merging will take place). Errors will + * result if Nodes of conflicting names exist. + * + * Returns the path of the newly created patch. + */ +string +PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) +{ + string filename = pm->filename(); + + string additional_path = (pm->parent() == NULL) + ? "" : ((PatchModel*)pm->parent())->filename(); + additional_path = additional_path.substr(0, additional_path.find_last_of("/")); + + filename = find_file(pm->filename(), additional_path); + + size_t poly = pm->poly(); + + //cerr << "[PatchLibrarian] Loading patch " << filename << "" << endl; + + const size_t temp_buf_length = 255; + char temp_buf[temp_buf_length]; + + bool load_name = (pm->path() == ""); + bool load_poly = (poly == 0); + + xmlDocPtr doc = xmlParseFile(filename.c_str()); + + if (doc == NULL ) { + cerr << "Unable to parse patch file." << endl; + return ""; + } + + xmlNodePtr cur = xmlDocGetRootElement(doc); + + if (cur == NULL) { + cerr << "Empty document." << endl; + xmlFreeDoc(doc); + return ""; + } + + if (xmlStrcmp(cur->name, (const xmlChar*) "patch")) { + cerr << "File is not an Om patch file, root node != patch" << endl; + xmlFreeDoc(doc); + return ""; + } + + xmlChar* key = NULL; + cur = cur->xmlChildrenNode; + string path; + + pm->filename(filename); + + // Load Patch attributes + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { + if (load_name) { + assert(key != NULL); + if (pm->parent() != NULL) { + path = pm->parent()->base_path() + string((char*)key); + } else { + path = string("/") + string((char*)key); + } + assert(path.find("//") == string::npos); + assert(path.length() > 0); + pm->set_path(path); + } + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { + if (load_poly) { + poly = atoi((char*)key); + pm->poly(poly); + } + } else if (xmlStrcmp(cur->name, (const xmlChar*)"connection") + && xmlStrcmp(cur->name, (const xmlChar*)"node") + && xmlStrcmp(cur->name, (const xmlChar*)"subpatch") + && xmlStrcmp(cur->name, (const xmlChar*)"filename") + && xmlStrcmp(cur->name, (const xmlChar*)"preset")) { + // Don't know what this tag is, add it as metadata without overwriting + // (so caller can set arbitrary parameters which will be preserved) + if (key != NULL) + if (pm->get_metadata((const char*)cur->name) == "") + pm->set_metadata((const char*)cur->name, (const char*)key); + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + cur = cur->next; + } + + if (poly == 0) poly = 1; + + if (!existing) { + // Wait until the patch is created or the node creations may fail + if (wait) { + //int id = m_osc_model_engine_interface->get_next_request_id(); + //m_osc_model_engine_interface->set_wait_response_id(id); + m_osc_model_engine_interface->create_patch_from_model(pm); + //bool succeeded = m_osc_model_engine_interface->wait_for_response(); + + // If creating the patch failed, bail out so we don't load all these nodes + // into an already existing patch + /*if (!succeeded) { + cerr << "[PatchLibrarian] Patch load failed (patch already exists)" << endl; + return ""; + }*/ // FIXME + } else { + m_osc_model_engine_interface->create_patch_from_model(pm); + } + } + + + // Set the filename metadata. (FIXME) + // This isn't so good, considering multiple clients on multiple machines, and + // absolute filesystem paths obviously aren't going to be correct. But for now + // this is all I can figure out to have Save/Save As work properly for subpatches + m_osc_model_engine_interface->set_metadata(pm->path(), "filename", pm->filename()); + + // Load nodes + NodeModel* nm = NULL; + cur = xmlDocGetRootElement(doc)->xmlChildrenNode; + + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar*)"node"))) { + nm = parse_node(pm, doc, cur); + if (nm != NULL) { + m_osc_model_engine_interface->create_node_from_model(nm); + m_osc_model_engine_interface->set_all_metadata(nm); + for (list::const_iterator j = nm->ports().begin(); + j != nm->ports().end(); ++j) { + // FIXME: ew + snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min()); + m_osc_model_engine_interface->set_metadata((*j)->path(), "user-min", temp_buf); + snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max()); + m_osc_model_engine_interface->set_metadata((*j)->path(), "user-max", temp_buf); + } + nm = NULL; + usleep(10000); + } + } + cur = cur->next; + } + + // Load subpatches + cur = xmlDocGetRootElement(doc)->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) { + load_subpatch(pm, doc, cur); + } + cur = cur->next; + } + + // Load connections + ConnectionModel* cm = NULL; + cur = xmlDocGetRootElement(doc)->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) { + cm = parse_connection(pm, doc, cur); + if (cm != NULL) { + m_osc_model_engine_interface->connect(cm->src_port_path(), cm->dst_port_path()); + usleep(1000); + } + } + cur = cur->next; + } + + + // Load presets (control values) + PresetModel* preset_model = NULL; + cur = xmlDocGetRootElement(doc)->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) { + preset_model = parse_preset(pm, doc, cur); + assert(preset_model != NULL); + if (preset_model->name() == "default") + m_osc_model_engine_interface->set_preset(pm->path(), preset_model); + } + cur = cur->next; + } + + xmlFreeDoc(doc); + xmlCleanupParser(); + + m_osc_model_engine_interface->set_all_metadata(pm); + + if (!existing) + m_osc_model_engine_interface->enable_patch(pm->path()); + + string ret = pm->path(); + return ret; +} + + +/** Build a NodeModel given a pointer to a Node in a patch file. + */ +NodeModel* +PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) +{ + NodeModel* nm = new NodeModel("/UNINITIALIZED"); // FIXME: ew + PluginModel* plugin = new PluginModel(); + + xmlChar* key; + xmlNodePtr cur = node->xmlChildrenNode; + + bool found_name = false; + + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { + nm->set_path(parent->base_path() + (char*)key); + found_name = true; + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) { + nm->polyphonic(!strcmp((char*)key, "true")); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) { + plugin->set_type((const char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"library-name"))) { + plugin->lib_name((char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-label"))) { + plugin->plug_label((char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-uri"))) { + plugin->uri((char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"port"))) { + xmlNodePtr child = cur->xmlChildrenNode; + + string path; + float user_min = 0.0; + float user_max = 0.0; + + while (child != NULL) { + key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + + if ((!xmlStrcmp(child->name, (const xmlChar*)"name"))) { + path = nm->base_path() + (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-min"))) { + user_min = atof((char*)key); + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-max"))) { + user_max = atof((char*)key); + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + child = child->next; + } + + // FIXME: nasty assumptions + PortModel* pm = new PortModel(path, + PortModel::CONTROL, PortModel::INPUT, PortModel::NONE, + 0.0, user_min, user_max); + nm->add_port(pm); + + // DSSI hacks. Stored in the patch files as special elements, but sent to + // the engine as normal metadata with specially formatted key/values. Not + // sure if this is the best way to go about this, but it's the least damaging + // right now + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-program"))) { + xmlNodePtr child = cur->xmlChildrenNode; + + string bank; + string program; + + while (child != NULL) { + key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + + if ((!xmlStrcmp(child->name, (const xmlChar*)"bank"))) { + bank = (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"program"))) { + program = (char*)key; + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + child = child->next; + } + nm->set_metadata("dssi-program", bank +"/"+ program); + + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-configure"))) { + xmlNodePtr child = cur->xmlChildrenNode; + + string dssi_key; + string dssi_value; + + while (child != NULL) { + key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + + if ((!xmlStrcmp(child->name, (const xmlChar*)"key"))) { + dssi_key = (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { + dssi_value = (char*)key; + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + child = child->next; + } + nm->set_metadata(string("dssi-configure--").append(dssi_key), dssi_value); + + } else { // Don't know what this tag is, add it as metadata + if (key != NULL) + nm->set_metadata((const char*)cur->name, (const char*)key); + } + xmlFree(key); + key = NULL; + + cur = cur->next; + } + + if (nm->path() == "") { + cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl; + cerr << "[PatchLibrarian] Node ignored." << endl; + delete nm; + return NULL; + } else { + nm->plugin(plugin); + return nm; + } +} + + +void +PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr subpatch) +{ + xmlChar *key; + xmlNodePtr cur = subpatch->xmlChildrenNode; + + PatchModel* pm = new PatchModel("/UNINITIALIZED", 1); // FIXME: ew + + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { + if (parent == NULL) + pm->set_path(string("/") + (const char*)key); + else + pm->set_path(parent->base_path() + (const char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { + pm->poly(atoi((const char*)key)); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"filename"))) { + pm->filename((const char*)key); + } else { // Don't know what this tag is, add it as metadata + if (key != NULL && strlen((const char*)key) > 0) + pm->set_metadata((const char*)cur->name, (const char*)key); + } + xmlFree(key); + key = NULL; + + cur = cur->next; + } + + // This needs to be done after setting the path above, to prevent + // NodeModel::set_path from calling it's parent's rename_node with + // an invalid (nonexistant) name + pm->set_parent(parent); + + load_patch(pm, false); +} + + +/** Build a ConnectionModel given a pointer to a connection in a patch file. + */ +ConnectionModel* +PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) +{ + //cerr << "[PatchLibrarian] Parsing connection..." << endl; + + xmlChar *key; + xmlNodePtr cur = node->xmlChildrenNode; + + string source_node, source_port, dest_node, dest_port; + + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-node"))) { + source_node = (char*)key; + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-port"))) { + source_port = (char*)key; + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-node"))) { + dest_node = (char*)key; + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-port"))) { + dest_port = (char*)key; + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + cur = cur->next; + } + + if (source_node == "" || source_port == "" || dest_node == "" || dest_port == "") { + cerr << "[PatchLibrarian] Malformed patch file (connection tag has empty children)" << endl; + cerr << "[PatchLibrarian] Connection ignored." << endl; + return NULL; + } + + // FIXME: temporary compatibility, remove any slashes from port names + // remove this soon once patches have migrated + string::size_type slash_index; + while ((slash_index = source_port.find("/")) != string::npos) + source_port[slash_index] = '-'; + + while ((slash_index = dest_port.find("/")) != string::npos) + dest_port[slash_index] = '-'; + + ConnectionModel* cm = new ConnectionModel(parent->base_path() + source_node +"/"+ source_port, + parent->base_path() + dest_node +"/"+ dest_port); + + return cm; +} + + +/** Build a PresetModel given a pointer to a preset in a patch file. + */ +PresetModel* +PatchLibrarian::parse_preset(const PatchModel* patch, xmlDocPtr doc, const xmlNodePtr node) +{ + xmlNodePtr cur = node->xmlChildrenNode; + xmlChar* key; + + PresetModel* pm = new PresetModel(patch->base_path()); + + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { + assert(key != NULL); + pm->name((char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"control"))) { + xmlNodePtr child = cur->xmlChildrenNode; + + string node_name = "", port_name = ""; + float val = 0.0; + + while (child != NULL) { + key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + + if ((!xmlStrcmp(child->name, (const xmlChar*)"node-name"))) { + node_name = (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"port-name"))) { + port_name = (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { + val = atof((char*)key); + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + child = child->next; + } + + if (port_name == "") { + string msg = "Unable to parse control in patch file ( node = "; + msg.append(node_name).append(", port = ").append(port_name).append(")"); + cerr << "ERROR: " << msg << endl; + //m_client_hooks->error(msg); + } else { + // FIXME: temporary compatibility, remove any slashes from port name + // remove this soon once patches have migrated + string::size_type slash_index; + while ((slash_index = port_name.find("/")) != string::npos) + port_name[slash_index] = '-'; + pm->add_control(node_name, port_name, val); + } + } + xmlFree(key); + key = NULL; + cur = cur->next; + } + if (pm->name() == "") { + cerr << "Preset in patch file has no name." << endl; + //m_client_hooks->error("Preset in patch file has no name."); + pm->name("Unnamed"); + } + + return pm; +} + +} // namespace LibOmClient diff --git a/src/libs/client/PatchLibrarian.cpp.new b/src/libs/client/PatchLibrarian.cpp.new new file mode 100644 index 00000000..dc05c9e3 --- /dev/null +++ b/src/libs/client/PatchLibrarian.cpp.new @@ -0,0 +1,830 @@ +/* This file is part of Om. 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 "PatchLibrarian.h" +#include +#include +#include +#include "PatchModel.h" +#include "NodeModel.h" +#include "ConnectionModel.h" +#include "PortModel.h" +#include "PresetModel.h" +#include "OSCController.h" +#include "PluginModel.h" +#include "Path.h" +#include +#include +#include +#include // for pair, make_pair +#include +#include +#include +#include // for usleep +#include // for atof +#include + +using std::string; using std::vector; using std::pair; +using std::cerr; using std::cout; using std::endl; + +namespace LibOmClient { + + +/** Searches for the filename passed in the path, returning the full + * path of the file, or the empty string if not found. + * + * This function tries to be as friendly a black box as possible - if the path + * passed is an absolute path and the file is found there, it will return + * that path, etc. + * + * additional_path is a list (colon delimeted as usual) of additional + * directories to look in. ie the directory the parent patch resides in would + * be a good idea to pass as additional_path, in the case of a subpatch. + */ +string +PatchLibrarian::find_file(const string& filename, const string& additional_path) +{ + string search_path = additional_path + ":" + m_patch_path; + + // Try to open the raw filename first + std::ifstream is(filename.c_str(), std::ios::in); + if (is.good()) { + is.close(); + return filename; + } + + string directory; + string full_patch_path = ""; + + while (search_path != "") { + directory = search_path.substr(0, search_path.find(':')); + if (search_path.find(':') != string::npos) + search_path = search_path.substr(search_path.find(':')+1); + else + search_path = ""; + + full_patch_path = directory +"/"+ filename; + + std::ifstream is; + is.open(full_patch_path.c_str(), std::ios::in); + + if (is.good()) { + is.close(); + return full_patch_path; + } else { + cerr << "[PatchLibrarian] Could not find patch file " << full_patch_path << endl; + } + } + + return ""; +} + + +/** Save a patch from a PatchModel to a filename. + * + * The filename passed is the true filename the patch will be saved to (with no prefixing or anything + * like that), and the patch_model's filename member will be set accordingly. + * + * This will break if: + * - The filename does not have an extension (ie contain a ".") + * - The patch_model has no (Om) path + */ +void +PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool recursive) +{ + assert(filename != ""); + assert(patch_model->path() != ""); + + cout << "Saving patch " << patch_model->path() << " to " << filename << endl; + + patch_model->filename(filename); + + string dir = filename.substr(0, filename.find_last_of("/")); + + NodeModel* nm = NULL; + PatchModel* spm = NULL; // subpatch model + + xmlDocPtr xml_doc = NULL; + xmlNodePtr xml_root_node = NULL; + xmlNodePtr xml_node = NULL; + xmlNodePtr xml_child_node = NULL; + xmlNodePtr xml_grandchild_node = NULL; + + xml_doc = xmlNewDoc((xmlChar*)"1.0"); + xml_root_node = xmlNewNode(NULL, (xmlChar*)"patch"); + xmlDocSetRootElement(xml_doc, xml_root_node); + + const size_t temp_buf_length = 255; + char temp_buf[temp_buf_length]; + + string patch_name; + if (patch_model->path() != "/") { + patch_name = patch_model->name(); + } else { + patch_name = filename; + if (patch_name.find("/") != string::npos) + patch_name = patch_name.substr(patch_name.find_last_of("/") + 1); + if (patch_name.find(".") != string::npos) + patch_name = patch_name.substr(0, patch_name.find_last_of(".")); + } + + assert(patch_name.length() > 0); + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"name", + (xmlChar*)patch_name.c_str()); + + snprintf(temp_buf, temp_buf_length, "%zd", patch_model->poly()); + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); + + // Write metadata + for (map::const_iterator i = patch_model->metadata().begin(); + i != patch_model->metadata().end(); ++i) { + // Dirty hack, don't save coordinates in patch file + if ((*i).first != "module-x" && (*i).first != "module-y" + && (*i).first != "filename") + xml_node = xmlNewChild(xml_root_node, NULL, + (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); + assert((*i).first != "connection"); + assert((*i).first != "node"); + assert((*i).first != "subpatch"); + assert((*i).first != "name"); + assert((*i).first != "polyphony"); + assert((*i).first != "preset"); + } + + // Save nodes and subpatches + for (NodeModelMap::const_iterator i = patch_model->nodes().begin(); i != patch_model->nodes().end(); ++i) { + nm = i->second; + + if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch + spm = (PatchModel*)i->second; + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL); + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->name().c_str()); + + string ref_filename; + // No path + if (spm->filename() == "") { + ref_filename = spm->name() + ".om"; + spm->filename(dir +"/"+ ref_filename); + // Absolute path + } else if (spm->filename().substr(0, 1) == "/") { + // Attempt to make it a relative path, if it's undernath this patch's dir + if (dir.substr(0, 1) == "/" && spm->filename().substr(0, dir.length()) == dir) { + ref_filename = spm->filename().substr(dir.length()+1); + } else { // FIXME: not good + ref_filename = spm->filename().substr(spm->filename().find_last_of("/")+1); + spm->filename(dir +"/"+ ref_filename); + } + } else { + ref_filename = spm->filename(); + } + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"filename", (xmlChar*)ref_filename.c_str()); + + snprintf(temp_buf, temp_buf_length, "%zd", spm->poly()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf); + + // Write metadata + for (map::const_iterator i = nm->metadata().begin(); + i != nm->metadata().end(); ++i) { + // Dirty hack, don't save metadata that would be in patch file + if ((*i).first != "polyphony" && (*i).first != "filename" + && (*i).first != "author" && (*i).first != "description") + xml_child_node = xmlNewChild(xml_node, NULL, + (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); + } + + if (recursive) + save_patch(spm, spm->filename(), true); + + } else { // Normal node + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"node", NULL); + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)nm->name().c_str()); + + if (nm->plugin() == NULL) break; + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphonic", + (xmlChar*)((nm->polyphonic()) ? "true" : "false")); + + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"type", + (xmlChar*)nm->plugin()->type_string()); + /* + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-label", + (xmlChar*)(nm->plugin()->plug_label().c_str())); + + if (nm->plugin()->type() != PluginModel::Internal) { + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"library-name", + (xmlChar*)(nm->plugin()->lib_name().c_str())); + }*/ + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-uri", + (xmlChar*)(nm->plugin()->uri().c_str())); + + // Write metadata + for (map::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) { + // DSSI _hack_ (FIXME: fix OSC to be more like this and not smash DSSI into metadata?) + if ((*i).first.substr(0, 16) == "dssi-configure--") { + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-configure", NULL); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, + (xmlChar*)"key", (xmlChar*)(*i).first.substr(16).c_str()); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, + (xmlChar*)"value", (xmlChar*)(*i).second.c_str()); + } else if ((*i).first == "dssi-program") { + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-program", NULL); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, + (xmlChar*)"bank", (xmlChar*)(*i).second.substr(0, (*i).second.find("/")).c_str()); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, + (xmlChar*)"program", (xmlChar*)(*i).second.substr((*i).second.find("/")+1).c_str()); + } else { + xml_child_node = xmlNewChild(xml_node, NULL, + (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str()); + } + } + + PortModel* pm = NULL; + // Write port metadata, if necessary + for (list::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) { + pm = (*i); + if (pm->is_input() && pm->user_min() != pm->min_val() || pm->user_max() != pm->max_val()) { + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port", NULL); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"name", + (xmlChar*)pm->path().name().c_str()); + snprintf(temp_buf, temp_buf_length, "%f", pm->user_min()); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-min", (xmlChar*)temp_buf); + snprintf(temp_buf, temp_buf_length, "%f", pm->user_max()); + xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-max", (xmlChar*)temp_buf); + } + } + } + } + + // Save connections + + const list& cl = patch_model->connections(); + const ConnectionModel* c = NULL; + + for (list::const_iterator i = cl.begin(); i != cl.end(); ++i) { + c = (*i); + xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"connection", NULL); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-node", + (xmlChar*)c->src_port_path().parent().name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-port", + (xmlChar*)c->src_port_path().name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-node", + (xmlChar*)c->dst_port_path().parent().name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-port", + (xmlChar*)c->dst_port_path().name().c_str()); + } + + // Save control values (ie presets eventually, right now just current control vals) + + xmlNodePtr xml_preset_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"preset", NULL); + xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"name", (xmlChar*)"default"); + + PortModel* pm = NULL; + + // Save node port controls + for (NodeModelMap::const_iterator n = patch_model->nodes().begin(); n != patch_model->nodes().end(); ++n) { + nm = n->second; + for (PortModelList::const_iterator p = nm->ports().begin(); p != nm->ports().end(); ++p) { + pm = *p; + if (pm->is_input() && pm->is_control()) { + float val = pm->value(); + xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"node-name", + (xmlChar*)nm->name().c_str()); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", + (xmlChar*)pm->path().name().c_str()); + snprintf(temp_buf, temp_buf_length, "%f", val); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", + (xmlChar*)temp_buf); + } + } + } + + // Save patch port controls + for (PortModelList::const_iterator p = patch_model->ports().begin(); + p != patch_model->ports().end(); ++p) { + pm = *p; + if (pm->is_input() && pm->is_control()) { + float val = pm->value(); + xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name", + (xmlChar*)pm->path().name().c_str()); + snprintf(temp_buf, temp_buf_length, "%f", val); + xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value", + (xmlChar*)temp_buf); + } + } + + xmlSaveFormatFile(filename.c_str(), xml_doc, 1); // 1 == pretty print + + xmlFreeDoc(xml_doc); + xmlCleanupParser(); +} + + +/** Load a patch in to the engine (and client) from a patch file. + * + * The name and poly from the passed PatchModel are used. If the name is + * the empty string, the name will be loaded from the file. If the poly + * is 0, it will be loaded from file. Otherwise the given values will + * be used. + * + * If @a wait is set, the patch will be checked for existence before + * loading everything in to it (to prevent messing up existing patches + * that exist at the path this one should load as). + * + * If the @a existing parameter is true, the patch will be loaded into a + * currently existing patch (ie a merging will take place). Errors will + * result if Nodes of conflicting names exist. + * + * Returns the path of the newly created patch. + */ +string +PatchLibrarian::load_patch(PatchModel* pm, bool wait, bool existing) +{ + string filename = pm->filename(); + + string additional_path = (pm->parent() == NULL) + ? "" : ((PatchModel*)pm->parent())->filename(); + additional_path = additional_path.substr(0, additional_path.find_last_of("/")); + + filename = find_file(pm->filename(), additional_path); + + size_t poly = pm->poly(); + + //cerr << "[PatchLibrarian] Loading patch " << filename << "" << endl; + + const size_t temp_buf_length = 255; + char temp_buf[temp_buf_length]; + + bool load_name = (pm->path() == ""); + bool load_poly = (poly == 0); + + xmlDocPtr doc = xmlParseFile(filename.c_str()); + + if (doc == NULL ) { + cerr << "Unable to parse patch file." << endl; + return ""; + } + + xmlNodePtr cur = xmlDocGetRootElement(doc); + + if (cur == NULL) { + cerr << "Empty document." << endl; + xmlFreeDoc(doc); + return ""; + } + + if (xmlStrcmp(cur->name, (const xmlChar*) "patch")) { + cerr << "File is not an Om patch file, root node != patch" << endl; + xmlFreeDoc(doc); + return ""; + } + + xmlChar* key = NULL; + cur = cur->xmlChildrenNode; + string path; + + pm->filename(filename); + + // Load Patch attributes + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { + if (load_name) { + assert(key != NULL); + if (pm->parent() != NULL) { + path = pm->parent()->base_path() + string((char*)key); + } else { + path = string("/") + string((char*)key); + } + assert(path.find("//") == string::npos); + assert(path.length() > 0); + pm->set_path(path); + } + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { + if (load_poly) { + poly = atoi((char*)key); + pm->poly(poly); + } + } else if (xmlStrcmp(cur->name, (const xmlChar*)"connection") + && xmlStrcmp(cur->name, (const xmlChar*)"node") + && xmlStrcmp(cur->name, (const xmlChar*)"subpatch") + && xmlStrcmp(cur->name, (const xmlChar*)"preset")) { + // Don't know what this tag is, add it as metadata without overwriting + // (so caller can set arbitrary parameters which will be preserved) + if (key != NULL) + if (pm->get_metadata((const char*)cur->name) == "") + pm->set_metadata((const char*)cur->name, (const char*)key); + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + cur = cur->next; + } + + if (poly == 0) poly = 1; + + if (!existing) { + // Wait until the patch is created or the node creations may fail + if (wait) { + int id = m_osc_controller->get_next_request_id(); + m_osc_controller->set_wait_response_id(id); + m_osc_controller->create_patch(pm, id); + bool succeeded = m_osc_controller->wait_for_response(); + + // If creating the patch failed, bail out so we don't load all these nodes + // into an already existing patch + if (!succeeded) { + cerr << "[PatchLibrarian] Patch load failed (patch already exists)" << endl; + return ""; + } + } else { + m_osc_controller->create_patch(pm); + } + } + + + // Set the filename metadata. (FIXME) + // This isn't so good, considering multiple clients on multiple machines, and + // absolute filesystem paths obviously aren't going to be correct. But for now + // this is all I can figure out to have Save/Save As work properly for subpatches + m_osc_controller->set_metadata(pm->path(), "filename", pm->filename()); + + // Load nodes + NodeModel* nm = NULL; + cur = xmlDocGetRootElement(doc)->xmlChildrenNode; + + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar*)"node"))) { + nm = parse_node(pm, doc, cur); + if (nm != NULL) { + m_osc_controller->add_node(nm); + m_osc_controller->set_all_metadata(nm); + for (list::const_iterator j = nm->ports().begin(); + j != nm->ports().end(); ++j) { + // FIXME: ew + snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min()); + m_osc_controller->set_metadata((*j)->path(), "user-min", temp_buf); + snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max()); + m_osc_controller->set_metadata((*j)->path(), "user-max", temp_buf); + } + nm = NULL; + usleep(10000); + } + } + cur = cur->next; + } + + // Load subpatches + cur = xmlDocGetRootElement(doc)->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) { + load_subpatch(pm, doc, cur); + } + cur = cur->next; + } + + // Load connections + ConnectionModel* cm = NULL; + cur = xmlDocGetRootElement(doc)->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) { + cm = parse_connection(pm, doc, cur); + if (cm != NULL) { + m_osc_controller->connect(cm->src_port_path(), cm->dst_port_path()); + usleep(1000); + } + } + cur = cur->next; + } + + + // Load presets (control values) + PresetModel* preset_model = NULL; + cur = xmlDocGetRootElement(doc)->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) { + preset_model = parse_preset(pm, doc, cur); + assert(preset_model != NULL); + if (preset_model->name() == "default") + m_osc_controller->set_preset(pm->path(), preset_model); + } + cur = cur->next; + } + + xmlFreeDoc(doc); + xmlCleanupParser(); + + m_osc_controller->set_all_metadata(pm); + + if (!existing) + m_osc_controller->enable_patch(pm->path()); + + string ret = pm->path(); + return ret; +} + + +/** Build a NodeModel given a pointer to a Node in a patch file. + */ +NodeModel* +PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) +{ + NodeModel* nm = new NodeModel("/UNINITIALIZED"); // FIXME: ew + PluginModel* plugin = new PluginModel(); + + xmlChar* key; + xmlNodePtr cur = node->xmlChildrenNode; + + bool found_name = false; + + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { + nm->set_path(parent->base_path() + (char*)key); + found_name = true; + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) { + nm->polyphonic(!strcmp((char*)key, "true")); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) { + plugin->set_type((const char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"library-name"))) { + plugin->lib_name((char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-label"))) { + plugin->plug_label((char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-uri"))) { + plugin->uri((char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"port"))) { + xmlNodePtr child = cur->xmlChildrenNode; + + string path; + float user_min = 0.0; + float user_max = 0.0; + + while (child != NULL) { + key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + + if ((!xmlStrcmp(child->name, (const xmlChar*)"name"))) { + path = nm->base_path() + (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-min"))) { + user_min = atof((char*)key); + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-max"))) { + user_max = atof((char*)key); + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + child = child->next; + } + + // FIXME: nasty assumptions + PortModel* pm = new PortModel(path, + PortModel::CONTROL, PortModel::INPUT, PortModel::NONE, + 0.0, user_min, user_max); + nm->add_port(pm); + + // DSSI hacks. Stored in the patch files as special elements, but sent to + // the engine as normal metadata with specially formatted key/values. Not + // sure if this is the best way to go about this, but it's the least damaging + // right now + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-program"))) { + xmlNodePtr child = cur->xmlChildrenNode; + + string bank; + string program; + + while (child != NULL) { + key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + + if ((!xmlStrcmp(child->name, (const xmlChar*)"bank"))) { + bank = (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"program"))) { + program = (char*)key; + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + child = child->next; + } + nm->set_metadata("dssi-program", bank +"/"+ program); + + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-configure"))) { + xmlNodePtr child = cur->xmlChildrenNode; + + string dssi_key; + string dssi_value; + + while (child != NULL) { + key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + + if ((!xmlStrcmp(child->name, (const xmlChar*)"key"))) { + dssi_key = (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { + dssi_value = (char*)key; + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + child = child->next; + } + nm->set_metadata(string("dssi-configure--").append(dssi_key), dssi_value); + + } else { // Don't know what this tag is, add it as metadata + if (key != NULL) + nm->set_metadata((const char*)cur->name, (const char*)key); + } + xmlFree(key); + key = NULL; + + cur = cur->next; + } + + if (nm->path() == "") { + cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl; + cerr << "[PatchLibrarian] Node ignored." << endl; + delete nm; + return NULL; + } else { + nm->plugin(plugin); + return nm; + } +} + + +void +PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr subpatch) +{ + xmlChar *key; + xmlNodePtr cur = subpatch->xmlChildrenNode; + + PatchModel* pm = new PatchModel("", 1); // FIXME: ew + + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { + if (parent == NULL) + pm->set_path(string("/") + (const char*)key); + else + pm->set_path(parent->base_path() + (const char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) { + pm->poly(atoi((const char*)key)); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"filename"))) { + pm->filename((const char*)key); + } else { // Don't know what this tag is, add it as metadata + if (key != NULL && strlen((const char*)key) > 0) + pm->set_metadata((const char*)cur->name, (const char*)key); + } + xmlFree(key); + key = NULL; + + cur = cur->next; + } + + // This needs to be done after setting the path above, to prevent + // NodeModel::set_path from calling it's parent's rename_node with + // an invalid (nonexistant) name + pm->set_parent(parent); + + load_patch(pm, false); +} + + +/** Build a ConnectionModel given a pointer to a connection in a patch file. + */ +ConnectionModel* +PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node) +{ + //cerr << "[PatchLibrarian] Parsing connection..." << endl; + + xmlChar *key; + xmlNodePtr cur = node->xmlChildrenNode; + + string source_node, source_port, dest_node, dest_port; + + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-node"))) { + source_node = (char*)key; + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-port"))) { + source_port = (char*)key; + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-node"))) { + dest_node = (char*)key; + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-port"))) { + dest_port = (char*)key; + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + cur = cur->next; + } + + if (source_node == "" || source_port == "" || dest_node == "" || dest_port == "") { + cerr << "[PatchLibrarian] Malformed patch file (connection tag has empty children)" << endl; + cerr << "[PatchLibrarian] Connection ignored." << endl; + return NULL; + } + + // FIXME: temporary compatibility, remove any slashes from port names + // remove this soon once patches have migrated + string::size_type slash_index; + while ((slash_index = source_port.find("/")) != string::npos) + source_port[slash_index] = '-'; + + while ((slash_index = dest_port.find("/")) != string::npos) + dest_port[slash_index] = '-'; + + ConnectionModel* cm = new ConnectionModel(parent->base_path() + source_node +"/"+ source_port, + parent->base_path() + dest_node +"/"+ dest_port); + + return cm; +} + + +/** Build a PresetModel given a pointer to a preset in a patch file. + */ +PresetModel* +PatchLibrarian::parse_preset(const PatchModel* patch, xmlDocPtr doc, const xmlNodePtr node) +{ + xmlNodePtr cur = node->xmlChildrenNode; + xmlChar* key; + + PresetModel* pm = new PresetModel(patch->base_path()); + + while (cur != NULL) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + + if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) { + assert(key != NULL); + pm->name((char*)key); + } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"control"))) { + xmlNodePtr child = cur->xmlChildrenNode; + + string node_name = "", port_name = ""; + float val = 0.0; + + while (child != NULL) { + key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + + if ((!xmlStrcmp(child->name, (const xmlChar*)"node-name"))) { + node_name = (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"port-name"))) { + port_name = (char*)key; + } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) { + val = atof((char*)key); + } + + xmlFree(key); + key = NULL; // Avoid a (possible?) double free + + child = child->next; + } + + if (port_name == "") { + string msg = "Unable to parse control in patch file ( node = "; + msg.append(node_name).append(", port = ").append(port_name).append(")"); + m_client_hooks->error(msg); + } else { + // FIXME: temporary compatibility, remove any slashes from port name + // remove this soon once patches have migrated + string::size_type slash_index; + while ((slash_index = port_name.find("/")) != string::npos) + port_name[slash_index] = '-'; + pm->add_control(node_name, port_name, val); + } + } + xmlFree(key); + key = NULL; + cur = cur->next; + } + if (pm->name() == "") { + m_client_hooks->error("Preset in patch file has no name."); + pm->name("Unnamed"); + } + + return pm; +} + +} // namespace LibOmClient diff --git a/src/libs/client/PatchLibrarian.h b/src/libs/client/PatchLibrarian.h new file mode 100644 index 00000000..ace91f24 --- /dev/null +++ b/src/libs/client/PatchLibrarian.h @@ -0,0 +1,78 @@ +/* This file is part of Om. 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 PATCHLIBRARIAN_H +#define PATCHLIBRARIAN_H + +#include +#include +#include +//#include "DummyModelClientInterface.h" + +using std::string; + +namespace LibOmClient { + +class PatchModel; +class NodeModel; +class ConnectionModel; +class PresetModel; +class OSCModelEngineInterface; +class ModelClientInterface; + + +/** Handles all patch saving and loading. + * + * \ingroup libomclient + */ +class PatchLibrarian +{ +public: + // FIXME: return booleans and set an errstr that can be checked? + + PatchLibrarian(OSCModelEngineInterface* const osc_model_engine_interface/*,ModelClientInterface* const client_hooks*/) + : m_patch_path("."), m_osc_model_engine_interface(osc_model_engine_interface)//, m_client_hooks(client_hooks) + { + assert(m_osc_model_engine_interface); + //assert(m_client_hooks != NULL); + } + +// PatchLibrarian(OSCModelEngineInterface* osc_model_engine_interface) +// : m_osc_model_engine_interface(osc_model_engine_interface), m_client_hooks(new DummyModelClientInterface()) +// {} + + void path(const string& path) { m_patch_path = path; } + const string& path() { return m_patch_path; } + + string find_file(const string& filename, const string& additional_path = ""); + + void save_patch(PatchModel* patch_model, const string& filename, bool recursive); + string load_patch(PatchModel* pm, bool wait = true, bool existing = false); + +private: + string m_patch_path; + OSCModelEngineInterface* const m_osc_model_engine_interface; + + NodeModel* parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); + ConnectionModel* parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); + PresetModel* parse_preset(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); + void load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur); +}; + + +} // namespace LibOmClient + +#endif // PATCHLIBRARIAN_H diff --git a/src/libs/client/PatchModel.cpp b/src/libs/client/PatchModel.cpp new file mode 100644 index 00000000..829c9ca5 --- /dev/null +++ b/src/libs/client/PatchModel.cpp @@ -0,0 +1,229 @@ +/* This file is part of Om. 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 "PatchModel.h" +#include "NodeModel.h" +#include "ConnectionModel.h" +#include +#include + +using std::cerr; using std::cout; using std::endl; + +namespace LibOmClient { + + +void +PatchModel::set_path(const Path& new_path) +{ + // FIXME: haack + if (new_path == "") { + m_path = ""; + return; + } + + NodeModel::set_path(new_path); + for (NodeModelMap::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) + (*i).second->set_path(m_path +"/"+ (*i).second->name()); + +#ifdef DEBUG + // Be sure connection paths are updated and sane + for (list::iterator j = m_connections.begin(); + j != m_connections.end(); ++j) { + assert((*j)->src_port_path().parent().parent() == new_path); + assert((*j)->src_port_path().parent().parent() == new_path); + } +#endif +} + + +NodeModel* +PatchModel::get_node(const string& name) +{ + assert(name.find("/") == string::npos); + NodeModelMap::iterator i = m_nodes.find(name); + return ((i != m_nodes.end()) ? (*i).second : NULL); +} + + +void +PatchModel::add_node(NodeModel* nm) +{ + assert(nm != NULL); + assert(nm->name().find("/") == string::npos); + assert(nm->parent() == NULL); + + m_nodes[nm->name()] = nm; + nm->set_parent(this); +} + + +void +PatchModel::remove_node(const string& name) +{ + assert(name.find("/") == string::npos); + NodeModelMap::iterator i = m_nodes.find(name); + if (i != m_nodes.end()) { + delete i->second; + m_nodes.erase(i); + return; + } + + cerr << "[PatchModel::remove_node] " << m_path << ": failed to find node " << name << endl; +} + + +void +PatchModel::clear() +{ + for (list::iterator j = m_connections.begin(); j != m_connections.end(); ++j) + delete (*j); + + for (NodeModelMap::iterator i = m_nodes.begin(); i != m_nodes.end(); ++i) { + (*i).second->clear(); + delete (*i).second; + } + + m_nodes.clear(); + m_connections.clear(); + + NodeModel::clear(); + + assert(m_nodes.empty()); + assert(m_connections.empty()); + assert(m_ports.empty()); +} + + +/** Updated the map key of the given node. + * + * The NodeModel must already have it's new path set to @a new_path, or this will + * abort with a fatal error. + */ +void +PatchModel::rename_node(const Path& old_path, const Path& new_path) +{ + assert(old_path.parent() == path()); + assert(new_path.parent() == path()); + + NodeModelMap::iterator i = m_nodes.find(old_path.name()); + NodeModel* nm = NULL; + + if (i != m_nodes.end()) { + nm = (*i).second; + for (list::iterator j = m_connections.begin(); j != m_connections.end(); ++j) { + if ((*j)->src_port_path().parent() == old_path) + (*j)->src_port_path(new_path.base_path() + (*j)->src_port_path().name()); + if ((*j)->dst_port_path().parent() == old_path) + (*j)->dst_port_path(new_path.base_path() + (*j)->dst_port_path().name()); + } + m_nodes.erase(i); + assert(nm->path() == new_path); + m_nodes[new_path.name()] = nm; + return; + } + + cerr << "[PatchModel::rename_node] " << m_path << ": failed to find node " << old_path << endl; +} + + +ConnectionModel* +PatchModel::get_connection(const string& src_port_path, const string& dst_port_path) +{ + for (list::iterator i = m_connections.begin(); i != m_connections.end(); ++i) + if ((*i)->src_port_path() == src_port_path && (*i)->dst_port_path() == dst_port_path) + return (*i); + return NULL; +} + + +/** Add a connection to this patch. + * + * Ownership of @a cm is taken, it will be deleted along with this PatchModel. + * If @a cm only contains paths (not pointers to the actual ports), the ports + * will be found and set. The ports referred to not existing as children of + * this patch is a fatal error. + */ +void +PatchModel::add_connection(ConnectionModel* cm) +{ + assert(cm != NULL); + assert(cm->src_port_path().parent().parent() == m_path); + assert(cm->dst_port_path().parent().parent() == m_path); + assert(cm->patch_path() == path()); + + ConnectionModel* existing = get_connection(cm->src_port_path(), cm->dst_port_path()); + + if (existing != NULL) { + delete cm; + return; + } + + NodeModel* src_node = get_node(cm->src_port_path().parent().name()); + PortModel* src_port = (src_node == NULL) ? NULL : src_node->get_port(cm->src_port_path().name()); + NodeModel* dst_node = get_node(cm->dst_port_path().parent().name()); + PortModel* dst_port = (dst_node == NULL) ? NULL : dst_node->get_port(cm->dst_port_path().name()); + + assert(src_port != NULL); + assert(dst_port != NULL); + + // Find source port pointer to 'resolve' connection if necessary + if (cm->src_port() != NULL) + assert(cm->src_port() == src_port); + else + cm->set_src_port(src_port); + + // Find dest port pointer to 'resolve' connection if necessary + if (cm->dst_port() != NULL) + assert(cm->dst_port() == dst_port); + else + cm->set_dst_port(dst_port); + + assert(cm->src_port() != NULL); + assert(cm->dst_port() != NULL); + + m_connections.push_back(cm); +} + + +void +PatchModel::remove_connection(const string& src_port_path, const string& dst_port_path) +{ + ConnectionModel* cm = NULL; + for (list::iterator i = m_connections.begin(); i != m_connections.end(); ++i) { + cm = (*i); + if (cm->src_port_path() == src_port_path && cm->dst_port_path() == dst_port_path) { + delete cm; + m_connections.erase(i); + assert(get_connection(src_port_path, dst_port_path) == NULL); // no duplicates + return; + } + } + cerr << "[PatchModel::remove_connection] WARNING: Failed to find connection " << + src_port_path << " -> " << dst_port_path << endl; + return; +} + + +bool +PatchModel::polyphonic() const +{ + return (m_parent == NULL) + ? (m_poly > 1) + : (m_poly > 1) && m_poly == parent_patch()->poly() && m_poly > 1; +} + + +} // namespace LibOmClient diff --git a/src/libs/client/PatchModel.h b/src/libs/client/PatchModel.h new file mode 100644 index 00000000..12871933 --- /dev/null +++ b/src/libs/client/PatchModel.h @@ -0,0 +1,88 @@ +/* This file is part of Om. 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 PATCHMODEL_H +#define PATCHMODEL_H + +#include +#include +#include +#include +#include "NodeModel.h" + +using std::list; using std::string; using std::map; + +namespace LibOmClient { + +class ConnectionModel; + + +/** Client's model of a patch. + * + * \ingroup libomclient + */ +class PatchModel : public NodeModel +{ +public: + PatchModel(const string& patch_path, uint poly) + : NodeModel(patch_path), + m_enabled(false), + m_poly(poly) + {} + + const NodeModelMap& nodes() const { return m_nodes; } + const list& connections() const { return m_connections; } + + virtual void set_path(const Path& path); + + NodeModel* get_node(const string& node_name); + void add_node(NodeModel* nm); + void remove_node(const string& name); + + void rename_node(const Path& old_path, const Path& new_path); + void rename_node_port(const Path& old_path, const Path& new_path); + ConnectionModel* get_connection(const string& src_port_path, const string& dst_port_path); + void add_connection(ConnectionModel* cm); + void remove_connection(const string& src_port_path, const string& dst_port_path); + + virtual void clear(); + + size_t poly() const { return m_poly; } + void poly(size_t p) { m_poly = p; } + const string& filename() const { return m_filename; } + void filename(const string& f) { m_filename = f; } + bool enabled() const { return m_enabled; } + void enabled(bool b) { m_enabled = b; } + bool polyphonic() const; + +private: + // Prevent copies (undefined) + PatchModel(const PatchModel& copy); + PatchModel& operator=(const PatchModel& copy); + + NodeModelMap m_nodes; + list m_connections; + string m_filename; + bool m_enabled; + size_t m_poly; +}; + +typedef map PatchModelMap; + + +} // namespace LibOmClient + +#endif // PATCHMODEL_H diff --git a/src/libs/client/PluginModel.h b/src/libs/client/PluginModel.h new file mode 100644 index 00000000..85365d64 --- /dev/null +++ b/src/libs/client/PluginModel.h @@ -0,0 +1,105 @@ +/* This file is part of Om. 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 PLUGINMODEL_H +#define PLUGINMODEL_H + +#include +using std::string; + +namespace LibOmClient { + + +/** Model for a plugin available for loading. + * + * \ingroup libomclient + */ +class PluginModel +{ +public: + enum Type { LV2, LADSPA, DSSI, Internal, Patch }; + + // FIXME: remove + PluginModel() {} + + PluginModel(const string& type_string, const string& uri) + : m_uri(uri) + { set_type(type_string); } + + PluginModel(Type type) + : m_type(type) + {} + + PluginModel(Type type, const string& uri, const string& name) + : m_type(type), + m_uri(uri), + m_name(name) + {} + + PluginModel(Type type, const string& lib_name, const string& plug_label, const string& name) + : m_type(type), + m_lib_name(lib_name), + m_plug_label(plug_label), + m_name(name) + {} + + //PluginModel() {} + + Type type() const { return m_type; } + void type(Type t) { m_type = t; } + const string& uri() const { return m_uri; } + void uri(const string& s) { m_uri = s; } + const string& lib_name() const { return m_lib_name; } + void lib_name(const string& s) { m_lib_name = s; } + const string& plug_label() const { return m_plug_label; } + void plug_label(const string& s) { m_plug_label = s; } + const string& name() const { return m_name; } + void name(const string& s) { m_name = s; } + + const char* const type_string() const { + if (m_type == LV2) return "LV2"; + else if (m_type == LADSPA) return "LADSPA"; + else if (m_type == DSSI) return "DSSI"; + else if (m_type == Internal) return "Internal"; + else if (m_type == Patch) return "Patch"; + else return ""; + } + + void set_type(const string& type_string) { + if (type_string == "LV2") m_type = LV2; + else if (type_string == "LADSPA") m_type = LADSPA; + else if (type_string == "DSSI") m_type = DSSI; + else if (type_string == "Internal") m_type = Internal; + else if (type_string == "Patch") m_type = Patch; + } + +private: + // Prevent copies + PluginModel(const PluginModel& copy); + PluginModel& operator=(const PluginModel& copy); + + Type m_type; + string m_uri; + string m_lib_name; + string m_plug_label; + string m_name; +}; + + +} // namespace Om + +#endif // PLUGINMODEL_H + diff --git a/src/libs/client/PortModel.h b/src/libs/client/PortModel.h new file mode 100644 index 00000000..6d0895cf --- /dev/null +++ b/src/libs/client/PortModel.h @@ -0,0 +1,118 @@ +/* This file is part of Om. 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 PORTMODEL_H +#define PORTMODEL_H + +#include +#include +#include +#include "ObjectModel.h" +using std::string; using std::list; + +namespace LibOmClient { + +/* Model of a port. + * + * \ingroup libomclient. + */ +class PortModel : public ObjectModel +{ +public: + enum Type { CONTROL, AUDIO, MIDI }; + enum Direction { INPUT, OUTPUT }; + enum Hint { NONE, INTEGER, TOGGLE, LOGARITHMIC }; + + PortModel(const string& path, Type type, Direction dir, Hint hint, + float default_val, float min, float max) + : ObjectModel(path), + m_type(type), + m_direction(dir), + m_hint(hint), + m_default_val(default_val), + m_min_val(min), + m_user_min(min), + m_max_val(max), + m_user_max(max), + m_current_val(default_val), + m_connected(false) + { + } + + PortModel(const string& path, Type type, Direction dir) + : ObjectModel(path), + m_type(type), + m_direction(dir), + m_hint(NONE), + m_default_val(0.0f), + m_min_val(0.0f), + m_user_min(0.0f), + m_max_val(0.0f), + m_user_max(0.0f), + m_current_val(0.0f), + m_connected(false) + { + } + + inline float min_val() const { return m_min_val; } + inline float user_min() const { return m_user_min; } + inline void user_min(float f) { m_user_min = f; } + inline float default_val() const { return m_default_val; } + inline void default_val(float f) { m_default_val = f; } + inline float max_val() const { return m_max_val; } + inline float user_max() const { return m_user_max; } + inline void user_max(float f) { m_user_max = f; } + inline float value() const { return m_current_val; } + inline void value(float f) { m_current_val = f; } + inline bool connected() { return m_connected; } + inline void connected(bool b) { m_connected = b; } + inline Type type() { return m_type; } + + inline bool is_input() const { return (m_direction == INPUT); } + inline bool is_output() const { return (m_direction == OUTPUT); } + inline bool is_audio() const { return (m_type == AUDIO); } + inline bool is_control() const { return (m_type == CONTROL); } + inline bool is_midi() const { return (m_type == MIDI); } + inline bool is_logarithmic() const { return (m_hint == LOGARITHMIC); } + inline bool is_integer() const { return (m_hint == INTEGER); } + inline bool is_toggle() const { return (m_hint == TOGGLE); } + + inline bool operator==(const PortModel& pm) + { return (m_path == pm.m_path); } + +private: + // Prevent copies (undefined) + PortModel(const PortModel& copy); + PortModel& operator=(const PortModel& copy); + + Type m_type; + Direction m_direction; + Hint m_hint; + float m_default_val; + float m_min_val; + float m_user_min; + float m_max_val; + float m_user_max; + float m_current_val; + bool m_connected; +}; + +typedef list PortModelList; + + +} // namespace LibOmClient + +#endif // PORTMODEL_H diff --git a/src/libs/client/PresetModel.h b/src/libs/client/PresetModel.h new file mode 100644 index 00000000..bd187dfc --- /dev/null +++ b/src/libs/client/PresetModel.h @@ -0,0 +1,66 @@ +/* This file is part of Om. 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 alongCont + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PRESETMODEL_H +#define PRESETMODEL_H + +#include +#include +#include "ControlModel.h" + +using std::string; using std::list; + +namespace LibOmClient { + + +/** Model of a preset (a collection of control settings). + * + * \ingroup libomclient + */ +class PresetModel +{ +public: + PresetModel(const string& base_path) + : m_base_path(base_path) + {} + + /** Add a control value to this preset. An empty string for a node_name + * means the port is on the patch itself (not a node in the patch). + */ + void add_control(const string& node_name, + const string& port_name, float value) + { + if (node_name != "") + m_controls.push_back(ControlModel(m_base_path + node_name +"/"+ port_name, value)); + else + m_controls.push_back(ControlModel(m_base_path + port_name, value)); + } + + const string& name() { return m_name; } + void name(const string& n) { m_name = n; } + + const list& controls() const { return m_controls; } + +private: + string m_name; + string m_base_path; + list m_controls; +}; + + +} // namespace LibOmClient + +#endif // PRESETMODEL diff --git a/src/libs/client/SigClientInterface.h b/src/libs/client/SigClientInterface.h new file mode 100644 index 00000000..f384f239 --- /dev/null +++ b/src/libs/client/SigClientInterface.h @@ -0,0 +1,120 @@ +/* This file is part of Om. Copyright (C) 2006 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 SIGCLIENTINTERFACE_H +#define SIGCLIENTINTERFACE_H + +#include +#include +#include +#include "interface/ClientInterface.h" +using std::string; + +namespace LibOmClient { + + +/** A LibSigC++ signal emitting interface for clients to use. + * + * sed would have the copyright to this code if it was a legal person. + */ +class SigClientInterface : virtual public Om::Shared::ClientInterface, public sigc::trackable +{ +public: + sigc::signal bundle_begin_sig; + sigc::signal bundle_end_sig; + sigc::signal error_sig; + sigc::signal num_plugins_sig; + sigc::signal new_plugin_sig; + sigc::signal new_patch_sig; + sigc::signal new_node_sig; + sigc::signal new_port_sig; + sigc::signal patch_enabled_sig; + sigc::signal patch_disabled_sig; + sigc::signal patch_cleared_sig; + sigc::signal object_renamed_sig; + sigc::signal object_destroyed_sig; + sigc::signal connection_sig; + sigc::signal disconnection_sig; + sigc::signal metadata_update_sig; + sigc::signal control_change_sig; + sigc::signal program_add_sig; + sigc::signal program_remove_sig; + + inline void emit_bundle_begin() + { bundle_begin_sig.emit(); } + + inline void emit_bundle_end() + { bundle_end_sig.emit(); } + + inline void emit_error(const string& msg) + { error_sig.emit(msg); } + + inline void emit_num_plugins(uint32_t num) + { num_plugins_sig.emit(num); } + + inline void emit_new_plugin(const string& type, const string& uri, const string& name) + { new_plugin_sig.emit(type, uri, name); } + + inline void emit_new_patch(const string& path, uint32_t poly) + { new_patch_sig.emit(path, poly); } + + inline void emit_new_node(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports) + { new_node_sig.emit(plugin_type, plugin_uri, node_path, is_polyphonic, num_ports); } + + inline void emit_new_port(const string& path, const string& data_type, bool is_output) + { new_port_sig.emit(path, data_type, is_output); } + + inline void emit_patch_enabled(const string& path) + { patch_enabled_sig.emit(path); } + + inline void emit_patch_disabled(const string& path) + { patch_disabled_sig.emit(path); } + + inline void emit_patch_cleared(const string& path) + { patch_cleared_sig.emit(path); } + + inline void emit_object_renamed(const string& old_path, const string& new_path) + { object_renamed_sig.emit(old_path, new_path); } + + inline void emit_object_destroyed(const string& path) + { object_destroyed_sig.emit(path); } + + inline void emit_connection(const string& src_port_path, const string& dst_port_path) + { connection_sig.emit(src_port_path, dst_port_path); } + + inline void emit_disconnection(const string& src_port_path, const string& dst_port_path) + { disconnection_sig.emit(src_port_path, dst_port_path); } + + inline void emit_metadata_update(const string& subject_path, const string& predicate, const string& value) + { metadata_update_sig.emit(subject_path, predicate, value); } + + inline void emit_control_change(const string& port_path, float value) + { control_change_sig.emit(port_path, value); } + + inline void emit_program_add(const string& node_path, uint32_t bank, uint32_t program, const string& program_name) + { program_add_sig.emit(node_path, bank, program, program_name); } + + inline void emit_program_remove(const string& node_path, uint32_t bank, uint32_t program) + { program_remove_sig.emit(node_path, bank, program); } + +protected: + SigClientInterface() {} +}; + + +} // namespace LibOmClient + +#endif diff --git a/src/libs/client/ThreadedSigClientInterface.cpp b/src/libs/client/ThreadedSigClientInterface.cpp new file mode 100644 index 00000000..860d91f6 --- /dev/null +++ b/src/libs/client/ThreadedSigClientInterface.cpp @@ -0,0 +1,71 @@ +/* This file is part of Om. Copyright (C) 2006 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 "ThreadedSigClientInterface.h" +#include +using std::cerr; using std::endl; + +namespace LibOmClient { + + +/** Push an event (from the engine, ie 'new patch') on to the queue. + */ +void +ThreadedSigClientInterface::push_sig(Closure ev) +{ + cerr << "-- pushing event\n"; + + bool success = false; + bool first = true; + + // (Very) slow busy-wait if the queue is full + // FIXME: Make this wait on a signal from process_sigs iff this happens + while (!success) { + success = _sigs.push(ev); + if (!success) { + if (first) { + cerr << "[ThreadedSigClientInterface] WARNING: (Client) event queue full. Waiting to try again..." << endl; + first = false; + } + usleep(200000); // 100 milliseconds (2* rate process_sigs is called) + } + } +} + + +/** Process all queued events that came from the OSC thread. + * + * This function should be called from the Gtk thread to emit signals and cause + * the connected methods to execute. + */ +bool +ThreadedSigClientInterface::emit_signals() +{ + // Process a maximum of queue-size events, to prevent locking the GTK + // thread indefinitely while processing continually arriving events + size_t num_processed = 0; + while (!_sigs.is_empty() && num_processed++ < _sigs.capacity()/2) { + cerr << "-- emitting event\n"; + Closure& ev = _sigs.pop(); + ev(); + ev.disconnect(); + } + + return true; +} + + +} // namespace LibOmClient diff --git a/src/libs/client/ThreadedSigClientInterface.h b/src/libs/client/ThreadedSigClientInterface.h new file mode 100644 index 00000000..16259531 --- /dev/null +++ b/src/libs/client/ThreadedSigClientInterface.h @@ -0,0 +1,177 @@ +/* This file is part of Om. Copyright (C) 2006 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 THREADEDSIGCLIENTINTERFACE_H +#define THREADEDSIGCLIENTINTERFACE_H + +#include +#include +#include +#include "interface/ClientInterface.h" +#include "SigClientInterface.h" +#include "util/Queue.h" +using std::string; + +/** Returns nothing and takes no parameters (because they have all been bound) */ +typedef sigc::slot Closure; + +namespace LibOmClient { + + +/** A LibSigC++ signal emitting interface for clients to use. + * + * This emits signals (possibly) in a different thread than the ClientInterface + * functions are called. It must be explicitly driven with the emit_signals() + * function, which fires all enqueued signals up until the present. You can + * use this in a GTK idle callback for receiving thread safe engine signals. + */ +class ThreadedSigClientInterface : virtual public SigClientInterface +{ +public: + ThreadedSigClientInterface(uint32_t queue_size) + : _sigs(queue_size) + , error_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_error)) + //, new_plugin_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_plugin_model)) + //, new_patch_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_patch_model)) + //, new_node_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_node_model)) + //, new_port_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_port_model)) + //, connection_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_connection_model)) + , new_plugin_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_plugin)) + , new_patch_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_patch)) + , new_node_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_node)) + , new_port_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_new_port)) + , connection_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_connection)) + , patch_enabled_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_patch_enabled)) + , patch_disabled_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_patch_disabled)) + , patch_cleared_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_patch_cleared)) + , object_destroyed_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_object_destroyed)) + , object_renamed_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_object_renamed)) + , disconnection_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_disconnection)) + , metadata_update_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_metadata_update)) + , control_change_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_control_change)) + , program_add_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_program_add)) + , program_remove_slot(sigc::mem_fun((SigClientInterface*)this, &SigClientInterface::emit_program_remove)) + {} + + + // FIXME + void bundle_begin() {} + void bundle_end() {} + + void num_plugins(uint32_t num) { _num_plugins = num; } + + void error(const string& msg) + { push_sig(sigc::bind(error_slot, msg)); } + /* + void new_plugin_model(PluginModel* const pm) + { push_sig(sigc::bind(new_plugin_slot, pm)); } + + void new_patch_model(PatchModel* const pm) + { push_sig(sigc::bind(new_patch_slot, pm)); } + + void new_node_model(NodeModel* const nm) + { assert(nm); push_sig(sigc::bind(new_node_slot, nm)); } + + void new_port_model(PortModel* const pm) + { push_sig(sigc::bind(new_port_slot, pm)); } + + void connection_model(ConnectionModel* const cm) + { push_sig(sigc::bind(connection_slot, cm)); } + */ + void new_plugin(const string& type, const string& uri, const string& name) + { push_sig(sigc::bind(new_plugin_slot, type, uri, name)); } + + void new_patch(const string& path, uint32_t poly) + { push_sig(sigc::bind(new_patch_slot, path, poly)); } + + void new_node(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports) + { push_sig(sigc::bind(new_node_slot, plugin_type, plugin_uri, node_path, is_polyphonic, num_ports)); } + + void new_port(const string& path, const string& data_type, bool is_output) + { push_sig(sigc::bind(new_port_slot, path, data_type, is_output)); } + + void connection(const string& src_port_path, const string& dst_port_path) + { push_sig(sigc::bind(connection_slot, src_port_path, dst_port_path)); } + + void object_destroyed(const string& path) + { push_sig(sigc::bind(object_destroyed_slot, path)); } + + void patch_enabled(const string& path) + { push_sig(sigc::bind(patch_enabled_slot, path)); } + + void patch_disabled(const string& path) + { push_sig(sigc::bind(patch_disabled_slot, path)); } + + void patch_cleared(const string& path) + { push_sig(sigc::bind(patch_cleared_slot, path)); } + + void object_renamed(const string& old_path, const string& new_path) + { push_sig(sigc::bind(object_renamed_slot, old_path, new_path)); } + + void disconnection(const string& src_port_path, const string& dst_port_path) + { push_sig(sigc::bind(disconnection_slot, src_port_path, dst_port_path)); } + + void metadata_update(const string& path, const string& key, const string& value) + { push_sig(sigc::bind(metadata_update_slot, path, key, value)); } + + void control_change(const string& port_path, float value) + { push_sig(sigc::bind(control_change_slot, port_path, value)); } + + void program_add(const string& path, uint32_t bank, uint32_t program, const string& name) + { push_sig(sigc::bind(program_add_slot, path, bank, program, name)); } + + void program_remove(const string& path, uint32_t bank, uint32_t program) + { push_sig(sigc::bind(program_remove_slot, path, bank, program)); } + + /** Process all queued events - Called from GTK thread to emit signals. */ + bool emit_signals(); + +private: + void push_sig(Closure ev); + + Queue _sigs; + uint32_t _num_plugins; + + sigc::slot bundle_begin_slot; + sigc::slot bundle_end_slot; + sigc::slot num_plugins_slot; + sigc::slot error_slot; + /*sigc::slot new_plugin_slot; + sigc::slot new_patch_slot; + sigc::slot new_node_slot; + sigc::slot new_port_slot; + sigc::slot connection_slot; */ + sigc::slot new_plugin_slot; + sigc::slot new_patch_slot; + sigc::slot new_node_slot; + sigc::slot new_port_slot; + sigc::slot connection_slot; + sigc::slot patch_enabled_slot; + sigc::slot patch_disabled_slot; + sigc::slot patch_cleared_slot; + sigc::slot object_destroyed_slot; + sigc::slot object_renamed_slot; + sigc::slot disconnection_slot; + sigc::slot metadata_update_slot; + sigc::slot control_change_slot; + sigc::slot program_add_slot; + sigc::slot program_remove_slot; +}; + + +} // namespace LibOmClient + +#endif diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am index ae0b3e53..3b425ba2 100644 --- a/src/libs/engine/Makefile.am +++ b/src/libs/engine/Makefile.am @@ -1,11 +1,13 @@ SUBDIRS = tests DIST_SUBDIRS = events -AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @SLV2_CFLAGS@ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/engine/events -fno-exceptions -fno-rtti +AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @SLV2_CFLAGS@ -I$(top_srcdir)/src/libom_la -I$(top_srcdir)/src/engine/events -fno-exceptions -fno-rtti MAINTAINERCLEANFILES = Makefile.in -common_SOURCES = \ +LTLIBRARIES = libom.la + +libom_la_SOURCES = \ util.h \ tuning.h \ Node.h \ @@ -98,16 +100,13 @@ common_SOURCES = \ AudioDriver.h \ MidiDriver.h \ midi.h \ - ../common/util/Semaphore.h \ - ../common/util/types.h \ - ../common/util/Path.h \ - ../common/util/Queue.h \ - ../common/interface/ClientInterface.h \ - ../common/interface/EngineInterface.h \ - instantiations.cpp - -# Events -common_SOURCES += \ + ../libom_la/util/Semaphore.h \ + ../libom_la/util/types.h \ + ../libom_la/util/Path.h \ + ../libom_la/util/Queue.h \ + ../libom_la/interface/ClientInterface.h \ + ../libom_la/interface/EngineInterface.h \ + instantiations.cpp \ events/RegisterClientEvent.h \ events/RegisterClientEvent.cpp \ events/UnregisterClientEvent.h \ @@ -165,25 +164,25 @@ common_SOURCES += \ events/MidiLearnEvent.cpp if WITH_JACK_MIDI -common_SOURCES += \ +libom_la_SOURCES += \ JackMidiDriver.h \ JackMidiDriver.cpp endif if WITH_ALSA_MIDI -common_SOURCES += \ +libom_la_SOURCES += \ AlsaMidiDriver.h \ AlsaMidiDriver.cpp endif if WITH_LADSPA -common_SOURCES += \ +libom_la_SOURCES += \ LADSPAPlugin.h \ LADSPAPlugin.cpp endif if WITH_DSSI -common_SOURCES += \ +libom_la_SOURCES += \ DSSIPlugin.h \ DSSIPlugin.cpp \ events/DSSIConfigureEvent.cpp \ @@ -197,63 +196,15 @@ common_SOURCES += \ endif if WITH_LV2 -common_SOURCES += \ +libom_la_SOURCES += \ LV2Plugin.h \ LV2Plugin.cpp endif if WITH_LASH -common_SOURCES += \ +libom_la_SOURCES += \ LashDriver.h \ LashDriver.cpp \ LashRestoreDoneEvent.h endif - -# -# Non-installed library to link stand-alone and in-process build against -# - -noinst_LTLIBRARIES = libom.la -libom_la_SOURCES = $(common_SOURCES) - - - -# -# Stand-alone engine -# -if BUILD_ENGINE - -bin_PROGRAMS = om -om_DEPENDENCIES = libom.la -om_LDADD = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -lrt libom.la - -om_SOURCES = \ - main.cpp \ - cmdline.h \ - cmdline.c - -endif # BUILD_ENGINE - - - -# -# Jack internal client -# -if BUILD_IN_PROCESS_ENGINE - - -# FIXME: broken - - -# FIXME: Figure out how to get this properly -omdir = $(prefix)/lib/jack - -om_la_CFLAGS = -fPIC -om_LTLIBRARIES = om.la -om_la_LDFLAGS = -module -avoid-version @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -om_la_SOURCES = OmInProcess.cpp - -endif # BUILD_IN_PROCESS_ENGINE - - diff --git a/src/libs/engine/cmdline.c b/src/libs/engine/cmdline.c deleted file mode 100644 index 6b7ddf6a..00000000 --- a/src/libs/engine/cmdline.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - File autogenerated by gengetopt version 2.10 - generated with the following command: - gengetopt - - The developers of gengetopt consider the fixed text that goes in all - gengetopt output files to be in the public domain: - we make no copyright claims on it. -*/ - - -#include -#include -#include - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "getopt.h" - -#include "cmdline.h" - -void -cmdline_parser_print_version (void) -{ - printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); -} - -void -cmdline_parser_print_help (void) -{ - cmdline_parser_print_version (); - printf("\n" - "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); - printf(" -h --help Print help and exit\n"); - printf(" -V --version Print version and exit\n"); - printf(" -pSTRING --port=STRING OSC port to listen on (default='16180')\n"); - printf(" -i --in-jackd Run engine as in-process JACK client (default=off)\n"); -} - - -static char *gengetopt_strdup (const char *s); - -/* gengetopt_strdup() */ -/* strdup.c replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) -{ - char *result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; -} - -int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) -{ - int c; /* Character of the parsed option. */ - int missing_required_options = 0; - - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->port_given = 0 ; - args_info->in_jackd_given = 0 ; -#define clear_args() { \ - args_info->port_arg = gengetopt_strdup("16180") ;\ - args_info->in_jackd_flag = 0;\ -} - - clear_args(); - - optarg = 0; - optind = 1; - opterr = 1; - optopt = '?'; - - while (1) - { - int option_index = 0; - char *stop_char; - - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "port", 1, NULL, 'p' }, - { "in-jackd", 0, NULL, 'i' }, - { NULL, 0, NULL, 0 } - }; - - stop_char = 0; - c = getopt_long (argc, argv, "hVp:i", long_options, &option_index); - - if (c == -1) break; /* Exit from `while (1)' loop. */ - - switch (c) - { - case 'h': /* Print help and exit. */ - clear_args (); - cmdline_parser_print_help (); - exit (EXIT_SUCCESS); - - case 'V': /* Print version and exit. */ - clear_args (); - cmdline_parser_print_version (); - exit (EXIT_SUCCESS); - - case 'p': /* OSC port to listen on. */ - if (args_info->port_given) - { - fprintf (stderr, "%s: `--port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->port_given = 1; - args_info->port_arg = gengetopt_strdup (optarg); - break; - - case 'i': /* Run engine as in-process JACK client. */ - if (args_info->in_jackd_given) - { - fprintf (stderr, "%s: `--in-jackd' (`-i') option given more than once\n", CMDLINE_PARSER_PACKAGE); - clear_args (); - exit (EXIT_FAILURE); - } - args_info->in_jackd_given = 1; - args_info->in_jackd_flag = !(args_info->in_jackd_flag); - break; - - - case 0: /* Long option with no short option */ - - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - exit (EXIT_FAILURE); - - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); - abort (); - } /* switch */ - } /* while */ - - - if ( missing_required_options ) - exit (EXIT_FAILURE); - - return 0; -} diff --git a/src/libs/engine/cmdline.ggo b/src/libs/engine/cmdline.ggo deleted file mode 100644 index 8c006ca7..00000000 --- a/src/libs/engine/cmdline.ggo +++ /dev/null @@ -1,7 +0,0 @@ -# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) - -package "Om - An OSC controlled realtime modular synthesizer" - -option "port" p "OSC port to listen on" string default="16180" no -option "in-jackd" i "Run engine as in-process JACK client" flag off - diff --git a/src/libs/engine/cmdline.h b/src/libs/engine/cmdline.h deleted file mode 100644 index fe36a969..00000000 --- a/src/libs/engine/cmdline.h +++ /dev/null @@ -1,45 +0,0 @@ -/* cmdline.h */ - -/* File autogenerated by gengetopt version 2.10 */ - -#ifndef CMDLINE_H -#define CMDLINE_H - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef CMDLINE_PARSER_PACKAGE -#define CMDLINE_PARSER_PACKAGE "Om - An OSC controlled realtime modular synthesizer" -#endif - -#ifndef CMDLINE_PARSER_VERSION -#define CMDLINE_PARSER_VERSION VERSION -#endif - -struct gengetopt_args_info -{ - char * port_arg; /* OSC port to listen on (default='16180'). */ - int in_jackd_flag; /* Run engine as in-process JACK client (default=off). */ - - int help_given ; /* Whether help was given. */ - int version_given ; /* Whether version was given. */ - int port_given ; /* Whether port was given. */ - int in_jackd_given ; /* Whether in-jackd was given. */ - -} ; - -int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); - -void cmdline_parser_print_help(void); -void cmdline_parser_print_version(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CMDLINE_H */ diff --git a/src/libs/engine/main.cpp b/src/libs/engine/main.cpp deleted file mode 100644 index a69c7e76..00000000 --- a/src/libs/engine/main.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 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 -#include -#include -#include "config.h" -#include "util.h" -#include "cmdline.h" -#include "Om.h" -#include "OmApp.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif -#ifdef BUILD_IN_PROCESS_ENGINE -#include -#include -#endif - -using std::cout; using std::endl; using std::cerr; - - -void -catch_int(int) -{ - signal(SIGINT, catch_int); - signal(SIGTERM, catch_int); - - std::cout << "[Main] Om interrupted." << std::endl; - Om::om->quit(); -} - - -#ifdef BUILD_IN_PROCESS_ENGINE - -jack_client_t* jack_client; -jack_intclient_t jack_intclient; - - -void -unload_in_process_engine(int) -{ - jack_status_t status; - int ret = EXIT_SUCCESS; - - cout << "Unloading..."; - status = jack_internal_client_unload(jack_client, jack_intclient); - if (status & JackFailure) { - cout << "failed" << endl; - ret = EXIT_FAILURE; - } else { - cout << "done" << endl; - } - jack_client_close(jack_client); - exit(ret); -} - - -int -load_in_process_engine(const char* port) -{ - int ret = EXIT_SUCCESS; - - jack_status_t status; - - if ((jack_client = jack_client_open("om_load", JackNoStartServer, - &status)) != NULL) { - jack_intclient = - jack_internal_client_load(jack_client, "Om", - (jack_options_t)(JackLoadName|JackLoadInit), - &status, "om", port); - if (status == 0) { - cout << "Engine loaded" << endl; - signal(SIGINT, unload_in_process_engine); - signal(SIGTERM, unload_in_process_engine); - - while (1) { - sleep(1); - } - } else if (status & JackFailure) { - cerr << "Could not load om.so" << endl; - ret = EXIT_FAILURE; - } - - jack_client_close(jack_client); - } else { - cerr << "jack_client_open failed" << endl; - ret = EXIT_FAILURE; - } -} - -#endif // BUILD_IN_PROCESS_ENGINE - - -int -main(int argc, char** argv) -{ -#ifdef HAVE_LASH - lash_args_t* lash_args = lash_extract_args(&argc, &argv); -#endif - - int ret = EXIT_SUCCESS; - - /* Parse command line options */ - gengetopt_args_info args_info; - if (cmdline_parser (argc, argv, &args_info) != 0) - return EXIT_FAILURE; - - - if (args_info.in_jackd_flag) { -#ifdef BUILD_IN_PROCESS_ENGINE - ret = load_in_process_engine(args_info.port_arg); -#else - cerr << "In-process Jack client support not enabled in this build." << endl; - ret = EXIT_FAILURE; -#endif // JACK_IN_PROCESS_ENGINE - } else { - signal(SIGINT, catch_int); - signal(SIGTERM, catch_int); - - Om::set_denormal_flags(); - - Om::om = new Om::OmApp(args_info.port_arg); - -#ifdef HAVE_LASH - Om::lash_driver = new Om::LashDriver(Om::om, lash_args); -#endif - - Om::om->main(); - -#ifdef HAVE_LASH - delete Om::lash_driver; -#endif - - delete Om::om; - } - - return ret; -} - diff --git a/src/progs/console/ConsoleClientHooks.cpp b/src/progs/console/ConsoleClientHooks.cpp new file mode 100644 index 00000000..1a911c6a --- /dev/null +++ b/src/progs/console/ConsoleClientHooks.cpp @@ -0,0 +1,33 @@ +/* This file is part of Om. 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 "ConsoleClientHooks.h" + +#include + + +void +ConsoleClientHooks::new_node(NodeModel* nm) +{ + std::cerr << "[ConsoleClient] New node notification" << std::endl; +} + +void +ConsoleClientHooks::error(std::string msg) +{ + std::cerr << "Server returned an error: " << msg << std::endl; +} diff --git a/src/progs/console/ConsoleClientHooks.h b/src/progs/console/ConsoleClientHooks.h new file mode 100644 index 00000000..ceb6cd5a --- /dev/null +++ b/src/progs/console/ConsoleClientHooks.h @@ -0,0 +1,66 @@ +/* This file is part of Om. 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 CONSOLECLIENTHOOKS_H +#define CONSOLECLIENTHOOKS_H + +#include "ClientHooks.h" + +#include +using std::string; + +namespace LibOmClient { + +class PatchModel; +class NodeModel; +class ConnectionModel; +class PortModel; +class MetadataModel; +class PluginModel; + +class ConsoleClientHooks : public ClientHooks +{ +public: + ConsoleClientHooks() + ~ConsoleClientHooks(); + + void error(const string& msg); + void new_node(NodeModel* nm); + + void engine_enabled() {} + void engine_disabled() {} + void new_patch(PatchModel* pm) {} + void new_port(PortModel* port_info) {} + void port_removal(const string& path) {} + void patch_destruction(const string& path) {} + void patch_enabled(const string& path) {} + void patch_disabled(const string& path) {} + void node_removal(const string& path) {} + void object_renamed(const string& old_path, const string& new_path) {} + void connection(ConnectionModel* cm) {} + void disconnection(const string& src_port_path, const string& dst_port_path) {} + void metadata_update(MetadataModel* mm) {} + void control_change(const string& port_path, float value) {} + void new_plugin(PluginModel* pi) {} + void program_add(const string& path, int bank, int program, const string& name) {} + void program_remove(const string& path, int bank, int program) {} +}; + + +} // namespace LibOmClient + + +#endif // CONSOLECLIENTHOOKS_H diff --git a/src/progs/console/Makefile.am b/src/progs/console/Makefile.am new file mode 100644 index 00000000..f46bdbad --- /dev/null +++ b/src/progs/console/Makefile.am @@ -0,0 +1,12 @@ +om_console_client_CXXFLAGS = -I$(top_srcdir)/src/clients -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) +om_console_client_LDADD = ../libomclient.a $(LOSC_LIBS) $(LXML2_LIBS) + +bin_PROGRAMS = console_client +EXTRA_DIST = README + +console_client_CXXFLAGS = "-I../../common" +console_client_LDADD = @LOSC_LIBS@ ../Comm.o +console_client_SOURCES = \ + console_client.cpp \ + ConsoleClientHooks.h \ + ConsoleClientHooks.cpp diff --git a/src/progs/console/README b/src/progs/console/README new file mode 100644 index 00000000..79c629a5 --- /dev/null +++ b/src/progs/console/README @@ -0,0 +1,4 @@ +Everything in and under this directory is very, very, very old. It remains +on the off chance that I actually make it work again - and for history's +sake :) + diff --git a/src/progs/console/console_client.cpp b/src/progs/console/console_client.cpp new file mode 100644 index 00000000..4e5586ce --- /dev/null +++ b/src/progs/console/console_client.cpp @@ -0,0 +1,110 @@ +/* This file is part of Om. 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 +#include +#include +#include +#include "OSCModelEngineInterface.h" +#include "ConsoleClientHooks.h" + + +OSCModelEngineInterface* comm; +ConsoleClientHooks* client_hooks; + +int +main() +{ + std::string input; + std::string s; + std::string path; + std::string types; + lo_message m; + + client_hooks = new ConsoleClientHooks(); + comm = new OSCModelEngineInterface(client_hooks); + comm->attach("1234"); + + while (input != "q") { + std::cout << "> "; + std::getline(std::cin, input); + std::istringstream stream(input); + + if (std::cin.eof()) break; + + if (input == "") continue; + + //std::cout << "INPUT = " << input << std::endl; + + m = lo_message_new(); + stream >> path; + + char cs[256]; + + stream >> types; + + for (uint i=0; stream >> s && i < types.length(); ++i) { + // Take care of quoted strings + if (s[0] == '\"') { + s = s.substr(1); // hack off begin quote + + if (s[s.length()-1] == '\"') { // single quoted word + s = s.substr(0, s.length()-1); + } else { + std::string temp; + do { + stream >> temp; + if (temp.find('\n') != std::string::npos) { + std::cerr << "Mismatched quotes.\n" << std::endl; + break; + } + s += ' '; + s += temp; + } while (temp[temp.length()-1] != '\"'); + s = s.substr(0, s.length() - 1); // hack off end quote + } + } + + switch (types[i]) { + case 'f': + //std::cerr << "float" << std::endl; + lo_message_add_float(m, atof(s.c_str())); + break; + case 's': + strncpy(cs, s.c_str(), 256); + //std::cerr << "string" << std::endl; + lo_message_add_string(m, cs); + break; + case 'i': + //std::cerr << "integer" << std::endl; + lo_message_add_int32(m, atoi(s.c_str())); + break; + default: + std::cerr << "Unknown type \'" << types[i] << "\'" << std::endl; + exit(1); + } + } + + //std::cout << "Sending message..." << std::endl; + //lo_message_pp(m); + //usleep(500); + lo_send_message(comm->addr(), path.c_str(), m); + lo_message_free(m); + //std::cout << "Input = " << input << std::endl; + input = ""; + } + return 0; +} diff --git a/src/progs/console/patches/COPYING b/src/progs/console/patches/COPYING new file mode 100644 index 00000000..e265c4a3 --- /dev/null +++ b/src/progs/console/patches/COPYING @@ -0,0 +1,2 @@ +The files in this directory are temporary and not considered code; thus are +released into the public domain. You may do with them as you please. diff --git a/src/progs/console/patches/dssi_test.omp b/src/progs/console/patches/dssi_test.omp new file mode 100644 index 00000000..0613a57b --- /dev/null +++ b/src/progs/console/patches/dssi_test.omp @@ -0,0 +1,19 @@ +/create_patch si patch1 1 +/patches/patch1/add_output s out_1 +/patches/patch1/add_output s out_2 + +/patches/patch1/add_midi_input + +/patches/patch1/load_dssi_plugin sss trivial_synth.so trivial_synth synth + +/patches/patch1/connect ssss midi_in Frequency synth Frequency +/patches/patch1/connect ssss synth Output output out_1 +/patches/patch1/connect ssss synth Output output out_2 + +/patches/patch1/set_control ssf midi_in Frequency 440 + +/patches/patch1/set_control ssf osc Slope 0.5 + +/patches/patch1/activate +/engine/set_master_patch s patch1 +/engine/start diff --git a/src/progs/console/patches/filter_patch.omp b/src/progs/console/patches/filter_patch.omp new file mode 100644 index 00000000..acaad0c8 --- /dev/null +++ b/src/progs/console/patches/filter_patch.omp @@ -0,0 +1,54 @@ +/create_patch si patch1 1 +/patches/patch1/add_output s out_1 +/patches/patch1/add_output s out_2 + +/patches/patch1/add_midi_input + +/patches/patch1/load_ladspa_plugin isss 1 triangle_1649.so triangle_fcsc_oa osc +/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control aenv +/patches/patch1/load_ladspa_plugin isss 1 amp_1654.so amp_gaia_oa amp +/patches/patch1/load_ladspa_plugin isss 1 lp4pole_1671.so lp4pole_fcrcia_oa filt +/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control fenv +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa fscale +/patches/patch1/load_ladspa_plugin isss 1 sum_1665.so sum_iaic_oa sum + +/patches/patch1/connect ssss midi_in Frequency osc Frequency +/patches/patch1/connect ssss midi_in Gate aenv "Gate" +/patches/patch1/connect ssss midi_in Gate fenv "Gate" +/patches/patch1/connect ssss osc Output filt Input +/patches/patch1/connect ssss fenv "Envelope Out" fscale "First Input" +/patches/patch1/connect ssss fscale "Product Output" sum "First Input" +/patches/patch1/connect ssss midi_in Frequency sum "Second Input" +/patches/patch1/connect ssss sum "Summed Output" filt "Cutoff Frequency" + +/patches/patch1/connect ssss filt Output amp "Input" +/patches/patch1/connect ssss aenv "Envelope Out" amp "Gain (dB)" +/patches/patch1/connect ssss amp "Output" output out_1 +/patches/patch1/connect ssss amp "Output" output out_2 + + +/patches/patch1/set_control ssf midi_in Frequency 200.0 +/patches/patch1/set_control ssf midi_in Gate 0.0 +/patches/patch1/set_control ssf filt Resonance 3.0 +/patches/patch1/set_control ssf osc Slope 0.9 +/patches/patch1/set_control ssf fscale "Second Input" 800 + +/patches/patch1/set_control ssf aenv "Trigger" 0 +/patches/patch1/set_control ssf aenv "Delay Time (s)" 0.0 +/patches/patch1/set_control ssf aenv "Attack Time (s)" 0.01 +/patches/patch1/set_control ssf aenv "Hold Time (s)" 0.0 +/patches/patch1/set_control ssf aenv "Decay Time (s)" 0.3 +/patches/patch1/set_control ssf aenv "Sustain Level" 0.7 +/patches/patch1/set_control ssf aenv "Release Time (s)" 1.5 + +/patches/patch1/set_control ssf fenv "Trigger" 0 +/patches/patch1/set_control ssf fenv "Delay Time (s)" 0.0 +/patches/patch1/set_control ssf fenv "Attack Time (s)" 0.0 +/patches/patch1/set_control ssf fenv "Hold Time (s)" 0.0 +/patches/patch1/set_control ssf fenv "Decay Time (s)" 0.1 +/patches/patch1/set_control ssf fenv "Sustain Level" 0.0 +/patches/patch1/set_control ssf fenv "Release Time (s)" 0.0 + +/patches/patch1/activate +/engine/set_master_patch s patch1 +/engine/start diff --git a/src/progs/console/patches/old_super_simple_patch.omp b/src/progs/console/patches/old_super_simple_patch.omp new file mode 100644 index 00000000..1abd3c23 --- /dev/null +++ b/src/progs/console/patches/old_super_simple_patch.omp @@ -0,0 +1,36 @@ +/create_patch si patch1 4 +/patches/patch1/add_output s out_1 +/patches/patch1/add_output s out_2 + +/patches/patch1/add_midi_input + +/patches/patch1/load_ladspa_plugin isss 1 triangle_1649.so triangle_fcsc_oa osc +/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control aenv +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaia_oa amp +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa endamp + +/patches/patch1/connect ssss midi_in Frequency osc Frequency +/patches/patch1/connect ssss midi_in Gate aenv "Gate" +/patches/patch1/connect ssss osc Output amp "First Input" +/patches/patch1/connect ssss aenv "Envelope Out" amp "Second Input" +/patches/patch1/connect ssss amp "Product Output" endamp "First Input" +/patches/patch1/connect ssss endamp "Product Output" output out_1 +/patches/patch1/connect ssss endamp "Product Output" output out_2 + + +/patches/patch1/set_control ssf midi_in Frequency 200 +/patches/patch1/set_control ssf midi_in Gate 0 +/patches/patch1/set_control ssf osc Slope 0.5 +/patches/patch1/set_control ssf endamp "Second Input" 0.5 + +/patches/patch1/set_control ssf aenv "Trigger" 0 +/patches/patch1/set_control ssf aenv "Delay Time (s)" 0.0 +/patches/patch1/set_control ssf aenv "Attack Time (s)" 0.001 +/patches/patch1/set_control ssf aenv "Hold Time (s)" 0.0 +/patches/patch1/set_control ssf aenv "Decay Time (s)" 0.3 +/patches/patch1/set_control ssf aenv "Sustain Level" 0.5 +/patches/patch1/set_control ssf aenv "Release Time (s)" 0.5 + +/patches/patch1/activate +/engine/set_master_patch s patch1 +/engine/start diff --git a/src/progs/console/patches/send_test.omp b/src/progs/console/patches/send_test.omp new file mode 100644 index 00000000..579a3b80 --- /dev/null +++ b/src/progs/console/patches/send_test.omp @@ -0,0 +1,2 @@ +/load_plugins +/send_plugins diff --git a/src/progs/console/patches/simple_patch.omp b/src/progs/console/patches/simple_patch.omp new file mode 100644 index 00000000..aaa38827 --- /dev/null +++ b/src/progs/console/patches/simple_patch.omp @@ -0,0 +1,54 @@ +/load_plugins +/create_patch si patch1 1 +/patches/patch1/add_output s out_1 +/patches/patch1/add_output s out_2 + +/patches/patch1/add_midi_input + +/patches/patch1/load_ladspa_plugin isss 1 triangle_1649.so triangle_fcsc_oa osc +/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control aenv +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaia_oa amp +/patches/patch1/load_ladspa_plugin isss 1 lp4pole_1671.so lp4pole_fcrcia_oa filt +/patches/patch1/load_ladspa_plugin isss 1 dahdsr_2021.so dahdsr_cg+t_control fenv +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa fscale +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa endamp + +/patches/patch1/connect ssss midi_in Frequency osc Frequency +/patches/patch1/connect ssss midi_in Gate aenv "Gate" +/patches/patch1/connect ssss midi_in Gate fenv "Gate" +/patches/patch1/connect ssss osc Output filt Input +/patches/patch1/connect ssss fenv "Envelope Out" fscale "First Input" +/patches/patch1/connect ssss fscale "Product Output" filt "Cutoff Frequency" +/patches/patch1/connect ssss filt Output amp "First Input" +/patches/patch1/connect ssss aenv "Envelope Out" amp "Second Input" +/patches/patch1/connect ssss amp "Product Output" endamp "First Input" +/patches/patch1/connect ssss endamp "Product Output" output out_1 +/patches/patch1/connect ssss endamp "Product Output" output out_2 + + +/patches/patch1/set_control ssf midi_in Frequency 200.0 +/patches/patch1/set_control ssf midi_in Gate 0.0 +/patches/patch1/set_control ssf filt Resonance 2.0 +/patches/patch1/set_control ssf osc Slope 1.0 +/patches/patch1/set_control ssf fscale "Second Input" 900 +/patches/patch1/set_control ssf endamp "Second Input" 0.5 + +/patches/patch1/set_control ssf aenv "Trigger" 0 +/patches/patch1/set_control ssf aenv "Delay Time (s)" 0.0 +/patches/patch1/set_control ssf aenv "Attack Time (s)" 0.01 +/patches/patch1/set_control ssf aenv "Hold Time (s)" 0.0 +/patches/patch1/set_control ssf aenv "Decay Time (s)" 0.3 +/patches/patch1/set_control ssf aenv "Sustain Level" 0.6 +/patches/patch1/set_control ssf aenv "Release Time (s)" 0.6 + +/patches/patch1/set_control ssf fenv "Trigger" 0 +/patches/patch1/set_control ssf fenv "Delay Time (s)" 0.0 +/patches/patch1/set_control ssf fenv "Attack Time (s)" 0.0 +/patches/patch1/set_control ssf fenv "Hold Time (s)" 0.0 +/patches/patch1/set_control ssf fenv "Decay Time (s)" 0.2 +/patches/patch1/set_control ssf fenv "Sustain Level" 0.5 +/patches/patch1/set_control ssf fenv "Release Time (s)" 0.5 + +/patches/patch1/activate +/engine/set_master_patch s patch1 +/engine/start diff --git a/src/progs/console/patches/super_simple_patch.omp b/src/progs/console/patches/super_simple_patch.omp new file mode 100644 index 00000000..02dc63a2 --- /dev/null +++ b/src/progs/console/patches/super_simple_patch.omp @@ -0,0 +1,36 @@ +/load_plugins + +/create_patch si patch1 1 + +/patches/patch1/load_internal_plugin iss 0 midi_in midi_in +/patches/patch1/load_internal_plugin iss 0 output output + +/patches/patch1/load_ladspa_plugin isss 0 triangle_1649.so triangle_fcsc_oa osc +/patches/patch1/load_ladspa_plugin isss 0 dahdsr_2021.so dahdsr_cg+t_control aenv +/patches/patch1/load_ladspa_plugin isss 0 product_1668.so product_iaia_oa amp +/patches/patch1/load_ladspa_plugin isss 0 product_1668.so product_iaic_oa endamp + +/patches/patch1/connect sisi midi_in 0 osc 0 +/patches/patch1/connect sisi midi_in 1 aenv 0 +/patches/patch1/connect sisi osc 2 amp 0 +/patches/patch1/connect sisi aenv 8 amp 1 +/patches/patch1/connect sisi amp 2 endamp 0 +/patches/patch1/connect sisi endamp 2 output 0 +/patches/patch1/connect sisi endamp 2 output 1 + + +/patches/patch1/set_control sif midi_in 0 200 +/patches/patch1/set_control sif midi_in 1 1.0 +/patches/patch1/set_control sif osc 1 0.5 +/patches/patch1/set_control sif endamp 1 0.5 + +/patches/patch1/set_control sif aenv 1 0 +/patches/patch1/set_control sif aenv 2 0.0 +/patches/patch1/set_control sif aenv 3 0.001 +/patches/patch1/set_control sif aenv 4 0.0 +/patches/patch1/set_control sif aenv 5 0.3 +/patches/patch1/set_control sif aenv 6 0.5 +/patches/patch1/set_control sif aenv 7 0.5 + +/engine/set_master_patch i 0 +/engine/start diff --git a/src/progs/console/patches/test_patch.omp b/src/progs/console/patches/test_patch.omp new file mode 100644 index 00000000..04c0487b --- /dev/null +++ b/src/progs/console/patches/test_patch.omp @@ -0,0 +1,48 @@ +/create_patch si patch1 1 +/patches/patch1/add_output s out_1 +/patches/patch1/add_output s out_2 + +/patches/patch1/add_midi_input + +/patches/patch1/load_ladspa_plugin isss 1 triangle_1649.so triangle_fcsc_oa osc +/patches/patch1/load_ladspa_plugin isss 1 adsr_1653.so adsr aenv +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaia_oa amp +/patches/patch1/load_ladspa_plugin isss 1 lp4pole_1671.so lp4pole_fcrcia_oa filt +/patches/patch1/load_ladspa_plugin isss 1 adsr_1653.so adsr fenv +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa fscale +/patches/patch1/load_ladspa_plugin isss 1 product_1668.so product_iaic_oa endamp + +/patches/patch1/connect ssss midi_in Frequency osc Frequency +/patches/patch1/connect ssss midi_in Gate aenv "Driving Signal" +/patches/patch1/connect ssss midi_in Gate fenv "Driving Signal" +/patches/patch1/connect ssss osc Output filt Input +/patches/patch1/connect ssss fenv "Envelope Out" output out_1 +/patches/patch1/connect ssss fscale "Product Output" filt "Cutoff Frequency" +/patches/patch1/connect ssss filt Output amp "First Input" +/patches/patch1/connect ssss aenv "Envelope Out" output out_2 +/patches/patch1/connect ssss amp "Product Output" endamp "First Input" +/patches/patch1/connect ssss endamp "Product Output" output out_1 +/patches/patch1/connect ssss endamp "Product Output" output out_2 + + +/patches/patch1/set_control ssf midi_in Frequency 200 +/patches/patch1/set_control ssf filt Resonance 3.0 +/patches/patch1/set_control ssf osc Slope 1.0 +/patches/patch1/set_control ssf fscale "Second Input" 900 +/patches/patch1/set_control ssf endamp "Second Input" 0.5 + +/patches/patch1/set_control ssf aenv "Trigger Threshold" 0 +/patches/patch1/set_control ssf aenv "Attack Time (s)" 0.1 +/patches/patch1/set_control ssf aenv "Decay Time (s)" 0.3 +/patches/patch1/set_control ssf aenv "Sustain Level" 0.5 +/patches/patch1/set_control ssf aenv "Release Time (s)" 0.5 + +/patches/patch1/set_control ssf fenv "Trigger Threshold" 0 +/patches/patch1/set_control ssf fenv "Attack Time (s)" 0.1 +/patches/patch1/set_control ssf fenv "Decay Time (s)" 0.2 +/patches/patch1/set_control ssf fenv "Sustain Level" 0.6 +/patches/patch1/set_control ssf fenv "Release Time (s)" 0.4 + +/patches/patch1/activate +/engine/set_master_patch s patch1 +/engine/start diff --git a/src/progs/demolition/DemolitionClientInterface.cpp b/src/progs/demolition/DemolitionClientInterface.cpp new file mode 100644 index 00000000..e58371d4 --- /dev/null +++ b/src/progs/demolition/DemolitionClientInterface.cpp @@ -0,0 +1,109 @@ +/* This file is part of Om. 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 "DemolitionClientInterface.h" +#include "DemolitionModel.h" + + +DemolitionClientInterface::DemolitionClientInterface(DemolitionModel* model) +: m_model(model) +{ +} + + +DemolitionClientInterface::~DemolitionClientInterface() +{ +} + + +void +DemolitionClientInterface::error(const string& msg) +{ +} + + +void +DemolitionClientInterface::new_patch_model(PatchModel* pm) +{ + m_model->add_patch(pm); +} + + +void +DemolitionClientInterface::new_port_model(PortModel* port_model) +{ + m_model->add_port(port_model); +} + + +void +DemolitionClientInterface::object_destroyed(const string& path) +{ + m_model->remove_object(path); +} + +void +DemolitionClientInterface::patch_enabled(const string& path) +{ +} + + +void +DemolitionClientInterface::patch_disabled(const string& path) +{ +} + + +void +DemolitionClientInterface::new_node_model(NodeModel* nm) +{ + m_model->add_node(nm); +} + + +void +DemolitionClientInterface::object_renamed(const string& old_path, const string& new_path) +{ + m_model->object_renamed(old_path, new_path); +} + + +void +DemolitionClientInterface::connection_model(ConnectionModel* cm) +{ + m_model->add_connection(cm); +} + + +void +DemolitionClientInterface::disconnection(const string& src_port_path, const string& dst_port_path) +{ + m_model->remove_connection(src_port_path, dst_port_path); +} + + +void +DemolitionClientInterface::control_change(const string& port_path, float value) +{ +} + + +void +DemolitionClientInterface::new_plugin_model(PluginModel* pi) +{ + m_model->add_plugin(pi); +} + diff --git a/src/progs/demolition/DemolitionClientInterface.h b/src/progs/demolition/DemolitionClientInterface.h new file mode 100644 index 00000000..374008b5 --- /dev/null +++ b/src/progs/demolition/DemolitionClientInterface.h @@ -0,0 +1,75 @@ +/* This file is part of Om. 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 DEMOLITIONCLIENTHOOKS_H +#define DEMOLITIONCLIENTHOOKS_H + +#include +#include +#include "ModelClientInterface.h" +#include "DemolitionModel.h" +#include "PluginModel.h" +using std::string; + +using namespace LibOmClient; + + +/** ModelClientInterface implementation for the Gtk client. + * + * These are the hooks into the GUI for the Comm class. + * + * \ingroup OmGtk + */ +class DemolitionClientInterface : public ModelClientInterface +{ +public: + DemolitionClientInterface(DemolitionModel* model); + virtual ~DemolitionClientInterface(); + + void bundle_begin() {} + void bundle_end() {} + + void num_plugins(size_t num) {} + + // OSC thread functions + void error(const string& msg); + + void new_plugin(const string& type, + const string& uri, + const string& name) {} + void new_patch_model(PatchModel* const pm); + void new_port_model(PortModel* const port_model); + void object_destroyed(const string& path); + void patch_enabled(const string& path); + void patch_disabled(const string& path); + void patch_cleared(const string& path) { throw; } + void new_node_model(NodeModel* const nm); + void object_renamed(const string& old_path, const string& new_path); + void connection_model(ConnectionModel* const cm); + void disconnection(const string& src_port_path, const string& dst_port_path); + void metadata_update(const string& path, const string& key, const string& value) {} + void control_change(const string& port_path, float value); + void new_plugin_model(PluginModel* const pi); + void program_add(const string& path, uint32_t bank, uint32_t program, const string& name) {}; + void program_remove(const string& path, uint32_t bank, uint32_t program) {}; + +private: + DemolitionModel* m_model; +}; + + +#endif // DEMOLITIONCLIENTHOOKS_H diff --git a/src/progs/demolition/DemolitionModel.cpp b/src/progs/demolition/DemolitionModel.cpp new file mode 100644 index 00000000..786c08cd --- /dev/null +++ b/src/progs/demolition/DemolitionModel.cpp @@ -0,0 +1,246 @@ +/* This file is part of Om. 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 "DemolitionModel.h" +#include "util/Path.h" +#include "PluginModel.h" +#include +#include +using std::cout; using std::cerr; using std::endl; + + +DemolitionModel::~DemolitionModel() +{ + for (vector::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) + delete *i; + + for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) + delete *i; +} + + +PatchModel* +DemolitionModel::random_patch() +{ + if (m_patches.size() == 0) + return NULL; + else + return m_patches.at(rand() % m_patches.size()); +} + + +NodeModel* +DemolitionModel::random_node() +{ + int max_attempts = m_patches.size()*4; + int attempts = 0; + + while (attempts++ < max_attempts) { + PatchModel* pm = random_patch(); + + if (pm == NULL) { + return NULL; + } else { + int size = pm->nodes().size(); + if (size == 0) + continue; + int index = rand() % size; + NodeModelMap::const_iterator i = pm->nodes().begin(); + for (int j=0; j < index; ++j) { + ++i; + if (i == pm->nodes().end()) + return NULL; + } + return (*i).second; + } + } + //cout << "***************************** Not returning node *********" << endl; + return NULL; +} + + +NodeModel* +DemolitionModel::random_node_in_patch(PatchModel* pm) +{ + if (pm == NULL) + return NULL; + + int size = pm->nodes().size(); + if (size == 0) + return NULL; + + int index = rand() % size; + NodeModelMap::const_iterator i = pm->nodes().begin(); + for (int j=0; j < index; ++j) { + ++i; + if (i == pm->nodes().end()) + return NULL; + } + return (*i).second; +} + + +PortModel* +DemolitionModel::random_port() +{ + NodeModel* node = random_node(); + + if (node == NULL) return NULL; + + PortModelList ports = node->ports(); + + int num_ports = ports.size(); + int index = rand() % num_ports; + int i = 0; + + for (PortModelList::iterator p = ports.begin(); p != ports.end(); ++p, ++i) + if (i == index) + return (*p); + + return NULL; // shouldn't happen +} + + +PortModel* +DemolitionModel::random_port_in_node(NodeModel* node) +{ + if (node == NULL) + return NULL; + + PortModelList ports = node->ports(); + + int num_ports = ports.size(); + int index = rand() % num_ports; + int i = 0; + + for (PortModelList::iterator p = ports.begin(); p != ports.end(); ++p, ++i) + if (i == index) + return (*p); + + return NULL; // shouldn't happen +} + + +PluginModel* +DemolitionModel::random_plugin() +{ + if (m_plugins.size() == 0) + return NULL; + else + return m_plugins.at(rand() % m_plugins.size()); +} + + +PatchModel* +DemolitionModel::patch(const Path& path) +{ + for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) { + if ((*i)->path() == path) + return (*i); + } + return NULL; +} + + +NodeModel* +DemolitionModel::node(const Path& path) +{ + NodeModel* ret = NULL; + + for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) { + ret = (*i)->get_node(path.name()); + if (ret != NULL) + break; + } + return ret; +} + + +void +DemolitionModel::remove_object(const Path& path) +{ + // Patch + for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) { + if ((*i)->path() == path) { + delete (*i); + m_patches.erase(i); + break; + } + } + + // Node + PatchModel* parent = patch(path.parent()); + if (parent != NULL) + parent->remove_node(path.name()); +} + + +void +DemolitionModel::add_node(NodeModel* nm) +{ + PatchModel* parent = patch(nm->path().parent()); + if (parent == NULL) { + cout << "**** ERROR: Parent for new Node does not exist." << endl; + } else { + parent->add_node(nm); + } +} + + +void +DemolitionModel::add_port(PortModel* pm) +{ +} + + +void +DemolitionModel::add_connection(ConnectionModel* cm) +{ +} + + +void +DemolitionModel::remove_connection(const Path& src_port_path, const Path& dst_port_path) +{ +} + +void +DemolitionModel::object_renamed(const Path& old_path, const Path& new_path) +{ + /* FIXME: broken, does not rename children + assert(OmPath::parent(old_path) == OmPath::parent(new_path)); + + // Rename node + NodeModel* nm = get_node(old_path); + if (nm != NULL) { + if (nm->parent() != NULL) { + nm->parent()->remove_node(OmPath::name(old_path)); + nm->path(new_path); + nm->parent()->add_node(OmPath::name(new_path)); + } + } + + // Rename patch + for (vector::iterator i = m_patches.begin(); i != m_patches.end(); ++i) { + if ((*i)->path() == path) { + delete (*i); + m_patches.erase(i); + return; + } + } + */ +} + diff --git a/src/progs/demolition/DemolitionModel.h b/src/progs/demolition/DemolitionModel.h new file mode 100644 index 00000000..64e0cc61 --- /dev/null +++ b/src/progs/demolition/DemolitionModel.h @@ -0,0 +1,60 @@ +/* This file is part of Om. 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 DEMOLITIONMODEL_H +#define DEMOLITIONMODEL_H + +#include +#include "PatchModel.h" +#include "util/Path.h" +using Om::Path; +using std::vector; + +using namespace LibOmClient; + +class DemolitionModel { +public: + ~DemolitionModel(); + + PatchModel* random_patch(); + NodeModel* random_node(); + NodeModel* random_node_in_patch(PatchModel* patch); + PortModel* random_port(); + PortModel* random_port_in_node(NodeModel* node); + PluginModel* random_plugin(); + + PatchModel* patch(const Path& path); + NodeModel* node(const Path& path); + + void add_patch(PatchModel* pm) { m_patches.push_back(pm); } + void add_node(NodeModel* nm); + void add_port(PortModel* pm); + void remove_object(const Path& path); + void add_connection(ConnectionModel* cm); + void remove_connection(const Path& src_port_path, const Path& dst_port_path); + void add_plugin(PluginModel* pi) { m_plugins.push_back(pi); } + + void object_renamed(const Path& old_path, const Path& new_path); + + int num_patches() { return m_patches.size(); } + +private: + vector m_plugins; + vector m_patches; +}; + + +#endif // DEMOLITIONMODEL_H diff --git a/src/progs/demolition/Makefile.am b/src/progs/demolition/Makefile.am new file mode 100644 index 00000000..4854f045 --- /dev/null +++ b/src/progs/demolition/Makefile.am @@ -0,0 +1,17 @@ +EXTRA_DIST = README + +om_demolition_CXXFLAGS = -I$(top_srcdir)/src/clients -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) +om_demolition_LDADD = ../libomclient.a $(LOSC_LIBS) $(LXML2_LIBS) + +bin_PROGRAMS = om_demolition + +om_demolition_DEPENDENCIES = ../libomclient.a + +om_demolition_SOURCES = \ + DemolitionClientInterface.h \ + DemolitionClientInterface.cpp \ + DemolitionModel.h \ + DemolitionModel.cpp \ + demolition.cpp \ + cmdline.h \ + cmdline.c diff --git a/src/progs/demolition/README b/src/progs/demolition/README new file mode 100644 index 00000000..536d3481 --- /dev/null +++ b/src/progs/demolition/README @@ -0,0 +1,7 @@ +This is a stress tester for the Om engine. + +It constantly sends random events (with a bias towards sane events) to the +engine, to test for potential segfaults (or assertion failures, etc). + +It's not very clever at the moment, and doesn't hit all test cases. Renaming +is also not supported yet. diff --git a/src/progs/demolition/cmdline.c b/src/progs/demolition/cmdline.c new file mode 100644 index 00000000..11fcd108 --- /dev/null +++ b/src/progs/demolition/cmdline.c @@ -0,0 +1,149 @@ +/* + File autogenerated by gengetopt version 2.10 + generated with the following command: + gengetopt + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + + +#include +#include +#include + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#include "cmdline.h" + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); +} + +void +cmdline_parser_print_help (void) +{ + cmdline_parser_print_version (); + printf("\n" + "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); + printf(" -h --help Print help and exit\n"); + printf(" -V --version Print version and exit\n"); + printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n"); + printf(" -pINT --client-port=INT Client port to listen on\n"); +} + + +static char *gengetopt_strdup (const char *s); + +/* gengetopt_strdup() */ +/* strdup.c replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) +{ + int c; /* Character of the parsed option. */ + int missing_required_options = 0; + + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->engine_url_given = 0 ; + args_info->client_port_given = 0 ; +#define clear_args() { \ + args_info->engine_url_arg = NULL; \ +} + + clear_args(); + + optarg = 0; + optind = 1; + opterr = 1; + optopt = '?'; + + while (1) + { + int option_index = 0; + char *stop_char; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "engine-url", 1, NULL, 'u' }, + { "client-port", 1, NULL, 'p' }, + { NULL, 0, NULL, 0 } + }; + + stop_char = 0; + c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index); + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + clear_args (); + cmdline_parser_print_help (); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + clear_args (); + cmdline_parser_print_version (); + exit (EXIT_SUCCESS); + + case 'u': /* Om engine URL to connect to. */ + if (args_info->engine_url_given) + { + fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->engine_url_given = 1; + args_info->engine_url_arg = gengetopt_strdup (optarg); + break; + + case 'p': /* Client port to listen on. */ + if (args_info->client_port_given) + { + fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->client_port_given = 1; + args_info->client_port_arg = strtol (optarg,&stop_char,0); + break; + + + case 0: /* Long option with no short option */ + + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + exit (EXIT_FAILURE); + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); + abort (); + } /* switch */ + } /* while */ + + + if ( missing_required_options ) + exit (EXIT_FAILURE); + + return 0; +} diff --git a/src/progs/demolition/cmdline.ggo b/src/progs/demolition/cmdline.ggo new file mode 100644 index 00000000..8fb68170 --- /dev/null +++ b/src/progs/demolition/cmdline.ggo @@ -0,0 +1,7 @@ +# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) + +package "om_demolition - A stress testing client for Om" + +option "engine-url" u "Om engine URL to connect to" string no +option "client-port" p "Client port to listen on" int no + diff --git a/src/progs/demolition/cmdline.h b/src/progs/demolition/cmdline.h new file mode 100644 index 00000000..be56aafe --- /dev/null +++ b/src/progs/demolition/cmdline.h @@ -0,0 +1,45 @@ +/* cmdline.h */ + +/* File autogenerated by gengetopt version 2.10 */ + +#ifndef CMDLINE_H +#define CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +#define CMDLINE_PARSER_PACKAGE "om_demolotion - A stress testing client for Om" +#endif + +#ifndef CMDLINE_PARSER_VERSION +#define CMDLINE_PARSER_VERSION VERSION +#endif + +struct gengetopt_args_info +{ + char * engine_url_arg; /* Om engine URL to connect to. */ + int client_port_arg; /* Client port to listen on. */ + + int help_given ; /* Whether help was given. */ + int version_given ; /* Whether version was given. */ + int engine_url_given ; /* Whether engine-url was given. */ + int client_port_given ; /* Whether client-port was given. */ + +} ; + +int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); + +void cmdline_parser_print_help(void); +void cmdline_parser_print_version(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/src/progs/demolition/demolition.cpp b/src/progs/demolition/demolition.cpp new file mode 100644 index 00000000..84a08c84 --- /dev/null +++ b/src/progs/demolition/demolition.cpp @@ -0,0 +1,334 @@ +/* This file is part of Om. 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 "OSCModelEngineInterface.h" +#include "OSCModelEngineInterface.h" // FIXME: make conditional +#include "PatchLibrarian.h" +#include "DemolitionClientInterface.h" +#include "interface/ClientInterface.h" +#include "interface/ClientKey.h" +#include "util/CountedPtr.h" +#include +#include +#include +#include "cmdline.h" // generated by gengetopt + +using std::cout; +using std::endl; + +using namespace LibOmClient; + +void do_something(); + +string random_name(); + +void create_patch(); +void destroy(); +void add_node(); +void connect(); +void disconnect(); +void disconnect_all(); +void set_port_value(); +void set_port_value_queued(); +void rename_object(); + + +// Yay globals! +DemolitionModel* model; +OSCModelEngineInterface* engine; + + +int +main(int argc, char** argv) +{ + const char* engine_url = NULL; + int client_port = 0; + + /* Parse command line options */ + gengetopt_args_info args_info; + if (cmdline_parser (argc, argv, &args_info) != 0) + return 1; + + if (args_info.engine_url_given) { + engine_url = args_info.engine_url_arg; + } else { + cout << "[Main] No engine URL specified. Attempting to use osc.udp://localhost:16180" << endl; + engine_url = "osc.udp://localhost:16180"; + } + + if (args_info.client_port_given) + client_port = args_info.client_port_arg; + else + client_port = 0; // will choose a free port automatically + + model = new DemolitionModel(); + + // Create this first so engine interface (liblo) uses the port + CountedPtr client + = CountedPtr(new DemolitionClientInterface(model)); + + engine = new OSCModelEngineInterface(engine_url); + engine->activate(); + + /* Connect to engine */ + //engine->attach(engine_url); + engine->register_client(ClientKey(), (CountedPtr)client); + + engine->load_plugins(); + engine->request_plugins(); + + //int id = engine->get_next_request_id(); + engine->request_all_objects(/*id*/); + //engine->set_wait_response_id(id); + //engine->wait_for_response(); + + // Disable DSP for stress testing + engine->disable_patch("/"); + + while (true) { + do_something(); + usleep(100000); + } + + sleep(2); + engine->unregister_client(ClientKey()); + //engine->detach(); + + delete engine; + delete model; + + return 0; +} + +/** Does some random action + */ +void +do_something() +{ + int action = rand() % 10; + + switch(action) { + case 0: + create_patch(); break; + case 1: + destroy(); break; + case 2: + add_node(); break; + case 3: + connect(); break; + case 4: + disconnect(); break; + case 5: + disconnect_all(); break; + case 6: + set_port_value(); break; + case 7: + set_port_value_queued(); break; + case 8: + rename_object(); break; + default: + break; + } +} + + +string +random_name() +{ + int length = (rand()%10)+1; + string name(length, '-'); + + for (int i=0; i < length; ++i) + name[i] = 'a' + rand()%26; + + return name; +} + + +void +create_patch() +{ + // Make the probability of this happening inversely proportionate to the number + // of patches to keep the # in a sane range + //if (model->num_patches() > 0 && (rand() % model->num_patches())) + // return; + + bool subpatch = rand()%2; + PatchModel* parent = NULL; + string name = random_name(); + PatchModel* pm = NULL; + + if (subpatch) + parent = model->random_patch(); + + if (parent != NULL) + pm = new PatchModel(parent->path() +"/"+ name, (rand()%8)+1); + else + pm = new PatchModel(string("/") + name, (rand()%8)+1); + + cout << "Creating patch " << pm->path() << endl; + + engine->create_patch_from_model(pm); + + // Spread them out a bit for easier monitoring with om_gtk + char tmp_buf[8]; + snprintf(tmp_buf, 8, "%d", 1600 + rand()%800 - 400); + engine->set_metadata(pm->path(), "module-x", string(tmp_buf)); + snprintf(tmp_buf, 8, "%d", 1200 + rand()%700 - 350); + engine->set_metadata(pm->path(), "module-y", string(tmp_buf)); + + delete pm; +} + + +void +destroy() +{ + // Make the probability of this happening proportionate to the number + // of patches to keep the # in a sane range + if (model->num_patches() == 0 || !(rand() % model->num_patches())) + return; + + NodeModel* nm = NULL; + + if (rand()%2) + nm = model->random_patch(); + else + nm = model->random_node(); + + if (nm != NULL) { + cout << "Destroying " << nm->path() << endl; + engine->destroy(nm->path()); + } +} + + +void +add_node() +{ + PatchModel* parent = model->random_patch(); + PluginModel* plugin = model->random_plugin(); + + if (parent != NULL && plugin != NULL) { + NodeModel* nm = new NodeModel(parent->path() +"/"+ random_name()); + nm->plugin(plugin); + cout << "Adding node " << nm->path() << endl; + engine->create_node_from_model(nm); + // Spread them out a bit for easier monitoring with om_gtk + char tmp_buf[8]; + snprintf(tmp_buf, 8, "%d", 1600 + rand()%800 - 400); + engine->set_metadata(nm->path(), "module-x", tmp_buf); + snprintf(tmp_buf, 8, "%d", 1200 + rand()%700 - 350); + engine->set_metadata(nm->path(), "module-y", tmp_buf); + } +} + + +void +connect() +{ + if (!(rand() % 10)) { // Attempt a connection between two nodes in the same patch + PatchModel* parent = model->random_patch(); + NodeModel* n1 = model->random_node_in_patch(parent); + NodeModel* n2 = model->random_node_in_patch(parent); + PortModel* p1 = model->random_port_in_node(n1); + PortModel* p2 = model->random_port_in_node(n2); + + if (p1 != NULL && p2 != NULL) { + cout << "Connecting " << p1->path() << " -> " << p2->path() << endl; + engine->connect(p1->path(), p2->path()); + } + + } else { // Attempt a connection between two truly random nodes + PortModel* p1 = model->random_port(); + PortModel* p2 = model->random_port(); + + if (p1 != NULL && p2 != NULL) { + cout << "Connecting " << p1->path() << " -> " << p2->path() << endl; + engine->connect(p1->path(), p2->path()); + } + } +} + + +void +disconnect() +{ + PortModel* p1 = model->random_port(); + PortModel* p2 = model->random_port(); + + if (p1 != NULL && p2 != NULL) { + cout << "Disconnecting " << p1->path() << " -> " << p2->path() << endl; + engine->disconnect(p1->path(), p2->path()); + } +} + + +void +disconnect_all() +{ + PortModel* p = model->random_port(); + + if (p != NULL) { + cout << "Disconnecting all from" << p->path() << endl; + engine->disconnect_all(p->path()); + } +} + + +void +set_port_value() +{ + PortModel* pm = model->random_port(); + float val = (float)rand() / (float)RAND_MAX; + + if (pm != NULL) { + cout << "Setting control for port " << pm->path() << " to " << val << endl; + engine->set_port_value(pm->path(), val); + } +} + + +void +set_port_value_queued() +{ + PortModel* pm = model->random_port(); + float val = (float)rand() / (float)RAND_MAX; + + if (pm != NULL) { + cout << "Setting control (slow) for port " << pm->path() << " to " << val << endl; + engine->set_port_value_queued(pm->path(), val); + } +} + + +void +rename_object() +{ + // 1/6th chance of it being a patch + /*int type = rand()%6; + + if (type == 0) { + NodeModel* n = model->random_node(); + if (n != NULL) + engine->rename(n->path(), random_name()); + } else { + PatchModel* p = model->random_patch(); + if (p != NULL) + engine->rename(p->path(), random_name()); + }*/ +} + diff --git a/src/progs/gtk/App.cpp b/src/progs/gtk/App.cpp new file mode 100644 index 00000000..6b71b4ec --- /dev/null +++ b/src/progs/gtk/App.cpp @@ -0,0 +1,230 @@ +/* This file is part of Om. Copyright (C) 2006 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 "App.h" +#include +#include +#include +#include +#include +#include +#include "ControlInterface.h" +#include "PatchView.h" +#include "OmModule.h" +#include "ControlPanel.h" +#include "SubpatchModule.h" +#include "OmFlowCanvas.h" +#include "GtkObjectController.h" +#include "PatchController.h" +#include "NodeController.h" +#include "PortController.h" +#include "LoadPluginWindow.h" +#include "PatchWindow.h" +#include "MessagesWindow.h" +#include "ConfigWindow.h" +#include "Controller.h" +#include "GladeFactory.h" +#include "util/Path.h" +#include "ObjectModel.h" +#include "PatchModel.h" +#include "PatchTreeWindow.h" +#include "Configuration.h" +#include "ConnectWindow.h" +#ifdef HAVE_LASH +#include "LashController.h" +#endif +using std::cerr; using std::cout; using std::endl; +using std::string; +namespace LibOmClient { class PluginModel; } +using namespace LibOmClient; + +namespace OmGtk { + +class OmPort; + +App::App() +: m_control_interface(new ControlInterface(this)), + m_configuration(new Configuration()), + m_about_dialog(NULL), + m_enable_signal(true) +{ + Glib::RefPtr glade_xml = GladeFactory::new_glade_reference(); + + glade_xml->get_widget_derived("connect_win", m_connect_window); + //glade_xml->get_widget_derived("new_patch_win", m_new_patch_window); + //glade_xml->get_widget_derived("load_patch_win", m_load_patch_window); + glade_xml->get_widget_derived("config_win", m_config_window); + glade_xml->get_widget_derived("patch_tree_win", m_patch_tree_window); +// glade_xml->get_widget_derived("main_patches_treeview", m_objects_treeview); + glade_xml->get_widget("about_win", m_about_dialog); + + m_config_window->configuration(m_configuration); + + glade_xml->get_widget_derived("messages_win", m_messages_window); +} + + +App::~App() +{ + delete m_control_interface; +} + + +void +App::error_message(const string& str) +{ + m_messages_window->post(str); + m_messages_window->show(); + m_messages_window->raise(); +} + + +/* +bool +App::idle_callback() +{ + m_client_hooks->process_events(); + +#ifdef HAVE_LASH + //if (lash_controller->enabled()) + // lash_controller->process_events(); +#endif + + return true; +} +*/ + + +/******** Event Handlers ************/ + + +#if 0 +App::event_load_session() +{ + Gtk::FileChooserDialog* dialog + = new Gtk::FileChooserDialog(*m_main_window, "Load Session", Gtk::FILE_CHOOSER_ACTION_OPEN); + + dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); + int result = dialog->run(); + string filename = dialog->get_filename(); + delete dialog; + + cout << result << endl; + + assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); + + if (result == Gtk::RESPONSE_OK) + //configuration->load_session(filename); + _controller->load_session(filename); +} + + +void +App::event_save_session_as() +{ + Gtk::FileChooserDialog dialog(*m_main_window, "Save Session", Gtk::FILE_CHOOSER_ACTION_SAVE); + + /* + Gtk::VBox* box = dialog.get_vbox(); + Gtk::Label warning("Warning: Recursively saving will overwrite any subpatch files \ + without confirmation."); + box->pack_start(warning, false, false, 2); + Gtk::CheckButton recursive_checkbutton("Recursively save all subpatches"); + box->pack_start(recursive_checkbutton, false, false, 0); + recursive_checkbutton.show(); + */ + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + + int result = dialog.run(); + //bool recursive = recursive_checkbutton.get_active(); + + assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); + + if (result == Gtk::RESPONSE_OK) { + string filename = dialog.get_filename(); + if (filename.length() < 11 || filename.substr(filename.length()-10) != ".omsession") + filename += ".omsession"; + + bool confirm = false; + std::fstream fin; + fin.open(filename.c_str(), std::ios::in); + if (fin.is_open()) { // File exists + string msg = "File already exists! Are you sure you want to overwrite "; + msg += filename + "?"; + Gtk::MessageDialog confirm_dialog(*m_main_window, + msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + if (confirm_dialog.run() == Gtk::RESPONSE_YES) + confirm = true; + else + confirm = false; + } else { // File doesn't exist + confirm = true; + } + fin.close(); + + if (confirm) { + _controller->save_session(filename); + } + } +} +#endif + +void +App::add_patch_window(PatchWindow* pw) +{ + m_windows.push_back(pw); +} + + +void +App::remove_patch_window(PatchWindow* pw) +{ + m_windows.erase(find(m_windows.begin(), m_windows.end(), pw)); +} + + +/** Returns the number of Patch windows currently visible. + */ +int +App::num_open_patch_windows() +{ + int ret = 0; + for (list::iterator i = m_windows.begin(); i != m_windows.end(); ++i) + if ((*i)->is_visible()) + ++ret; + + return ret; +} + +void +App::quit() +{ + Gtk::Main::quit(); +} + +void +App::quit_and_kill() +{ + Controller::instance().quit(); + Gtk::Main::quit(); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/App.h b/src/progs/gtk/App.h new file mode 100644 index 00000000..1ba18962 --- /dev/null +++ b/src/progs/gtk/App.h @@ -0,0 +1,123 @@ +/* This file is part of Om. Copyright (C) 2006 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 OMGTKAPP_H +#define OMGTKAPP_H + +#include +#include +#include +#include +#include +#include +#include +#include +using std::string; using std::map; using std::list; +using std::cerr; using std::endl; + +namespace LibOmClient { class PatchModel; class PluginModel; } +using namespace LibOmClient; + +/** \defgroup OmGtk GTK Client + */ + +namespace OmGtk { + +class PatchWindow; +class GtkObjectController; +class PatchController; +class NodeController; +class PortController; +class LoadPatchWindow; +class MessagesWindow; +class ConfigWindow; +class OmGtkObject; +class OmModule; +class OmPort; +class OmFlowCanvas; +class PatchTreeView; +class PatchTreeWindow; +class ControlInterface; +class ConnectWindow; +class Configuration; + + +/** Singleton master class most everything is contained within. + * + * This is a horrible god-object, but it's shrinking in size as things are + * moved out. Hopefully it will go away entirely some day.. + * + * \ingroup OmGtk + */ +class App +{ +public: + ~App(); + + void error_message(const string& msg); + + void quit(); + void quit_and_kill(); + + void add_patch_window(PatchWindow* pw); + void remove_patch_window(PatchWindow* pw); + + int num_open_patch_windows(); + + ConnectWindow* connect_window() const { return m_connect_window; } + Gtk::Dialog* about_dialog() const { return m_about_dialog; } + ConfigWindow* configuration_dialog() const { return m_config_window; } + MessagesWindow* messages_dialog() const { return m_messages_window; } + PatchTreeWindow* patch_tree() const { return m_patch_tree_window; } + Configuration* configuration() const { return m_configuration; } + + ControlInterface* control_interface() { return m_control_interface; } + + static void instantiate() { if (!_instance) _instance = new App(); } + static inline App& instance() { assert(_instance); return *_instance; } + +protected: + App(); + static App* _instance; + + //bool connect_callback(); + //bool idle_callback(); + + ControlInterface* m_control_interface; + Configuration* m_configuration; + + list m_windows; + + ConnectWindow* m_connect_window; + MessagesWindow* m_messages_window; + PatchTreeWindow* m_patch_tree_window; + ConfigWindow* m_config_window; + Gtk::Dialog* m_about_dialog; + Gtk::Button* m_engine_error_close_button; + + /** Used to avoid feedback loops with (eg) process checkbutton + * FIXME: Maybe this should be globally implemented at the Controller level, + * disable all command sending while handling events to avoid feedback + * issues with widget event callbacks? This same pattern is duplicated + * too much... */ + bool m_enable_signal; +}; + + +} // namespace OmGtk + +#endif // OMGTKAPP_H + diff --git a/src/progs/gtk/BreadCrumb.h b/src/progs/gtk/BreadCrumb.h new file mode 100644 index 00000000..f79ad363 --- /dev/null +++ b/src/progs/gtk/BreadCrumb.h @@ -0,0 +1,66 @@ +/* This file is part of Om. Copyright (C) 2006 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 BREADCRUMB_H +#define BREADCRUMB_H + +#include +#include "PatchWindow.h" +#include "PatchController.h" +#include "PatchModel.h" + +namespace OmGtk { + + +/** Breadcrumb button in a PatchWindow. + * + * \ingroup OmGtk + */ +class BreadCrumb : public Gtk::ToggleButton +{ +public: + BreadCrumb(PatchWindow* window, PatchController* patch) + : m_window(window), + m_patch(patch) + { + assert(patch != NULL); + set_border_width(0); + path(m_patch->path()); + signal_clicked().connect(sigc::bind(sigc::mem_fun( + m_window, &PatchWindow::breadcrumb_clicked), this)); + show_all(); + } + + PatchController* patch() { return m_patch; } + + void path(const Path& path) + { + remove(); + const string text = (path == "/") ? "/" : path.name(); + Gtk::Label* lab = manage(new Gtk::Label(text)); + lab->set_padding(0, 0); + lab->show(); + add(*lab); + } + +private: + PatchWindow* m_window; + PatchController* m_patch; +}; + +} // namespace OmGtk + +#endif // BREADCRUMB_H diff --git a/src/progs/gtk/ConfigWindow.cpp b/src/progs/gtk/ConfigWindow.cpp new file mode 100644 index 00000000..db3bce18 --- /dev/null +++ b/src/progs/gtk/ConfigWindow.cpp @@ -0,0 +1,86 @@ +/* This file is part of Om. Copyright (C) 2006 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 "ConfigWindow.h" +#include +#include +#include +#include +#include "PatchController.h" +#include "NodeModel.h" +#include "OmFlowCanvas.h" +using std::cout; using std::cerr; using std::endl; + + +namespace OmGtk { + +ConfigWindow::ConfigWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::Window(cobject), + m_configuration(NULL) +{ + xml->get_widget("config_path_entry", m_path_entry); + xml->get_widget("config_save_button", m_save_button); + xml->get_widget("config_cancel_button", m_cancel_button); + xml->get_widget("config_ok_button", m_ok_button); + + m_save_button->signal_clicked().connect( sigc::mem_fun(this, &ConfigWindow::save_clicked)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &ConfigWindow::cancel_clicked)); + m_ok_button->signal_clicked().connect( sigc::mem_fun(this, &ConfigWindow::ok_clicked)); +} + + +/** Sets the state manager for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +ConfigWindow::configuration(Configuration* sm) +{ + m_configuration = sm; + m_path_entry->set_text(sm->patch_path()); +} + + + +///// Event Handlers ////// + + +void +ConfigWindow::save_clicked() +{ + m_configuration->patch_path(m_path_entry->get_text()); + m_configuration->apply_settings(); + m_configuration->save_settings(); +} + + +void +ConfigWindow::cancel_clicked() +{ + hide(); +} + + +void +ConfigWindow::ok_clicked() +{ + m_configuration->patch_path(m_path_entry->get_text()); + m_configuration->apply_settings(); + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ConfigWindow.h b/src/progs/gtk/ConfigWindow.h new file mode 100644 index 00000000..caf1531f --- /dev/null +++ b/src/progs/gtk/ConfigWindow.h @@ -0,0 +1,63 @@ +/* This file is part of Om. Copyright (C) 2006 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 CONFIGWINDOW_H +#define CONFIGWINDOW_H + +#include "PluginModel.h" +#include "Configuration.h" +#include +#include +#include +#include + +using std::list; +using LibOmClient::PluginModel; + +namespace OmGtk { + + +/** 'Configuration' window. + * + * Loaded by glade as a derived object. + * + * \ingroup OmGtk + */ +class ConfigWindow : public Gtk::Window +{ +public: + ConfigWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); + + void configuration(Configuration* sm); + +private: + void save_clicked(); + void cancel_clicked(); + void ok_clicked(); + + Configuration* m_configuration; + + Gtk::Entry* m_path_entry; + Gtk::Button* m_save_button; + Gtk::Button* m_cancel_button; + Gtk::Button* m_ok_button; +}; + + +} // namespace OmGtk + +#endif // CONFIGWINDOW_H diff --git a/src/progs/gtk/Configuration.cpp b/src/progs/gtk/Configuration.cpp new file mode 100644 index 00000000..e4882cc3 --- /dev/null +++ b/src/progs/gtk/Configuration.cpp @@ -0,0 +1,184 @@ +/* This file is part of Om. Copyright (C) 2006 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 "Configuration.h" +#include +#include +#include +#include +#include +#include "PortModel.h" +#include "PluginModel.h" +#include "PatchController.h" +#include "PatchModel.h" +#include "OmFlowCanvas.h" +#include "Controller.h" + +using std::cerr; using std::cout; using std::endl; +using std::map; using std::string; +using LibOmClient::PatchModel; + +namespace OmGtk { + +using namespace LibOmClient; + + +Configuration::Configuration() +: m_patch_path("/usr/share/om/patches:/usr/local/share/om/patches"), + m_audio_port_color( 0x394f66FF), + m_control_port_color(0x396639FF), + m_midi_port_color( 0x663939FF) +{ +} + + +Configuration::~Configuration() +{ +} + + +/** Loads settings from the rc file. Passing no parameter will load from + * the default location. + */ +void +Configuration::load_settings(string filename) +{ + if (filename == "") + filename = string(getenv("HOME")).append("/.omgtkrc"); + + std::ifstream is; + is.open(filename.c_str(), std::ios::in); + + if ( ! is.good()) { + cout << "[Configuration] Unable to open settings file " << filename << endl; + return; + } else { + cout << "[Configuration] Loading settings from " << filename << endl; + } + + string s; + + is >> s; + if (s != "file_version") { + cerr << "[Configuration] Corrupt settings file, load aborted." << endl; + is.close(); + return; + } + + is >> s; + if (s != "1") { + cerr << "[Configuration] Unknown settings file version number, load aborted." << endl; + is.close(); + return; + } + + is >> s; + if (s != "patch_path") { + cerr << "[Configuration] Corrupt settings file, load aborted." << endl; + is.close(); + return; + } + + is >> s; + m_patch_path = s; + + is.close(); +} + + +/** Saves settings to rc file. Passing no parameter will save to the + * default location. + */ +void +Configuration::save_settings(string filename) +{ + if (filename == "") + filename = string(getenv("HOME")).append("/.omgtkrc"); + + std::ofstream os; + os.open(filename.c_str(), std::ios::out); + + if ( ! os.good()) { + cout << "[Configuration] Unable to write to setting file " << filename << endl; + return; + } else { + cout << "[Configuration] Saving settings to " << filename << endl; + } + + os << "file_version 1" << endl; + os << "patch_path " << m_patch_path << endl; + + os.close(); +} + + +/** Applies the current loaded settings to whichever parts of the app + * need updating. + */ +void +Configuration::apply_settings() +{ + Controller::instance().set_patch_path(m_patch_path); +} + + +int +Configuration::get_port_color(const PortModel* pi) +{ + assert(pi != NULL); + + if (pi->is_control()) { + return m_control_port_color; + } else if (pi->is_audio()) { + return m_audio_port_color; + } else if (pi->is_midi()) { + return m_midi_port_color; + } + + cerr << "[Configuration] Unknown port type! Port will be bright red, this is an error." << endl; + return 0xFF0000FF; +} + +/* +Coord +Configuration::get_window_location(const string& id) +{ + return m_window_locations[id]; +} + + +void +Configuration::set_window_location(const string& id, Coord loc) +{ + m_window_locations[id] = loc; +} + + +Coord +Configuration::get_window_size(const string& id) +{ + return m_window_sizes[id]; +} + + +void +Configuration::set_window_size(const string& id, Coord size) +{ + m_window_sizes[id] = size; +}*/ + + +} // namespace OmGtk diff --git a/src/progs/gtk/Configuration.h b/src/progs/gtk/Configuration.h new file mode 100644 index 00000000..f0f9bef9 --- /dev/null +++ b/src/progs/gtk/Configuration.h @@ -0,0 +1,76 @@ +/* This file is part of Om. Copyright (C) 2006 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 CONFIG_H +#define CONFIG_H + +#include + +namespace LibOmClient { class PortModel; } +using LibOmClient::PortModel; +using std::string; + +struct Coord { double x; double y; }; + +namespace OmGtk { + +class Controller; + + +/** Singleton state manager for the entire app. + * + * Stores settings like color preferences, search paths, etc. + * (ie any user-defined preferences to be stoed in the rc file). + * + * \ingroup OmGtk + */ +class Configuration +{ +public: + Configuration(); + ~Configuration(); + + void load_settings(string filename = ""); + void save_settings(string filename = ""); + + void apply_settings(); + + string patch_path() { return m_patch_path; } + void patch_path(const string& path) { m_patch_path = path; } + + const string& patch_folder() { return m_patch_folder; } + void set_patch_folder(const string& f) { m_patch_folder = f; } + + int get_port_color(const PortModel* pi); + +private: + /** Search path for patch files. Colon delimited, as usual. */ + string m_patch_path; + + /** Most recent patch folder shown in open dialog */ + string m_patch_folder; + + int m_audio_port_color; + int m_control_port_color; + int m_midi_port_color; +}; + + +} // namespace OmGtk + +#endif // CONFIG_H + + diff --git a/src/progs/gtk/ConnectWindow.cpp b/src/progs/gtk/ConnectWindow.cpp new file mode 100644 index 00000000..15bab62c --- /dev/null +++ b/src/progs/gtk/ConnectWindow.cpp @@ -0,0 +1,170 @@ +/* This file is part of Om. Copyright (C) 2006 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 "ConnectWindow.h" +#include +#include +#include +#include "interface/ClientKey.h" +#include "interface/ClientInterface.h" +#include "ThreadedSigClientInterface.h" +#include "Controller.h" +#include "OSCListener.h" +#include "Store.h" + +namespace OmGtk { + + +ConnectWindow::ConnectWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::Dialog(cobject) +, _client(NULL) +{ + xml->get_widget("connect_progress_bar", _progress_bar); + xml->get_widget("connect_label", _label); + xml->get_widget("connect_launch_button", _launch_button); + xml->get_widget("connect_cancel_button", _cancel_button); + + assert(_progress_bar); + assert(_label); + assert(_launch_button); + assert(_cancel_button); + + _launch_button->signal_clicked().connect(sigc::mem_fun(this, &ConnectWindow::launch_engine)); + _cancel_button->signal_clicked().connect(sigc::ptr_fun(&Gtk::Main::quit)); +} + + +void +ConnectWindow::start(CountedPtr client) +{ + _client = client; + + Glib::signal_timeout().connect( + sigc::mem_fun(this, &ConnectWindow::gtk_callback), 100); + + resize(100, 100); +} + + +void +ConnectWindow::launch_engine() +{ + if (fork() == 0) { + //cerr << "Launching engine.."; + execlp("om", NULL); + } +} + + +bool +ConnectWindow::gtk_callback() +{ + /* This isn't very nice (isn't threaded), but better than no dialog at + * all like before :) + */ + + // Timing stuff for repeated attach attempts + timeval now; + gettimeofday(&now, NULL); + static timeval last = now; + + static int stage = 0; + + /* Connecting to engine */ + if (stage == 0) { + // FIXME + //assert(!Controller::instance().is_attached()); + _label->set_text(string("Connecting to engine at ").append( + Controller::instance().engine_url()).append("...")); + present(); + Controller::instance().attach(); + ++stage; + } else if (stage == 1) { + if (Controller::instance().is_attached()) { + Controller::instance().activate(); + ++stage; + } else { + const float ms_since_last = (now.tv_sec - last.tv_sec) * 1000.0f + + (now.tv_usec - last.tv_usec) * 0.001f; + if (ms_since_last > 1000) { + Controller::instance().attach(); + last = now; + } + } + } else if (stage == 2) { + _label->set_text(string("Registering as client...")); + //Controller::instance().register_client(Controller::instance().client_hooks()); + // FIXME + //auto_ptr client(new ThreadedSigClientInterface(); + Controller::instance().register_client(ClientKey(), _client); + Controller::instance().load_plugins(); + ++stage; + } else if (stage == 3) { + // Register idle callback to process events and whatnot + // (Gtk refreshes at priority G_PRIORITY_HIGH_IDLE+20) + /*Glib::signal_timeout().connect( + sigc::mem_fun(this, &App::idle_callback), 100, G_PRIORITY_HIGH_IDLE);*/ + //Glib::signal_idle().connect(sigc::mem_fun(this, &App::idle_callback)); + /* Glib::signal_timeout().connect( + sigc::mem_fun((ThreadedSigClientInterface*)_client, &ThreadedSigClientInterface::emit_signals), + 5, G_PRIORITY_DEFAULT_IDLE);*/ + + _label->set_text(string("Requesting plugins...")); + Controller::instance().request_plugins(); + ++stage; + } else if (stage == 4) { + // Wait for first plugins message + if (Store::instance().plugins().size() > 0) { + _label->set_text(string("Receiving plugins...")); + ++stage; + } + } else if (stage == 5) { + // FIXME + /*if (Store::instance().plugins().size() < _client->num_plugins()) { + static char buf[32]; + snprintf(buf, 32, "%zu/%zu", Store::instance().plugins().size(), + ThreadedSigClientInterface::instance()->num_plugins()); + _progress_bar->set_text(Glib::ustring(buf)); + _progress_bar->set_fraction( + Store::instance().plugins().size() / (double)_client->num_plugins()); + } else {*/ + _progress_bar->set_text(""); + ++stage; + //} + } else if (stage == 6) { + _label->set_text(string("Waiting for root patch...")); + Controller::instance().request_all_objects(); + ++stage; + } else if (stage == 7) { + if (Store::instance().num_objects() > 0) + ++stage; + } else if (stage == 8) { + stage = -1; + hide(); // FIXME: actually destroy window to save mem? + } + + if (stage != 5) // yeah, ew + _progress_bar->pulse(); + + if (stage == -1) { // finished connecting + return false; // deregister this callback + } else { + return true; + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ConnectWindow.h b/src/progs/gtk/ConnectWindow.h new file mode 100644 index 00000000..8c0c7390 --- /dev/null +++ b/src/progs/gtk/ConnectWindow.h @@ -0,0 +1,61 @@ +/* This file is part of Om. Copyright (C) 2006 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 CONNECT_WINDOW_H +#define CONNECT_WINDOW_H + +#include +#include +#include +#include "util/CountedPtr.h" +#include "interface/ClientInterface.h" + +namespace OmGtk { + +class App; +class Controller; + + +/** The initially visible "Connect to engine" window. + * + * This handles actually connecting to the engine and making sure everything + * is ready before really launching the app (eg wait for the root patch). + * + * \ingroup OmGtk + */ +class ConnectWindow : public Gtk::Dialog +{ +public: + ConnectWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); + + void start(CountedPtr client); + +private: + void launch_engine(); + + bool gtk_callback(); + + CountedPtr _client; + Gtk::ProgressBar* _progress_bar; + Gtk::Label* _label; + Gtk::Button* _launch_button; + Gtk::Button* _cancel_button; +}; + + +} // namespace OmGtk + +#endif // CONNECT_WINDOW_H diff --git a/src/progs/gtk/ControlGroups.cpp b/src/progs/gtk/ControlGroups.cpp new file mode 100644 index 00000000..de87be05 --- /dev/null +++ b/src/progs/gtk/ControlGroups.cpp @@ -0,0 +1,419 @@ +/* This file is part of Om. Copyright (C) 2006 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 "ControlGroups.h" +#include "ControlPanel.h" +#include "PortModel.h" +#include "Controller.h" +//#include "GtkClientInterface.h" +#include +#include +using std::cerr; using std::cout; using std::endl; + +using namespace LibOmClient; + +namespace OmGtk { + +//////////////////// SliderControlGroup //////////////////////// + + +SliderControlGroup::SliderControlGroup(ControlPanel* panel, PortModel* pm, bool separator) +: ControlGroup(panel, pm, separator), + m_enabled(true), + m_enable_signal(false), + m_name_label(pm->name(), 0.0, 0.0), + m_range_box(false, 0), + m_range_label("Range: "), + m_min_spinner(1.0, (pm->is_integer() ? 0 : 4)), // climb rate, digits + m_hyphen_label(" - "), + m_max_spinner(1.0, (pm->is_integer() ? 0 : 4)), + m_slider_box(false, 0), + m_value_spinner(1.0, (pm->is_integer() ? 0 : 4)), + m_slider(pm->user_min(), pm->user_max(), (pm->is_integer() ? 1.0 : 0.0001)) +{ + m_slider.set_increments(1.0, 10.0); + + // Compensate for crazy plugins + if (m_port_model->user_max() <= m_port_model->user_min()) { + m_port_model->user_max(m_port_model->user_min() + 1.0); + m_slider.set_range(m_port_model->user_min(), m_port_model->user_max()); + } + m_slider.property_draw_value() = false; + + set_name(pm->name()); + + m_name_label.property_use_markup() = true; + m_range_label.property_use_markup() = true; + + m_value_spinner.set_range(-99999, 99999); + m_value_spinner.set_update_policy(Gtk::UPDATE_ALWAYS); // allow entered values outside range + m_value_spinner.set_value(m_port_model->value()); + m_value_spinner.set_increments(1.0, 10.0); + m_value_spinner.set_digits(5); + m_value_spinner.signal_value_changed().connect( + sigc::mem_fun(*this, &SliderControlGroup::update_value_from_spinner)); + m_min_spinner.set_range(-99999, 99999); + m_min_spinner.set_value(m_port_model->user_min()); + m_min_spinner.set_increments(1.0, 10.0); + m_min_spinner.set_digits(5); + m_min_spinner.signal_value_changed().connect(sigc::mem_fun(*this, &SliderControlGroup::min_changed)); + m_max_spinner.set_range(-99999, 99999); + m_max_spinner.set_value(m_port_model->user_max()); + m_max_spinner.set_increments(1.0, 10.0); + m_max_spinner.set_digits(5); + m_max_spinner.signal_value_changed().connect(sigc::mem_fun(*this, &SliderControlGroup::max_changed)); + + m_slider.set_value(m_port_model->value()); + + m_slider.signal_event().connect( + sigc::mem_fun(*this, &SliderControlGroup::slider_pressed)); + + m_slider.signal_value_changed().connect( + sigc::mem_fun(*this, &SliderControlGroup::update_value_from_slider)); + + m_range_box.pack_start(m_range_label, false, false, 2); + m_range_box.pack_start(m_min_spinner, false, false, 1); + m_range_box.pack_start(m_hyphen_label, false, false, 1); + m_range_box.pack_start(m_max_spinner, false, false, 1); + + m_header_box.pack_start(m_name_label, true, true, 0); + m_header_box.pack_start(m_range_box, true, true, 2); + + m_slider_box.pack_start(m_value_spinner, false, false, 1); + m_slider_box.pack_start(m_slider, true, true, 5); + + pack_start(m_header_box, false, false, 0); + pack_start(m_slider_box, false, false, 0); + + update_range(); + + m_enable_signal = true; + + show_all(); +} + + +void +SliderControlGroup::set_name(const string& name) +{ + string name_label = ""; + name_label += name + ""; + m_name_label.set_markup(name_label); +} + + +void +SliderControlGroup::set_min(float val) +{ + m_enable_signal = false; + m_min_spinner.set_value(val); + m_enable_signal = true; +} + + +void +SliderControlGroup::set_max(float val) +{ + m_enable_signal = false; + m_max_spinner.set_value(val); + m_enable_signal = true; +} + + +void +SliderControlGroup::enable() +{ + m_slider.property_sensitive() = true; + m_min_spinner.property_sensitive() = true; + m_max_spinner.property_sensitive() = true; + m_value_spinner.property_sensitive() = true; + m_name_label.property_sensitive() = true; + m_range_label.property_sensitive() = true; +} + + +void +SliderControlGroup::disable() +{ + m_slider.property_sensitive() = false; + m_min_spinner.property_sensitive() = false; + m_max_spinner.property_sensitive() = false; + m_value_spinner.property_sensitive() = false; + m_name_label.property_sensitive() = false; + m_range_label.property_sensitive() = false; +} + + +void +SliderControlGroup::min_changed() +{ + double min = m_min_spinner.get_value(); + const double max = m_max_spinner.get_value(); + + if (min >= max) { + min = max - 1.0; + m_min_spinner.set_value(min); + } + + update_range(); +} + + +void +SliderControlGroup::max_changed() +{ + const double min = m_min_spinner.get_value(); + double max = m_max_spinner.get_value(); + + if (max <= min) { + max = min + 1.0; + m_max_spinner.set_value(max); + } + + update_range(); +} + + +void +SliderControlGroup::update_range() +{ + const double min = m_min_spinner.get_value(); + const double max = m_max_spinner.get_value(); + + assert(min < max); + m_slider.set_range(min, max); + + m_port_model->user_min(min); + m_port_model->user_max(max); + + if (m_enable_signal) { + char temp_buf[16]; + snprintf(temp_buf, 16, "%f", m_port_model->user_min()); + Controller::instance().set_metadata(m_port_model->path(), "user-min", temp_buf); + snprintf(temp_buf, 16, "%f", m_port_model->user_max()); + Controller::instance().set_metadata(m_port_model->path(), "user-max", temp_buf); + } +} + + +void +SliderControlGroup::update_value_from_slider() +{ + if (m_enable_signal) { + const float value = m_slider.get_value(); + // Prevent spinner signal from doing all this over again (slow) + m_enable_signal = false; + m_value_spinner.set_value(value); + m_control_panel->value_changed(m_port_model->path(), value); + m_port_model->value(value); + m_enable_signal = true; + } +} + + +void +SliderControlGroup::update_value_from_spinner() +{ + if (m_enable_signal) { + m_enable_signal = false; + const float value = m_value_spinner.get_value(); + if (value < m_min_spinner.get_value()) + m_min_spinner.set_value(value); + if (value > m_max_spinner.get_value()) + m_max_spinner.set_value(value); + + m_enable_signal = false; + update_range(); + m_slider.set_value(m_value_spinner.get_value()); + m_enable_signal = true; + + m_control_panel->value_changed(m_port_model->path(), value); + + m_port_model->value(value); + m_enable_signal = true; + } +} + + +/** Callback for when slider is grabbed so we can ignore set_control + * events for this port (and avoid nasty feedback issues). + */ +bool +SliderControlGroup::slider_pressed(GdkEvent* ev) +{ + //cerr << "Pressed: " << ev->type << endl; + if (ev->type == GDK_BUTTON_PRESS) { + m_enabled = false; + cerr << "SLIDER FIXME\n"; + //GtkClientInterface::instance()->set_ignore_port(m_port_model->path()); + } else if (ev->type == GDK_BUTTON_RELEASE) { + m_enabled = true; + cerr << "SLIDER FIXME\n"; + //GtkClientInterface::instance()->clear_ignore_port(); + } + + return false; +} + + +/////////////// IntegerControlGroup //////////////// + + +IntegerControlGroup::IntegerControlGroup(ControlPanel* panel, PortModel* pm, bool separator) +: ControlGroup(panel, pm, separator), + m_enable_signal(false), + m_alignment(0.5, 0.5, 0.0, 0.0), + m_name_label(pm->name()), + m_spinner(1.0, 0) +{ + set_name(pm->name()); + + m_spinner.set_range(-99999, 99999); + m_spinner.set_value(m_port_model->value()); + m_spinner.signal_value_changed().connect( + sigc::mem_fun(*this, &IntegerControlGroup::update_value)); + m_spinner.set_increments(1, 10); + + m_alignment.add(m_spinner); + pack_start(m_name_label); + pack_start(m_alignment); + + m_enable_signal = true; + + show_all(); +} + + +void +IntegerControlGroup::set_name(const string& name) +{ + string name_label = ""; + name_label += name + ""; + m_name_label.set_markup(name_label); +} + + +void +IntegerControlGroup::set_value(float val) +{ + //cerr << "[IntegerControlGroup] Setting value to " << val << endl; + m_enable_signal = false; + m_spinner.set_value(val); + m_port_model->value(val); + m_enable_signal = true; +} + + +void +IntegerControlGroup::enable() +{ + m_spinner.property_sensitive() = true; + m_name_label.property_sensitive() = true; +} + + +void +IntegerControlGroup::disable() +{ + m_spinner.property_sensitive() = false; + m_name_label.property_sensitive() = false; +} + + +void +IntegerControlGroup::update_value() +{ + if (m_enable_signal) { + float value = m_spinner.get_value(); + m_control_panel->value_changed(m_port_model->path(), value); + m_port_model->value(value); + } +} + + +/////////////// ToggleControlGroup //////////////// + + +ToggleControlGroup::ToggleControlGroup(ControlPanel* panel, PortModel* pm, bool separator) +: ControlGroup(panel, pm, separator), + m_enable_signal(false), + m_alignment(0.5, 0.5, 0.0, 0.0), + m_name_label(pm->name()) +{ + set_name(pm->name()); + + set_value(m_port_model->value()); + m_checkbutton.signal_toggled().connect( + sigc::mem_fun(*this, &ToggleControlGroup::update_value)); + + m_alignment.add(m_checkbutton); + pack_start(m_name_label); + pack_start(m_alignment); + + m_enable_signal = true; + + show_all(); +} + + +void +ToggleControlGroup::set_name(const string& name) +{ + string name_label = ""; + name_label += name + ""; + m_name_label.set_markup(name_label); +} + + +void +ToggleControlGroup::set_value(float val) +{ + //cerr << "[ToggleControlGroup] Setting value to " << val << endl; + m_enable_signal = false; + m_checkbutton.set_active( (val > 0.0f) ); + m_port_model->value(val); + m_enable_signal = true; +} + + +void +ToggleControlGroup::enable() +{ + m_checkbutton.property_sensitive() = true; + m_name_label.property_sensitive() = true; +} + + +void +ToggleControlGroup::disable() +{ + m_checkbutton.property_sensitive() = false; + m_name_label.property_sensitive() = false; +} + + +void +ToggleControlGroup::update_value() +{ + if (m_enable_signal) { + float value = m_checkbutton.get_active() ? 1.0f : 0.0f; + m_control_panel->value_changed(m_port_model->path(), value); + m_port_model->value(value); + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ControlGroups.h b/src/progs/gtk/ControlGroups.h new file mode 100644 index 00000000..ab1e3413 --- /dev/null +++ b/src/progs/gtk/ControlGroups.h @@ -0,0 +1,196 @@ +/* This file is part of Om. Copyright (C) 2006 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 CONTROLGROUPS_H +#define CONTROLGROUPS_H + +#include +#include +#include +#include +#include "PortModel.h" + + +namespace LibOmClient { class PortModel; } +using namespace LibOmClient; + +namespace OmGtk { + +class ControlPanel; + + +/** A group of controls in a NodeControlWindow. + * + * \ingroup OmGtk + */ +class ControlGroup : public Gtk::VBox +{ +public: + ControlGroup(ControlPanel* panel, PortModel* pm, bool separator) + : Gtk::VBox(false, 0), + m_control_panel(panel), + m_port_model(pm), + m_has_separator(separator) + { + assert(m_port_model != NULL); + assert(panel != NULL); + + if (separator) { + m_separator = new Gtk::HSeparator(); + pack_start(*m_separator, false, false, 4); + } else { + m_separator = NULL; + } + } + + ~ControlGroup() { delete m_separator; } + + virtual void set_name(const string& name) {} + + virtual void set_value(float val) = 0; + + inline const PortModel* const port_model() { return m_port_model; } + + virtual void set_min(float val) {} + virtual void set_max(float val) {} + + void remove_separator() { assert(m_has_separator); + remove(*m_separator); delete m_separator; } + + virtual void enable() {} + virtual void disable() {} + +protected: + ControlPanel* m_control_panel; + PortModel* m_port_model; + bool m_has_separator; + Gtk::HSeparator* m_separator; +}; + + +/** A slider for a continuous control. + * + * \ingroup OmGtk + */ +class SliderControlGroup : public ControlGroup +{ +public: + SliderControlGroup(ControlPanel* panel, PortModel* pm, bool separator); + + void set_name(const string& name); + + inline void set_value(const float val); + void set_min(float val); + void set_max(float val); + + void enable(); + void disable(); + +private: + void min_changed(); + void max_changed(); + void update_range(); + void update_value_from_slider(); + void update_value_from_spinner(); + + //void slider_grabbed(bool b); + + bool slider_pressed(GdkEvent* ev); + + bool m_enabled; + bool m_enable_signal; + + Gtk::HBox m_header_box; + Gtk::Label m_name_label; + Gtk::HBox m_range_box; + Gtk::Label m_range_label; + Gtk::SpinButton m_min_spinner; + Gtk::Label m_hyphen_label; + Gtk::SpinButton m_max_spinner; + Gtk::HBox m_slider_box; + Gtk::SpinButton m_value_spinner; + Gtk::HScale m_slider; +}; + + +inline void +SliderControlGroup::set_value(const float val) +{ + m_enable_signal = false; + if (m_enabled) { + m_slider.set_value(val); + m_value_spinner.set_value(val); + } + m_port_model->value(val); + m_enable_signal = true; +} + + + + +/** A spinbutton for integer controls. + * + * \ingroup OmGtk + */ +class IntegerControlGroup : public ControlGroup +{ +public: + IntegerControlGroup(ControlPanel* panel, PortModel* pm, bool separator); + + void set_name(const string& name); + void set_value(float val); + + void enable(); + void disable(); + +private: + void update_value(); + + bool m_enable_signal; + Gtk::Alignment m_alignment; + Gtk::Label m_name_label; + Gtk::SpinButton m_spinner; +}; + + +/** A radio button for toggle controls. + * + * \ingroup OmGtk + */ +class ToggleControlGroup : public ControlGroup +{ +public: + ToggleControlGroup(ControlPanel* panel, PortModel* pm, bool separator); + + void set_name(const string& name); + void set_value(float val); + + void enable(); + void disable(); + +private: + void update_value(); + + bool m_enable_signal; + Gtk::Alignment m_alignment; + Gtk::Label m_name_label; + Gtk::CheckButton m_checkbutton; +}; + + +} // namespace OmGtk + +#endif // CONTROLGROUPS_H diff --git a/src/progs/gtk/ControlInterface.cpp b/src/progs/gtk/ControlInterface.cpp new file mode 100644 index 00000000..9ac6e07e --- /dev/null +++ b/src/progs/gtk/ControlInterface.cpp @@ -0,0 +1,302 @@ +/* This file is part of Om. Copyright (C) 2006 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 + +#include "ControlInterface.h" +#include "App.h" + +#include "PluginModel.h" +#include "PatchModel.h" +#include "NodeModel.h" +#include "PortModel.h" +#include "ConnectionModel.h" + +#include "PatchController.h" +#include "PortController.h" +#include "PatchTreeWindow.h" +#include "Store.h" + +namespace OmGtk +{ + + +void +ControlInterface::error(const string& msg) +{ + _app->error_message(msg); +} + + +void +ControlInterface::new_plugin_model(PluginModel* pm) +{ + cerr << "NEW PLUGIN\n"; + Store::instance().add_plugin(pm); +} + + +void +ControlInterface::new_patch_model(PatchModel* const pm) +{ + assert(pm); + + //cout << "[ControlInterface] New patch." << endl; + + if (Store::instance().patch(pm->path()) != NULL) { + delete pm; + } else { + + // See if we cached this patch model to store its location (to avoid the + // module "jumping") and filename (which isn't sent to engine) + /*PatchModel* pm = _controller->yank_added_patch(pm->path()); + if (pm != NULL) { + assert(pm->path() == pm->path()); + // FIXME: ew + if (pm->parent() != NULL) + pm->set_parent(NULL); + const PluginModel* plugin = pm->plugin(); + *pm = *pm; + pm->plugin(plugin); + }*/ + + assert(pm->parent() == NULL); + PatchController* patch = new PatchController(pm); + Store::instance().add_object(patch); + _app->patch_tree()->add_patch(patch); + + if (pm->path() == "/") + patch->show_patch_window(); + + //_app->add_patch(pm, show); + } +} + + +void +ControlInterface::new_node_model(NodeModel* const nm) +{ + assert(nm); + + //cerr << "[ControlInterface] New node: " << nm->name() << endl; + + PatchController* const pc = Store::instance().patch(nm->path().parent()); + + if (pc != NULL) { + /* FIXME: this is crazy slow, and slows down patch loading too much. Define some + * kind of unified string to describe all plugins (ie ladspa:amp.so:amp_gaia) and + * just store that in node models, and look it up when needed */ + + /* Bit of a hack, throw away the placeholder PluginModel in the NodeModel + * and set it to the nice complete one we have stored */ + + for (map::const_iterator i = Store::instance().plugins().begin(); + i != Store::instance().plugins().end(); ++i) { + if ((*i).second->uri() == nm->plugin()->uri()) { + // FIXME: EVIL + delete (PluginModel*)(nm->plugin()); + nm->plugin((*i).second); + break; + } + } + + pc->add_node(nm); + + } else { + cerr << "[NewNode] Can not find parent of " << nm->path() + << ". Module will not appear." << endl; + } +} + + +void +ControlInterface::new_port_model(PortModel* const pm) +{ + assert(pm); + + //cout << "[ControlInterface] New port." << endl; + + NodeController* node = Store::instance().node(pm->path().parent()); + if (node != NULL) + node->add_port(pm); + else + cerr << "[NewPort] Could not find parent for " + << pm->path() << endl; +} + + +void +ControlInterface::patch_enabled(const string& path) +{ + //cout << "[ControlInterface] Patch enabled." << endl; + + PatchController* patch = Store::instance().patch(path); + if (patch != NULL) + patch->enable(); + else + cerr << "[PatchEnabled] Cannot find patch " << path << endl; +} + + +void +ControlInterface::patch_disabled(const string& path) +{ + //cout << "[ControlInterface] Patch disabled." << endl; + + PatchController* patch = Store::instance().patch(path); + if (patch != NULL) + patch->disable(); + else + cerr << "[PatchDisabled] Cannot find patch " << path << endl; +} + + +void +ControlInterface::patch_cleared(const string& path) +{ + //cout << "[ControlInterface] Patch cleared." << endl; + + PatchController* patch = Store::instance().patch(path); + if (patch != NULL) + patch->clear(); + else + cerr << "[PatchCleared] Cannot find patch " << path << endl; +} + + +void +ControlInterface::object_destroyed(const string& path) +{ + //cout << "[ControlInterface] Destroying." << endl; + + GtkObjectController* object = Store::instance().object(path); + if (object != NULL) { + object->destroy(); + delete object; + } else { + cerr << "[Destroy] Cannot find object " << path << endl; + } +} + + +void +ControlInterface::object_renamed(const string& old_path, const string& new_path) +{ + //cout << "[ControlInterface] Renaming." << endl; + + GtkObjectController* object = Store::instance().object(old_path); + if (object != NULL) + object->set_path(new_path); + else + cerr << "[ObjectRenamed] Can not find object " << old_path + << " to rename." << endl; +} + + +void +ControlInterface::connection_model(ConnectionModel* connection) +{ + assert(connection); + + //cout << "[ControlInterface] Connection" << endl; + + assert(connection->src_port_path().parent().parent() + == connection->dst_port_path().parent().parent()); + + PatchController* pc = Store::instance().patch(connection->patch_path()); + + if (pc != NULL) + pc->connection(connection); + else + cerr << "[Connection] Can not find patch " << connection->patch_path() + << ". Connection will not be made." << endl; +} + + +void +ControlInterface::disconnection(const string& src_port_path, const string& dst_port_path) +{ + //cerr << "[ControlInterface] Disconnection." << endl; + string patch_path = src_port_path; + patch_path = patch_path.substr(0, patch_path.find_last_of("/")); + patch_path = patch_path.substr(0, patch_path.find_last_of("/")); + + if (patch_path == "") + patch_path = "/"; + + PatchController* pc = Store::instance().patch(patch_path); + + if (pc != NULL) + pc->disconnection(src_port_path, dst_port_path); + else + cerr << "[Disconnection] Can not find window for patch " << patch_path + << ". Connection will not be removed." << endl; +} + + +void +ControlInterface::metadata_update(const string& path, const string& key, const string& value) +{ + //cerr << "[ControlInterface] Metadata." << endl; + + GtkObjectController* object = Store::instance().object(path); + if (object != NULL) + object->metadata_update(key, value); + else + cerr << "[MetadataUpdate] Could not find object " << path << endl; +} + + +void +ControlInterface::control_change(const string& port_path, float value) +{ + //cerr << "[ControlInterface] Control change." << endl; + + PortController* port = Store::instance().port(port_path); + if (port != NULL) + port->control_change(value); + else + cerr << "[ControlChange] Can not find port " << port_path << endl; +} + + +void +ControlInterface::program_add(const string& path, uint32_t bank, uint32_t program, const string& name) +{ + NodeController* node = Store::instance().node(path); + if (node != NULL) { + node->program_add(bank, program, name); + return; + } else { + cerr << "[ProgramAdd] Can not find node " << path << endl; + } +} + + +void +ControlInterface::program_remove(const string& path, uint32_t bank, uint32_t program) +{ + NodeController* node = Store::instance().node(path); + if (node != NULL) { + node->program_remove(bank, program); + return; + } else { + cerr << "[ProgramRemove] Can not find node " << path << endl; + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ControlInterface.h b/src/progs/gtk/ControlInterface.h new file mode 100644 index 00000000..8cba6a79 --- /dev/null +++ b/src/progs/gtk/ControlInterface.h @@ -0,0 +1,129 @@ +/* This file is part of Om. Copyright(C) 2006 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 CONTROLINTERFACE_H +#define CONTROLINTERFACE_H + +#include +#include "ModelClientInterface.h" +#include +#include +using std::string; + +namespace LibOmClient +{ +class PluginModel; +class PatchModel; +class NodeModel; +class PortModel; +class ConnectionModel; +} +using namespace LibOmClient; + +namespace OmGtk +{ + +class App; + + +/** Provides the public interface for controlling OmGtk(via engine events). + * + * All control of OmGtk from the engine happens through this interface. + * + * All of these functions must be called in the GTK thread. This is a unified + * interface for controlling OmGtk(eg from the engine) but it doesn't take + * care of any threading issues. + * + * \ingroup OmGtk + */ +class ControlInterface : public sigc::trackable//, public ModelClientInterface +{ +public: + + ControlInterface(App* app) + : error_slot(sigc::mem_fun(this, &ControlInterface::error)) + , new_plugin_slot(sigc::mem_fun(this, &ControlInterface::new_plugin_model)) + , new_patch_slot(sigc::mem_fun(this, &ControlInterface::new_patch_model)) + , new_node_slot(sigc::mem_fun(this, &ControlInterface::new_node_model)) + , new_port_slot(sigc::mem_fun(this, &ControlInterface::new_port_model)) + , patch_enabled_slot(sigc::mem_fun(this, &ControlInterface::patch_enabled)) + , patch_disabled_slot(sigc::mem_fun(this, &ControlInterface::patch_disabled)) + , patch_cleared_slot(sigc::mem_fun(this, &ControlInterface::patch_cleared)) + , object_destroyed_slot(sigc::mem_fun(this, &ControlInterface::object_destroyed)) + , object_renamed_slot(sigc::mem_fun(this, &ControlInterface::object_renamed)) + , connection_slot(sigc::mem_fun(this, &ControlInterface::connection_model)) + , disconnection_slot(sigc::mem_fun(this, &ControlInterface::disconnection)) + , metadata_update_slot(sigc::mem_fun(this, &ControlInterface::metadata_update)) + , control_change_slot(sigc::mem_fun(this, &ControlInterface::control_change)) + , program_add_slot(sigc::mem_fun(this, &ControlInterface::program_add)) + , program_remove_slot(sigc::mem_fun(this, &ControlInterface::program_remove)) + , _app(app) + { + assert(_app); + } + + virtual ~ControlInterface() {} + + sigc::slot bundle_begin_slot; + sigc::slot bundle_end_slot; + sigc::slot num_plugins_slot; + sigc::slot error_slot; + sigc::slot new_plugin_slot; + sigc::slot new_patch_slot; + sigc::slot new_node_slot; + sigc::slot new_port_slot; + sigc::slot patch_enabled_slot; + sigc::slot patch_disabled_slot; + sigc::slot patch_cleared_slot; + sigc::slot object_destroyed_slot; + sigc::slot object_renamed_slot; + sigc::slot connection_slot; + sigc::slot disconnection_slot; + sigc::slot metadata_update_slot; + sigc::slot control_change_slot; + sigc::slot program_add_slot; + sigc::slot program_remove_slot; + +private: + + void bundle_begin(); + void bundle_end(); + void num_plugins(uint32_t); + void error(const string&); + void new_plugin_model(PluginModel*); + void new_patch_model(PatchModel*); + void new_node_model(NodeModel*); + void new_port_model(PortModel*); + void patch_enabled(const string&); + void patch_disabled(const string&); + void patch_cleared(const string&); + void object_destroyed(const string&); + void object_renamed(const string&, const string&); + void connection_model(ConnectionModel*); + void disconnection(const string&, const string&); + void metadata_update(const string&, const string&, const string&); + void control_change(const string&, float); + void program_add(const string&, uint32_t, uint32_t, const string&); + void program_remove(const string&, uint32_t, uint32_t); + + App* _app; +}; + + +} // namespace OmGtk + +#endif // CONTROLINTERFACE_H + diff --git a/src/progs/gtk/ControlPanel.cpp b/src/progs/gtk/ControlPanel.cpp new file mode 100644 index 00000000..f344e2c3 --- /dev/null +++ b/src/progs/gtk/ControlPanel.cpp @@ -0,0 +1,279 @@ +/* This file is part of Om. Copyright (C) 2006 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 alongCont + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ControlPanel.h" +#include "PatchModel.h" +#include "NodeModel.h" +#include "PortModel.h" +#include "ControlGroups.h" +#include "PatchController.h" +#include "Controller.h" + +namespace OmGtk { + + +ControlPanel::ControlPanel(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::VBox(cobject), + m_callback_enabled(true) +{ + xml->get_widget("control_panel_controls_box", m_control_box); + xml->get_widget("control_panel_voice_controls_box", m_voice_control_box); + xml->get_widget("control_panel_all_voices_radio", m_all_voices_radio); + xml->get_widget("control_panel_specific_voice_radio", m_specific_voice_radio); + xml->get_widget("control_panel_voice_spinbutton", m_voice_spinbutton); + + m_all_voices_radio->signal_toggled().connect(sigc::mem_fun(this, &ControlPanel::all_voices_selected)); + m_specific_voice_radio->signal_toggled().connect(sigc::mem_fun(this, &ControlPanel::specific_voice_selected)); + m_voice_spinbutton->signal_value_changed().connect(sigc::mem_fun(this, &ControlPanel::voice_selected)); + + show_all(); +} + + +ControlPanel::~ControlPanel() +{ + for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) + delete (*i); +} + + +void +ControlPanel::init(NodeController* node, size_t poly) +{ + assert(node != NULL); + assert(poly > 0); + + NodeModel* const node_model = node->node_model(); + + if (poly > 1) { + m_voice_spinbutton->set_range(0, poly - 1); + } else { + remove(*m_voice_control_box); + } + + for (PortModelList::const_iterator i = node_model->ports().begin(); + i != node_model->ports().end(); ++i) { + PortController* pc = (PortController*)(*i)->controller(); + assert(pc != NULL); + add_port(pc); + } + + m_callback_enabled = true; +} + + +ControlGroup* +ControlPanel::find_port(const Path& path) const +{ + for (vector::const_iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) + if ((*cg)->port_model()->path() == path) + return (*cg); + + return NULL; +} + + +/** Add a control to the panel for the given port. + */ +void +ControlPanel::add_port(PortController* port) +{ + assert(port != NULL); + assert(port->model() != NULL); + assert(port->control_panel() == NULL); + + PortModel* const pm = port->port_model(); + + // Already have port, don't add another + if (find_port(pm->path()) != NULL) + return; + + // Add port + if (pm->is_control() && pm->is_input()) { + bool separator = (m_controls.size() > 0); + ControlGroup* cg = NULL; + if (pm->is_integer()) + cg = new IntegerControlGroup(this, pm, separator); + else if (pm->is_toggle()) + cg = new ToggleControlGroup(this, pm, separator); + else + cg = new SliderControlGroup(this, pm, separator); + + m_controls.push_back(cg); + m_control_box->pack_start(*cg, false, false, 0); + + if (pm->connected()) + cg->disable(); + else + cg->enable(); + } + + port->set_control_panel(this); + + Gtk::Requisition controls_size; + m_control_box->size_request(controls_size); + m_ideal_size.first = controls_size.width; + m_ideal_size.second = controls_size.height; + + Gtk::Requisition voice_size; + m_voice_control_box->size_request(voice_size); + m_ideal_size.first += voice_size.width; + m_ideal_size.second += voice_size.height; + + //cerr << "Setting ideal size to " << m_ideal_size.first + // << " x " << m_ideal_size.second << endl; +} + + +/** Remove the control for the given port. + */ +void +ControlPanel::remove_port(const Path& path) +{ + bool was_first = false; + for (vector::iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) { + if ((*cg)->port_model()->path() == path) { + m_control_box->remove(**cg); + if (cg == m_controls.begin()) + was_first = true; + m_controls.erase(cg); + break; + } + } + + if (was_first && m_controls.size() > 0) + (*m_controls.begin())->remove_separator(); +} + + +/** Rename the control for the given port. + */ +void +ControlPanel::rename_port(const Path& old_path, const Path& new_path) +{ + for (vector::iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) { + if ((*cg)->port_model()->path() == old_path) { + (*cg)->set_name(new_path.name()); + return; + } + } +} + + +/** Enable the control for the given port. + * + * Used when all connections to port are un-made. + */ +void +ControlPanel::enable_port(const Path& path) +{ + for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + if ((*i)->port_model()->path() == path) { + (*i)->enable(); + return; + } + } +} + + +/** Disable the control for the given port. + * + * Used when port is connected. + */ +void +ControlPanel::disable_port(const Path& path) +{ + for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + if ((*i)->port_model()->path() == path) { + (*i)->disable(); + return; + } + } +} + + +/** Callback for ControlGroups to notify this of a change. + */ +void +ControlPanel::value_changed(const Path& port_path, float val) +{ + if (m_callback_enabled) { + // Update patch control slider, if this is a control panel for a patch + // (or vice versa) + //if (m_mirror != NULL) + // m_mirror->set_port_value(port_path, val); + + if (m_all_voices_radio->get_active()) { + Controller::instance().set_port_value(port_path, val); + } else { + int voice = m_voice_spinbutton->get_value_as_int(); + Controller::instance().set_port_value(port_path, voice, val); + } + } +} + + +void +ControlPanel::set_range_min(const Path& port_path, float val) +{ + bool found = false; + for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + if ((*i)->port_model()->path() == port_path) { + found = true; + (*i)->set_min(val); + } + } + if (found == false) + cerr << "[ControlPanel::set_range_min] Unable to find control " << port_path << endl; +} + + +void +ControlPanel::set_range_max(const Path& port_path, float val) +{ + bool found = false; + for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + if ((*i)->port_model()->path() == port_path) { + found = true; + (*i)->set_max(val); + } + } + if (found == false) + cerr << "[ControlPanel::set_range_max] Unable to find control " << port_path << endl; +} + + +void +ControlPanel::all_voices_selected() +{ + m_voice_spinbutton->property_sensitive() = false; +} + + +void +ControlPanel::specific_voice_selected() +{ + m_voice_spinbutton->property_sensitive() = true; +} + + +void +ControlPanel::voice_selected() +{ +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ControlPanel.h b/src/progs/gtk/ControlPanel.h new file mode 100644 index 00000000..1f24344f --- /dev/null +++ b/src/progs/gtk/ControlPanel.h @@ -0,0 +1,129 @@ +/* This file is part of Om. Copyright (C) 2006 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 CONTROLPANEL_H +#define CONTROLPANEL_H + +#include +#include +#include +#include +#include +#include +#include +#include // for pair<> +#include "ControlGroups.h" +#include "util/Path.h" +#include "PortController.h" + +using std::vector; using std::string; using std::pair; +using std::cerr; using std::cout; using std::endl; + +namespace LibOmClient { +class PortModel; +class NodeModel; +} +using namespace LibOmClient; +using Om::Path; + +namespace OmGtk { + +class NodeController; +class PortController; + + +/** A group of controls for a node (or patch). + * + * Used by both NodeControlWindow and the main window (for patch controls). + * + * \ingroup OmGtk + */ +class ControlPanel : public Gtk::VBox { +public: + ControlPanel(BaseObjectType* cobject, const Glib::RefPtr& glade_xml); + virtual ~ControlPanel(); + + void init(NodeController* node, size_t poly); + + ControlGroup* find_port(const Path& path) const; + + void add_port(PortController* port); + void remove_port(const Path& path); + + void rename_port(const Path& old_path, const Path& new_path); + + void enable_port(const Path& path); + void disable_port(const Path& path); + + size_t num_controls() const { return m_controls.size(); } + pair ideal_size() const { return m_ideal_size; } + + // Callback for ControlGroup + void value_changed(const Path& port_path, float val); + + inline void set_control(const Path& port_path, float value); + void set_range_min(const Path& port_path, float value); + void set_range_max(const Path& port_path, float value); + +private: + void all_voices_selected(); + void specific_voice_selected(); + void voice_selected(); + + bool m_callback_enabled; + + pair m_ideal_size; + + vector m_controls; + Gtk::VBox* m_control_box; + Gtk::Box* m_voice_control_box; + Gtk::RadioButton* m_all_voices_radio; + Gtk::RadioButton* m_specific_voice_radio; + Gtk::SpinButton* m_voice_spinbutton; +}; + + +/** Set a port on this panel to a certain value. + * + * Profiling has shown this is performance critical. Needs to be made + * faster. + */ +inline void +ControlPanel::set_control(const Path& port_path, const float val) +{ + // FIXME: double lookup, ports should just have a pointer directly to + // their control group + + m_callback_enabled = false; + ControlGroup* cg = NULL; + + for (vector::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + cg = (*i); + if (cg->port_model()->path() == port_path) { + cg->set_value(val); + m_callback_enabled = true; + return; + } + } + + cerr << "[ControlPanel::set_control] Unable to find control " << port_path << endl; + m_callback_enabled = true; +} + + +} // namespace OmGtk + +#endif // CONTROLPANEL_H diff --git a/src/progs/gtk/Controller.cpp b/src/progs/gtk/Controller.cpp new file mode 100644 index 00000000..05ebe84a --- /dev/null +++ b/src/progs/gtk/Controller.cpp @@ -0,0 +1,173 @@ +/* This file is part of Om. Copyright (C) 2006 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 "PatchModel.h" +#include "PatchController.h" +#include "ControlInterface.h" +#include "OSCModelEngineInterface.h" +#include "OSCListener.h" +//#include "GtkClientInterface.h" +#include "PatchLibrarian.h" +#include "Controller.h" +#include "Loader.h" +#include "interface/ClientKey.h" + +namespace OmGtk { + + +Controller::Controller(const string& engine_url) +: OSCModelEngineInterface(engine_url), + m_patch_librarian(new PatchLibrarian(this)), + m_loader(new Loader(m_patch_librarian)) +{ + m_loader->launch(); +} + + +Controller::~Controller() +{ + if (is_attached()) { + unregister_client(ClientKey()); // FIXME + detach(); + } + + delete m_loader; + delete m_patch_librarian; +} + + +/** "Attach" to the Om engine. + * See documentation OSCModelEngineInterface::attach. + */ +void +Controller::attach() +{ + OSCModelEngineInterface::attach(false); +} + +/* +void +Controller::register_client_and_wait() +{ +// int id = get_next_request_id(); +// set_wait_response_id(id); + OSCModelEngineInterface::register_client(); +// wait_for_response(); + cout << "[Controller] Registered with engine. maybe. fixme." << endl; +} +*/ +void Controller::set_engine_url(const string& url) { _engine_url = url; } + +void +Controller::create_node_from_model(const NodeModel* nm) +{ + //push_added_node(nm); + OSCModelEngineInterface::create_node_from_model(nm); + char temp_buf[16]; + snprintf(temp_buf, 16, "%f", nm->x()); + set_metadata(nm->path(), "module-x", temp_buf); + snprintf(temp_buf, 16, "%f", nm->y()); + set_metadata(nm->path(), "module-y", temp_buf); +} + +void +Controller::create_patch_from_model(const PatchModel* pm) +{ + //push_added_patch(pm); + + //int id = get_next_request_id(); + //set_wait_response_id(id); + create_patch_from_model(pm); + if (pm->parent() != NULL) { + // wait_for_response(); + char temp_buf[16]; + snprintf(temp_buf, 16, "%f", pm->x()); + set_metadata(pm->path(), "module-x", temp_buf); + snprintf(temp_buf, 16, "%f", pm->y()); + set_metadata(pm->path(), "module-y", temp_buf); + } + enable_patch(pm->path()); +} + + +void +Controller::set_patch_path(const string& path) +{ + m_patch_librarian->path(path); +} + + +/** Load patch in a seperate thread. + * This will return immediately and the patch will be loaded in the background. + * FIXME: merge parameter makes no sense, always true */ +void +Controller::load_patch(PatchModel* model, bool wait, bool merge) +{ + //push_added_patch(model); + m_loader->load_patch(model, wait, merge); +} + + +/** Load patch in a seperate thread. + * This will return immediately and the patch will be saved in the background. */ +void +Controller::save_patch(PatchModel* model, const string& filename, bool recursive) +{ + m_loader->save_patch(model, filename, recursive); +} + + +#if 0 +/** Returns the added node with the given path and removes it from the cache. + */ +NodeModel* +Controller::yank_added_node(const string& path) +{ + NodeModel* nm = NULL; + + for (list::iterator i = m_added_nodes.begin(); i != m_added_nodes.end(); ++i) { + if ((*i)->path() == path) { + nm = *i; + m_added_nodes.erase(i); + break; + } + } + + return nm; +} + + +/** Returns the added patch with the given path and removes it from the cache. + */ +PatchModel* +Controller::yank_added_patch(const string& path) +{ + PatchModel* pm = NULL; + + for (list::iterator i = m_added_patches.begin(); i != m_added_patches.end(); ++i) { + if ((*i)->path() == path) { + pm = *i; + m_added_patches.erase(i); + break; + } + } + + return pm; +} +#endif + +} // namespace OmGtk + diff --git a/src/progs/gtk/Controller.h b/src/progs/gtk/Controller.h new file mode 100644 index 00000000..fd516992 --- /dev/null +++ b/src/progs/gtk/Controller.h @@ -0,0 +1,112 @@ +/* This file is part of Om. Copyright (C) 2006 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 CONTROLLER_H +#define CONTROLLER_H + +#include +#include +#include +#include +#include "PluginModel.h" +#include "OSCModelEngineInterface.h" + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PatchLibrarian; +} + +using std::string; using std::list; +using namespace LibOmClient; + +namespace OmGtk { + +class PatchController; +//class GtkClientInterface; +class Loader; + + +/** Singleton engine controller for the entire app. + * + * This is hardly more than a trivial wrapper for OSCModelEngineInterface, suggesting something + * needs a rethink around here.. + * + * This needs to be either eliminated or the name changed to OmController. Probably + * best to keep around in case multiple engine control support comes around? + * + * \ingroup OmGtk + */ +class Controller : public OSCModelEngineInterface +{ +public: + ~Controller(); + + void attach(); + + //void register_client_and_wait(); + + void set_engine_url(const string& url); + + void create_node_from_model(const NodeModel* nm); + + void load_patch(PatchModel* model, bool wait = true, bool merge = false); + void save_patch(PatchModel* model, const string& filename, bool recursive); + + void create_patch_from_model(const PatchModel* pm); + + //void lash_restore_finished(); + + void set_patch_path(const string& path); + + /* + void push_added_node(NodeModel* nm) { m_added_nodes.push_back(nm); } + NodeModel* yank_added_node(const string& path); + + void push_added_patch(PatchModel* pm) { m_added_patches.push_back(pm); } + PatchModel* yank_added_patch(const string& path); + */ + //GtkClientInterface* client_hooks() { return (GtkClientInterface*)m_client_hooks; } + + static void instantiate(const string& engine_url) + { if (!_instance) _instance = new Controller(engine_url); } + + inline static Controller& instance() { assert(_instance); return *_instance; } + +private: + Controller(const string& engine_url); + static Controller* _instance; + + PatchLibrarian* m_patch_librarian; + Loader* m_loader; + + /** Used to cache added nodes so client can remember some values when the + * new node notification comes (location, etc). Used to prevent the node + * jumping locations during the delay between new node and the module-x/y + * metadata notifications */ + //list m_added_nodes; + + /** Used to cache added patches in the same was as m_added_nodes. Used to + * rember filename so File->Save can work without prompting (filename can't + * be sent to the server as metadata, because a client on another machine + * doesn't want that information) */ + //list m_added_patches; +}; + + +} // namespace OmGtk + +#endif // CONTROLLER_H diff --git a/src/progs/gtk/DSSIController.cpp b/src/progs/gtk/DSSIController.cpp new file mode 100644 index 00000000..570211c7 --- /dev/null +++ b/src/progs/gtk/DSSIController.cpp @@ -0,0 +1,280 @@ +/* This file is part of Om. Copyright (C) 2006 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 "DSSIController.h" +#include +#include +#include +#include +#include +#include "NodeModel.h" +#include "DSSIModule.h" +#include "Controller.h" + +namespace OmGtk { + + +DSSIController::DSSIController(NodeModel* model) +: NodeController(model), + m_banks_dirty(true) +{ + assert(model->plugin()->type() == PluginModel::DSSI); + Gtk::Menu::MenuList& items = m_menu.items(); + items[0].property_sensitive() = true; // "Show Control Window" item + + Gtk::Menu_Helpers::MenuElem program_elem("Select Program", m_program_menu); + items.push_front(program_elem); + m_program_menu_item = program_elem.get_child(); + m_program_menu_item->set_sensitive(false); + + items.push_front(Gtk::Menu_Helpers::MenuElem("Show Plugin GUI", + sigc::mem_fun(this, &DSSIController::show_gui))); +} + +void +DSSIController::program_add(int bank, int program, const string& name) +{ + node_model()->add_program(bank, program, name); + m_banks_dirty = true; +} + + +void +DSSIController::program_remove(int bank, int program) +{ + node_model()->remove_program(bank, program); + m_banks_dirty = true; +} + +/** Trivial wrapper of attempt_to_show_gui for libsigc + */ +void +DSSIController::show_gui() +{ + attempt_to_show_gui(); +} + + +void +DSSIController::update_program_menu() +{ + m_program_menu.items().clear(); + + const map >& banks = node_model()->get_programs(); + std::ostringstream oss; + + map >::const_iterator i; + for (i = banks.begin(); i != banks.end(); ++i) { + Gtk::Menu* bank_menu; + if (banks.size() > 1) + bank_menu = manage(new Gtk::Menu()); + else + bank_menu = &m_program_menu; + map::const_iterator j; + for (j = i->second.begin(); j != i->second.end(); ++j) { + oss.str(""); + oss << std::setw(3) << std::setfill('0') + << j->first << ' ' << j->second; + sigc::slot slt = bind( + bind(sigc::mem_fun(*this, &DSSIController::send_program_change), + j->first), i->first); + bank_menu->items().push_back( + Gtk::Menu_Helpers::MenuElem(oss.str(), slt)); + } + if (banks.size() > 1) { + oss.str(""); + oss << "Bank " << i->first; + m_program_menu.items().push_back( + Gtk::Menu_Helpers::MenuElem(oss.str(), *bank_menu)); + } + } + + // Disable the program menu if there are no programs + if (banks.size() == 0) + m_program_menu_item->set_sensitive(false); + else + m_program_menu_item->set_sensitive(true); + + m_banks_dirty = false; +} + + +void +DSSIController::send_program_change(int bank, int program) +{ + Controller::instance().set_program(node_model()->path(), bank, program); +} + + +void +DSSIController::create_module(OmFlowCanvas* canvas) +{ + //cerr << "Creating DSSI module " << m_model->path() << endl; + + assert(canvas != NULL); + assert(m_module == NULL); + + m_module = new DSSIModule(canvas, this); + create_all_ports(); + + m_module->move_to(node_model()->x(), node_model()->y()); +} + + + +/** Attempt to show the DSSI GUI for this plugin. + * + * Returns whether or not GUI was successfully loaded/shown. + */ +bool +DSSIController::attempt_to_show_gui() +{ + // Shamelessley "inspired by" jack-dssi-host + // Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + + const bool verbose = false; + + string engine_url = Controller::instance().engine_url(); + // Hack off last character if it's a / + if (engine_url[engine_url.length()-1] == '/') + engine_url = engine_url.substr(0, engine_url.length()-1); + + const char* dllName = node_model()->plugin()->lib_name().c_str(); + const char* label = node_model()->plugin()->plug_label().c_str(); + const char* myName = "om_gtk"; + const string& oscUrl = engine_url + "/dssi" + node_model()->path(); + + struct dirent* entry = NULL; + char* dllBase = strdup(dllName); + char* subpath = NULL; + DIR* subdir = NULL; + char* filename = NULL; + struct stat buf; + int fuzzy = 0; + + char* env_dssi_path = getenv("DSSI_PATH"); + string dssi_path; + if (!env_dssi_path) { + cerr << "DSSI_PATH is empty. Assuming /usr/lib/dssi:/usr/local/lib/dssi." << endl; + dssi_path = "/usr/lib/dssi:/usr/local/lib/dssi"; + } else { + dssi_path = env_dssi_path; + } + + if (strlen(dllBase) > 3 && !strcasecmp(dllBase + strlen(dllBase) - 3, ".so")) { + dllBase[strlen(dllBase) - 3] = '\0'; + } + + + // This is pretty nasty, it loops through the path, even if the dllBase is absolute + while (dssi_path != "") { + string directory = dssi_path.substr(0, dssi_path.find(':')); + if (dssi_path.find(':') != string::npos) + dssi_path = dssi_path.substr(dssi_path.find(':')+1); + else + dssi_path = ""; + + if (*dllBase == '/') { + subpath = strdup(dllBase); + } else { + subpath = (char*)malloc(strlen(directory.c_str()) + strlen(dllBase) + 2); + sprintf(subpath, "%s/%s", directory.c_str(), dllBase); + } + + for (fuzzy = 0; fuzzy <= 1; ++fuzzy) { + + if (!(subdir = opendir(subpath))) { + if (verbose) { + fprintf(stderr, "%s: can't open plugin GUI directory \"%s\"\n", myName, subpath); + } + break; + } + + while ((entry = readdir(subdir))) { + + if (entry->d_name[0] == '.') + continue; + if (!strchr(entry->d_name, '_')) + continue; + + if (fuzzy) { + if (verbose) { + fprintf(stderr, "checking %s against %s\n", entry->d_name, dllBase); + } + if (strncmp(entry->d_name, dllBase, strlen(dllBase))) + continue; + } else { + if (verbose) { + fprintf(stderr, "checking %s against %s\n", entry->d_name, label); + } + if (strncmp(entry->d_name, label, strlen(label))) + continue; + } + + filename = (char*)malloc(strlen(subpath) + strlen(entry->d_name) + 2); + sprintf(filename, "%s/%s", subpath, entry->d_name); + + if (stat(filename, &buf)) { + perror("stat failed"); + free(filename); + continue; + } + + if ((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) && + (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { + + if (verbose) { + fprintf(stderr, "%s: trying to execute GUI at \"%s\"\n", + myName, filename); + } + + if (fork() == 0) { + execlp(filename, filename, oscUrl.c_str(), dllName, label, + node_model()->name().c_str(), 0); + perror("exec failed"); + exit(1); + } + + free(filename); + free(subpath); + free(dllBase); + return true; + } + + free(filename); + } + } + } + + cerr << "Unable to launch DSSI GUI for " << node_model()->path() << endl; + + free(subpath); + free(dllBase); + return false; +} + + +void +DSSIController::show_menu(GdkEventButton* event) +{ + if (m_banks_dirty) + update_program_menu(); + NodeController::show_menu(event); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/DSSIController.h b/src/progs/gtk/DSSIController.h new file mode 100644 index 00000000..53f6fc8b --- /dev/null +++ b/src/progs/gtk/DSSIController.h @@ -0,0 +1,79 @@ +/* This file is part of Om. Copyright (C) 2006 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 DSSICONTROLLER_H +#define DSSICONTROLLER_H + +#include +#include +#include "util/Path.h" +#include "NodeController.h" + +using std::string; +using Om::Path; +using namespace LibOmClient; + +namespace LibOmClient { + class MetadataModel; + class NodeModel; + class PortModel; +} + +namespace OmGtk { + +class Controller; +class OmModule; +class NodeControlWindow; +class NodePropertiesWindow; +class PortController; +class OmFlowCanvas; +class DSSIModule; + +/* Controller for a DSSI node. + * + * \ingroup OmGtk + */ +class DSSIController : public NodeController +{ +public: + DSSIController(NodeModel* model); + + virtual ~DSSIController() {} + + void show_gui(); + bool attempt_to_show_gui(); + void program_add(int bank, int program, const string& name); + void program_remove(int bank, int program); + + void send_program_change(int bank, int program); + + void create_module(OmFlowCanvas* canvas); + + void show_menu(GdkEventButton* event); + +private: + void update_program_menu(); + + Gtk::Menu m_program_menu; + Glib::RefPtr m_program_menu_item; + + bool m_banks_dirty; +}; + + +} // namespace OmGtk + +#endif // DSSICONTROLLER_H diff --git a/src/progs/gtk/DSSIModule.cpp b/src/progs/gtk/DSSIModule.cpp new file mode 100644 index 00000000..7dae48ac --- /dev/null +++ b/src/progs/gtk/DSSIModule.cpp @@ -0,0 +1,38 @@ +/* This file is part of Om. Copyright (C) 2006 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 "DSSIModule.h" +#include "DSSIController.h" + +namespace OmGtk { + + +DSSIModule::DSSIModule(OmFlowCanvas* canvas, DSSIController* node) +: OmModule(canvas, static_cast(node)) +{ +} + + +void +DSSIModule::on_double_click(GdkEventButton* ev) +{ + DSSIController* const dc = static_cast(m_node); + if (!dc->attempt_to_show_gui()) + show_control_window(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/DSSIModule.h b/src/progs/gtk/DSSIModule.h new file mode 100644 index 00000000..2ad10c04 --- /dev/null +++ b/src/progs/gtk/DSSIModule.h @@ -0,0 +1,43 @@ +/* This file is part of Om. Copyright (C) 2006 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 DSSIMODULE_H +#define DSSIMODULE_H + +#include "OmModule.h" + +namespace OmGtk { + +class DSSIController; + +/* Module for a DSSI node. + * + * \ingroup OmGtk + */ +class DSSIModule : public OmModule +{ +public: + DSSIModule(OmFlowCanvas* canvas, DSSIController* node); + virtual ~DSSIModule() {} + + void on_double_click(GdkEventButton* ev); +}; + + +} // namespace OmGtk + +#endif // DSSIMODULE_H + diff --git a/src/progs/gtk/GladeFactory.cpp b/src/progs/gtk/GladeFactory.cpp new file mode 100644 index 00000000..e930c4c4 --- /dev/null +++ b/src/progs/gtk/GladeFactory.cpp @@ -0,0 +1,69 @@ +/* This file is part of Om. Copyright (C) 2006 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 "GladeFactory.h" +#include +#include +using std::cout; using std::cerr; using std::endl; +using std::ifstream; + +namespace OmGtk { + + +Glib::ustring GladeFactory::glade_filename = ""; + + +void +GladeFactory::find_glade_file() +{ + // Check for the .glade file in current directory + glade_filename = "./om_gtk.glade"; + ifstream fs(glade_filename.c_str()); + if (fs.fail()) { // didn't find it, check PKGDATADIR + fs.clear(); + glade_filename = PKGDATADIR; + glade_filename += "/om_gtk.glade"; + + fs.open(glade_filename.c_str()); + if (fs.fail()) { + cerr << "[GladeFactory] Unable to find om_gtk.glade in current directory or " << PKGDATADIR << "." << endl; + throw; + } + fs.close(); + } + cerr << "[GladeFactory] Loading widgets from " << glade_filename.c_str() << endl; +} + + +Glib::RefPtr +GladeFactory::new_glade_reference(const string& toplevel_widget) +{ + if (glade_filename == "") + find_glade_file(); + + try { + if (toplevel_widget == "") + return Gnome::Glade::Xml::create(glade_filename); + else + return Gnome::Glade::Xml::create(glade_filename, toplevel_widget.c_str()); + } catch (const Gnome::Glade::XmlError& ex) { + cerr << ex.what() << endl; + throw ex; + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/GladeFactory.h b/src/progs/gtk/GladeFactory.h new file mode 100644 index 00000000..a3ee1022 --- /dev/null +++ b/src/progs/gtk/GladeFactory.h @@ -0,0 +1,48 @@ +/* This file is part of Om. Copyright (C) 2006 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 GLADEFACTORY_H +#define GLADEFACTORY_H + +#include +#include + +using std::string; + +namespace OmGtk { + + +/** Creates glade references, so various objects can create widgets. + * Purely static. + * + * \ingroup OmGtk + */ +class GladeFactory { +public: + static Glib::RefPtr + new_glade_reference(const string& toplevel_widget = ""); + +private: + GladeFactory() {} + + static void find_glade_file(); + static Glib::ustring glade_filename; +}; + + +} // namespace OmGtk + +#endif // GLADEFACTORY_H diff --git a/src/progs/gtk/GtkClientInterface.cpp b/src/progs/gtk/GtkClientInterface.cpp new file mode 100644 index 00000000..7bda1e9e --- /dev/null +++ b/src/progs/gtk/GtkClientInterface.cpp @@ -0,0 +1,81 @@ +/* This file is part of Om. Copyright (C) 2006 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 "GtkClientInterface.h" +#include +#include +#include +#include +#include +#include "ControlInterface.h" + +namespace OmGtk { + + +GtkClientInterface::GtkClientInterface(ControlInterface* interface, int client_port) +: OSCListener(client_port) +, ModelClientInterface() +, _interface(interface) +, _num_plugins(0) +, _events(4096) +{ +} + + +/** Push an event (from the engine, ie 'new patch') on to the queue. + */ +void +GtkClientInterface::push_event(Closure ev) +{ + bool success = false; + bool first = true; + + // (Very) slow busy-wait if the queue is full + // FIXME: Make this wait on a signal from process_events iff this happens + while (!success) { + success = _events.push(ev); + if (!success) { + if (first) { + cerr << "[GtkClientInterface] WARNING: (Client) event queue full. Waiting to try again..." << endl; + first = false; + } + usleep(200000); // 100 milliseconds (2* rate process_events is called) + } + } +} + + +/** Process all queued events that came from the OSC thread. + * + * This function is to be called from the Gtk thread only. + */ +bool +GtkClientInterface::process_events() +{ + // Process a maximum of queue-size events, to prevent locking the GTK + // thread indefinitely while processing continually arriving events + size_t num_processed = 0; + while (!_events.is_empty() && num_processed++ < _events.capacity()/2) { + Closure& ev = _events.pop(); + ev(); + ev.disconnect(); + } + + return true; +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/GtkClientInterface.h b/src/progs/gtk/GtkClientInterface.h new file mode 100644 index 00000000..7214ef19 --- /dev/null +++ b/src/progs/gtk/GtkClientInterface.h @@ -0,0 +1,156 @@ +/* This file is part of Om. Copyright (C) 2006 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 GTKCLIENTHOOKS_H +#define GTKCLIENTHOOKS_H + +#include +#include +#include +#include +#include +#include "ControlInterface.h" +#include "OSCListener.h" +#include "util/Queue.h" +#include "util/CountedPtr.h" +#include "ModelClientInterface.h" +#include "SigClientInterface.h" +using std::string; +using std::cerr; using std::endl; + +namespace LibOmClient { class PluginModel; } +using namespace LibOmClient; + +namespace OmGtk { + +/** Returns nothing and takes no parameters (because they have been bound) */ +typedef sigc::slot Closure; + +#if 0 +/** ModelClientInterface implementation for the Gtk client. + * + * This is a threadsafe interface to OmGtk. It provides the same interface as + * @ref ControlInterface, except all public functions may be called in a thread + * other than the GTK thread (a closure will be created and pushed through a + * queue for the GTK thread to execute). + * + * It is also a ModelClientInterface, which is how it is driven by the engine. + * This is redundant, "ControlInterface" needs to go away. A model database + * that wraps a ClientInterface and emits sigc signals when things change would + * be a much better way of doing this. + * + * \ingroup OmGtk + */ +class GtkClientInterface : public OSCListener, public ModelClientInterface +{ +public: + GtkClientInterface(ControlInterface* interface, int client_port); + + void set_ignore_port(const string& path) { _ignore_port_path = path; } + void clear_ignore_port() { _ignore_port_path = ""; } + + // FIXME: ugly accessor + size_t num_plugins() const { return _num_plugins; } + + // OSC thread functions (deferred calls) + + void bundle_begin() {} + void bundle_end() {} + + void num_plugins(size_t num) { _num_plugins = num; } + + void error(const string& msg) + { push_event(sigc::bind(_interface->error_slot, msg)); } + + void new_plugin_model(PluginModel* const pm) + { push_event(sigc::bind(_interface->new_plugin_slot, pm)); } + + void new_patch_model(PatchModel* const pm) + { push_event(sigc::bind(_interface->new_patch_slot, pm)); } + + void new_node_model(NodeModel* const nm) + { assert(nm); push_event(sigc::bind(_interface->new_node_slot, nm)); } + + void new_port_model(PortModel* const pm) + { push_event(sigc::bind(_interface->new_port_slot, pm)); } + + void connection_model(ConnectionModel* const cm) + { push_event(sigc::bind(_interface->connection_slot, cm)); } + + void object_destroyed(const string& path) + { push_event(sigc::bind(_interface->object_destroyed_slot, path)); } + + void patch_enabled(const string& path) + { push_event(sigc::bind(_interface->patch_enabled_slot, path)); } + + void patch_disabled(const string& path) + { push_event(sigc::bind(_interface->patch_disabled_slot, path)); } + + void patch_cleared(const string& path) + { push_event(sigc::bind(_interface->patch_cleared_slot, path)); } + + void object_renamed(const string& old_path, const string& new_path) + { push_event(sigc::bind(_interface->object_renamed_slot, old_path, new_path)); } + + void disconnection(const string& src_port_path, const string& dst_port_path) + { push_event(sigc::bind(_interface->disconnection_slot, src_port_path, dst_port_path)); } + + void metadata_update(const string& path, const string& key, const string& value) + { push_event(sigc::bind(_interface->metadata_update_slot, path, key, value)); } + + void control_change(const string& port_path, float value) + { push_event(sigc::bind(_interface->control_change_slot, port_path, value)); } + + void program_add(const string& path, uint32_t bank, uint32_t program, const string& name) + { push_event(sigc::bind(_interface->program_add_slot, path, bank, program, name)); } + + void program_remove(const string& path, uint32_t bank, uint32_t program) + { push_event(sigc::bind(_interface->program_remove_slot, path, bank, program)); } + + /** Process all queued events - MUST be called from Gtk thread. + * Registered as a GTK idle handler by App. */ + bool process_events(); + + static void instantiate(ControlInterface* interface, int client_port) + { if (!_instance) _instance = new GtkClientInterface(interface, client_port); } + + inline static CountedPtr instance() + { assert(_instance); return _instance; } + +private: + + static CountedPtr _instance; + + /** Provides the functions/slots the closures will actually call in the GTK thread */ + ControlInterface* _interface; + + size_t _num_plugins; + + void push_event(Closure ev); + + /** Set if a port slider is grabbed and is being dragged. + * If a control event comes in for a port with this path, we'll just + * ignore it outright. (Just an optimization over doing all the searching + * for the port slider just to ignore the event) */ + string _ignore_port_path; + + Queue _events; +}; +#endif + +} // namespace OmGtk + +#endif // GTKCLIENTHOOKS_H diff --git a/src/progs/gtk/GtkObjectController.cpp b/src/progs/gtk/GtkObjectController.cpp new file mode 100644 index 00000000..7277d346 --- /dev/null +++ b/src/progs/gtk/GtkObjectController.cpp @@ -0,0 +1,40 @@ +/* This file is part of Om. Copyright (C) 2006 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 "GtkObjectController.h" + +namespace OmGtk { + + +GtkObjectController::GtkObjectController(ObjectModel* model) +: m_model(model) +{ + assert(m_model != NULL); +} + + +/** Derived classes should override this to handle special metadata + * keys, then call this to set the model's metadata key. + */ +void +GtkObjectController::metadata_update(const string& key, const string& value) +{ + m_model->set_metadata(key, value); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/GtkObjectController.h b/src/progs/gtk/GtkObjectController.h new file mode 100644 index 00000000..4a09b9c7 --- /dev/null +++ b/src/progs/gtk/GtkObjectController.h @@ -0,0 +1,77 @@ +/* This file is part of Om. Copyright (C) 2006 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 GTKOBJECTCONTROLLER_H +#define GTKOBJECTCONTROLLER_H + +#include +#include + +#include "ObjectModel.h" +#include "ObjectController.h" + + +using std::string; + +using namespace LibOmClient; + +namespace OmGtk { + +class Controller; + + +/** Controller for an Om object. + * + * Management of the model and view are this object's responsibility. + * The view may not be created (ie in the case of patches which have never + * been shown and all their children). + * + * \ingroup OmGtk + */ +class GtkObjectController : public LibOmClient::ObjectController +{ +public: + GtkObjectController(ObjectModel* model); + virtual ~GtkObjectController() {} + + /** Destroy object. + * + * Object must be safe to delete immediately following the return of + * this call. + */ + virtual void destroy() = 0; + + virtual void add_to_store() = 0; + virtual void remove_from_store() = 0; + + virtual void metadata_update(const string& key, const string& value); + + /** Rename object */ + virtual void set_path(const Path& new_path) + { m_model->set_path(new_path); } + + const Path& path() const { return m_model->path(); } + + ObjectModel* model() const { return m_model; } + +protected: + ObjectModel* m_model; ///< Model for this object +}; + + +} // namespace OmGtk + +#endif // GTKOBJECTCONTROLLER_H diff --git a/src/progs/gtk/LashController.cpp b/src/progs/gtk/LashController.cpp new file mode 100644 index 00000000..d95d8515 --- /dev/null +++ b/src/progs/gtk/LashController.cpp @@ -0,0 +1,168 @@ +/* This file is part of Om. Copyright (C) 2006 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 "LashController.h" +#include "config.h" +#include +#include +#include +#include +#include +#include "App.h" +#include "PatchController.h" +#include "PatchModel.h" + +using std::cerr; using std::cout; using std::endl; +using std::string; + +namespace OmGtk { + + +LashController::LashController(lash_args_t* args) +: m_client(NULL) +{ + m_client = lash_init(args, PACKAGE_NAME, + /*LASH_Config_Data_Set|*/LASH_Config_File, LASH_PROTOCOL(2, 0)); + if (m_client == NULL) { + cerr << "[LashController] Failed to connect to LASH. Session management will not function." << endl; + } else { + cout << "[LashController] Lash initialised" << endl; + } + + lash_event_t* event = lash_event_new_with_type(LASH_Client_Name); + lash_event_set_string(event, "OmGtk"); + lash_send_event(m_client, event); +} + + +LashController::~LashController() +{ + if (m_client != NULL) { + lash_event_t* quit_event = lash_event_new_with_type(LASH_Quit); + lash_send_event(m_client, quit_event); + } +} + + +void +LashController::process_events() +{ + assert(m_client != NULL); + + 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 +LashController::handle_event(lash_event_t* ev) +{ + assert(ev != NULL); + + 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; + + if (type == LASH_Save_File) { + cout << "[LashController] LASH Save File - " << str << endl; + save(str); + lash_send_event(m_client, lash_event_new_with_type(LASH_Save_File)); + } else if (type == LASH_Restore_File) { + cout << "[LashController] LASH Restore File - " << str << endl; + cerr << "LASH RESTORE NOT YET (RE)IMPLEMENTED." << endl; + /*_controller->load_session_blocking(str + "/session"); + _controller->lash_restore_finished(); + lash_send_event(m_client, lash_event_new_with_type(LASH_Restore_File)); + */ + /*} else if (type == LASH_Save_Data_Set) { + //cout << "[LashController] 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) { + cout << "[LashController] LASH Quit" << endl; + m_client = NULL; + App::instance().quit(); + } else { + cerr << "[LashController] Unhandled LASH event, type: " << static_cast(type) << endl; + } +} + + +void +LashController::handle_config(lash_config_t* conf) +{ + assert(conf != NULL); + + const char* key = NULL; + const void* val = NULL; + size_t val_size = 0; + + cout << "[LashController] 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); +} + +void +LashController::save(const string& dir) +{ + cerr << "LASH SAVING NOT YET (RE)IMPLEMENTED\n"; + /* + PatchController* pc = NULL; + + // Save every patch under dir with it's path as a filename + // (so the dir structure will resemble the patch heirarchy) + for (map::iterator i = m_app->patches().begin(); + i != m_app->patches().end(); ++i) { + pc = (*i).second; + pc->model()->filename(dir + pc->model()->path() + ".om"); + } + + // Create directories + for (map::iterator i = m_app->patches().begin(); + i != m_app->patches().end(); ++i) { + pc = (*i).second; + if (pc->model()->parent() != NULL) { + string path = OmPath::parent(pc->model()->path()).substr(1) + "/"; + while (path.find("/") != string::npos) { + mkdir(string(dir +"/"+ path.substr(0, path.find("/"))).c_str(), 0744); + path = path.substr(path.find("/")+1); + } + } + _controller->save_patch_blocking(pc->model(), pc->model()->filename(), false); + } + + //m_app->state_manager()->save(str + "/omgtkrc"); + _controller->save_session_blocking(dir + "/session"); + */ +} + +} // namespace OmGtk diff --git a/src/progs/gtk/LashController.h b/src/progs/gtk/LashController.h new file mode 100644 index 00000000..f61c9f7f --- /dev/null +++ b/src/progs/gtk/LashController.h @@ -0,0 +1,53 @@ +/* This file is part of OmGtk. Copyright (C) 2006 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 LASHCONTROLLER_H +#define LASHCONTROLLER_H + +#include +#include +using std::string; + +namespace OmGtk { + +class App; + +/* Old and unused LASH controller. + * + * \ingroup OmGtk + */ +class LashController +{ +public: + LashController(lash_args_t* args); + ~LashController(); + + bool enabled() { return lash_enabled(m_client); } + void process_events(); + +private: + void save(const string& dir); + + lash_client_t* m_client; + + void handle_event(lash_event_t* conf); + void handle_config(lash_config_t* conf); +}; + + +} // namespace OmGtk + +#endif // LASHCONTROLLER_H diff --git a/src/progs/gtk/LoadPatchWindow.cpp b/src/progs/gtk/LoadPatchWindow.cpp new file mode 100644 index 00000000..60f6e15f --- /dev/null +++ b/src/progs/gtk/LoadPatchWindow.cpp @@ -0,0 +1,131 @@ +/* This file is part of Om. Copyright (C) 2006 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 "LoadPatchWindow.h" +#include +#include +#include "App.h" +#include "Configuration.h" +#include "PatchController.h" +#include "PatchModel.h" +#include "Controller.h" + +namespace OmGtk { + + +LoadPatchWindow::LoadPatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::FileChooserDialog(cobject), + m_patch_controller(NULL), + m_replace(true) +{ + xml->get_widget("load_patch_poly_from_current_radio", m_poly_from_current_radio); + xml->get_widget("load_patch_poly_from_file_radio", m_poly_from_file_radio); + xml->get_widget("load_patch_poly_from_user_radio", m_poly_from_user_radio); + xml->get_widget("load_patch_poly_spinbutton", m_poly_spinbutton); + xml->get_widget("load_patch_ok_button", m_ok_button); + xml->get_widget("load_patch_cancel_button", m_cancel_button); + + m_poly_from_current_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_file_selected)); + m_poly_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_file_selected)); + m_poly_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_user_selected)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &LoadPatchWindow::ok_clicked)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &LoadPatchWindow::cancel_clicked)); + + m_poly_from_current_radio->set_active(true); + + Gtk::FileFilter filt; + filt.add_pattern("*.om"); + filt.set_name("Om patch files (*.om)"); + set_filter(filt); + + // Add global examples directory to "shortcut folders" (bookmarks) + string examples_dir = PKGDATADIR; + examples_dir.append("/patches"); + DIR* d = opendir(examples_dir.c_str()); + if (d != NULL) + add_shortcut_folder(examples_dir); +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +LoadPatchWindow::patch_controller(PatchController* pc) +{ + m_patch_controller = pc; +} + + +void +LoadPatchWindow::on_show() +{ + if (App::instance().configuration()->patch_folder().length() > 0) + set_current_folder(App::instance().configuration()->patch_folder()); + Gtk::FileChooserDialog::on_show(); +} + + +///// Event Handlers ////// + + +void +LoadPatchWindow::poly_from_file_selected() +{ + m_poly_spinbutton->property_sensitive() = false; +} + + +void +LoadPatchWindow::poly_from_user_selected() +{ + m_poly_spinbutton->property_sensitive() = true; +} + + +void +LoadPatchWindow::ok_clicked() +{ + // These values are interpreted by load_patch() as "not defined", ie load from file + string name = ""; + int poly = 0; + + if (m_poly_from_user_radio->get_active()) + poly = m_poly_spinbutton->get_value_as_int(); + + if (m_replace) + Controller::instance().clear_patch(m_patch_controller->model()->path()); + + PatchModel* pm = new PatchModel(m_patch_controller->model()->path(), poly); + pm->filename(get_filename()); + pm->set_metadata("filename", get_filename()); + pm->set_parent(m_patch_controller->patch_model()->parent()); + //Controller::instance().push_added_patch(pm); + Controller::instance().load_patch(pm, true, true); + + hide(); +} + + +void +LoadPatchWindow::cancel_clicked() +{ + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/LoadPatchWindow.h b/src/progs/gtk/LoadPatchWindow.h new file mode 100644 index 00000000..7d7093bd --- /dev/null +++ b/src/progs/gtk/LoadPatchWindow.h @@ -0,0 +1,73 @@ +/* This file is part of Om. Copyright (C) 2006 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 LOADPATCHWINDOW_H +#define LOADPATCHWINDOW_H + +#include "PluginModel.h" + +#include +#include + +namespace OmGtk { + +class PatchController; + + +/** 'Load Patch' window. + * + * Loaded by glade as a derived object. Used for both "Load" and "Load Into" + * operations (the radio button state should be changed with the provided + * methods prior to presenting this window). + * + * This is not for loading subpatches. See @a LoadSubpatchWindow for that. + * + * \ingroup OmGtk + */ +class LoadPatchWindow : public Gtk::FileChooserDialog +{ +public: + LoadPatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); + + void patch_controller(PatchController* pc); + + void set_replace() { m_replace = true; } + void set_merge() { m_replace = false; } + +protected: + void on_show(); + +private: + void poly_from_file_selected(); + void poly_from_user_selected(); + void ok_clicked(); + void cancel_clicked(); + + PatchController* m_patch_controller; + bool m_replace; + + Gtk::RadioButton* m_poly_from_current_radio; + Gtk::RadioButton* m_poly_from_file_radio; + Gtk::RadioButton* m_poly_from_user_radio; + Gtk::SpinButton* m_poly_spinbutton; + Gtk::Button* m_ok_button; + Gtk::Button* m_cancel_button; +}; + + +} // namespace OmGtk + +#endif // LOADPATCHWINDOW_H diff --git a/src/progs/gtk/LoadPluginWindow.cpp b/src/progs/gtk/LoadPluginWindow.cpp new file mode 100644 index 00000000..b84ae39e --- /dev/null +++ b/src/progs/gtk/LoadPluginWindow.cpp @@ -0,0 +1,407 @@ +/* This file is part of Om. Copyright (C) 2006 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 "LoadPluginWindow.h" +#include +#include +#include +#include +#include "PatchController.h" +#include "NodeModel.h" +#include "Controller.h" +#include "App.h" +#include "PatchWindow.h" +#include "OmFlowCanvas.h" +#include "PatchModel.h" +#include "Store.h" +using std::cout; using std::cerr; using std::endl; + + +namespace OmGtk { + +LoadPluginWindow::LoadPluginWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::Window(cobject), + m_patch_controller(NULL), + m_has_shown(false), + m_plugin_name_offset(0), + m_new_module_x(0), + m_new_module_y(0) +{ + xml->get_widget("load_plugin_plugins_treeview", m_plugins_treeview); + xml->get_widget("load_plugin_polyphonic_checkbutton", m_polyphonic_checkbutton); + xml->get_widget("load_plugin_name_entry", m_node_name_entry); + xml->get_widget("load_plugin_clear_button", m_clear_button); + xml->get_widget("load_plugin_add_button", m_add_button); + xml->get_widget("load_plugin_close_button", m_close_button); + //xml->get_widget("load_plugin_ok_button", m_ok_button); + + xml->get_widget("load_plugin_filter_combo", m_filter_combo); + xml->get_widget("load_plugin_search_entry", m_search_entry); + + // Set up the plugins list + m_plugins_liststore = Gtk::ListStore::create(m_plugins_columns); + m_plugins_treeview->set_model(m_plugins_liststore); + m_plugins_treeview->append_column("Name", m_plugins_columns.m_col_name); + m_plugins_treeview->append_column("Type", m_plugins_columns.m_col_type); + m_plugins_treeview->append_column("URI", m_plugins_columns.m_col_uri); + //m_plugins_treeview->append_column("Library", m_plugins_columns.m_col_library); + //m_plugins_treeview->append_column("Label", m_plugins_columns.m_col_label); + + // This could be nicer.. store the TreeViewColumns locally maybe? + m_plugins_treeview->get_column(0)->set_sort_column(m_plugins_columns.m_col_name); + m_plugins_treeview->get_column(1)->set_sort_column(m_plugins_columns.m_col_type); + m_plugins_treeview->get_column(2)->set_sort_column(m_plugins_columns.m_col_uri); + //m_plugins_treeview->get_column(3)->set_sort_column(m_plugins_columns.m_col_library); + //m_plugins_treeview->get_column(4)->set_sort_column(m_plugins_columns.m_col_label); + for (int i=0; i < 3; ++i) + m_plugins_treeview->get_column(i)->set_resizable(true); + + // Set up the search criteria combobox + m_criteria_liststore = Gtk::ListStore::create(m_criteria_columns); + m_filter_combo->set_model(m_criteria_liststore); + Gtk::TreeModel::iterator iter = m_criteria_liststore->append(); + Gtk::TreeModel::Row row = *iter; + row[m_criteria_columns.m_col_label] = "Name contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::NAME; + m_filter_combo->set_active(iter); + iter = m_criteria_liststore->append(); row = *iter; + row[m_criteria_columns.m_col_label] = "Type contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::TYPE; + iter = m_criteria_liststore->append(); row = *iter; + row[m_criteria_columns.m_col_label] = "URI contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::URI; + /*iter = m_criteria_liststore->append(); row = *iter; + row[m_criteria_columns.m_col_label] = "Library contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::LIBRARY; + iter = m_criteria_liststore->append(); row = *iter; + row[m_criteria_columns.m_col_label] = "Label contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::LABEL;*/ + + m_clear_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::clear_clicked)); + m_add_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::add_clicked)); + m_close_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::close_clicked)); + //m_ok_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::ok_clicked)); + m_plugins_treeview->signal_row_activated().connect(sigc::mem_fun(this, &LoadPluginWindow::plugin_activated)); + m_search_entry->signal_activate().connect( sigc::mem_fun(this, &LoadPluginWindow::add_clicked)); + m_search_entry->signal_changed().connect( sigc::mem_fun(this, &LoadPluginWindow::filter_changed)); + + m_selection = m_plugins_treeview->get_selection(); + m_selection->signal_changed().connect(sigc::mem_fun(this, &LoadPluginWindow::plugin_selection_changed)); + + //m_add_button->grab_default(); +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +LoadPluginWindow::patch_controller(PatchController* pc) +{ + m_patch_controller = pc; + + if (pc->patch_model()->poly() <= 1) + m_polyphonic_checkbutton->property_sensitive() = false; + else + m_polyphonic_checkbutton->property_sensitive() = true; + +} + + +/** Populates the plugin list on the first show. + * + * This is done here instead of construction time as the list population is + * really expensive and bogs down creation of a patch. This is especially + * important when many patch notifications are sent at one time from the + * engine. + */ +void +LoadPluginWindow::on_show() +{ + if (!m_has_shown) { + set_plugin_model(Store::instance().plugins()); + + // Center on patch window + int m_w, m_h; + get_size(m_w, m_h); + + int parent_x, parent_y, parent_w, parent_h; + m_patch_controller->window()->get_position(parent_x, parent_y); + m_patch_controller->window()->get_size(parent_w, parent_h); + + move(parent_x + parent_w/2 - m_w/2, parent_y + parent_h/2 - m_h/2); + + m_has_shown = true; + } + Gtk::Window::on_show(); +} + + +void +LoadPluginWindow::on_hide() +{ + m_new_module_x = 0; + m_new_module_y = 0; + Gtk::Window::on_hide(); +} + + +void +LoadPluginWindow::set_plugin_model(const std::map& m) +{ + m_plugins_liststore->clear(); + + const PluginModel* plugin = NULL; + for (std::map::const_iterator i = m.begin(); i != m.end(); ++i) { + plugin = (*i).second; + + Gtk::TreeModel::iterator iter = m_plugins_liststore->append(); + Gtk::TreeModel::Row row = *iter; + + row[m_plugins_columns.m_col_name] = plugin->name(); + //row[m_plugins_columns.m_col_label] = plugin->plug_label(); + row[m_plugins_columns.m_col_type] = plugin->type_string(); + row[m_plugins_columns.m_col_uri] = plugin->uri(); + row[m_plugins_columns.m_col_label] = plugin->name(); + //row[m_plugins_columns.m_col_library] = plugin->lib_name(); + row[m_plugins_columns.m_col_plugin_model] = plugin; + } + + m_plugins_treeview->columns_autosize(); +} + + +void +LoadPluginWindow::add_plugin(const PluginModel* const plugin) +{ + Gtk::TreeModel::iterator iter = m_plugins_liststore->append(); + Gtk::TreeModel::Row row = *iter; + + row[m_plugins_columns.m_col_name] = plugin->name(); + //row[m_plugins_columns.m_col_label] = plugin->plug_label(); + row[m_plugins_columns.m_col_type] = plugin->type_string(); + row[m_plugins_columns.m_col_uri] = plugin->uri(); + row[m_plugins_columns.m_col_label] = plugin->name(); + //row[m_plugins_columns.m_col_library] = plugin->lib_name(); + row[m_plugins_columns.m_col_plugin_model] = plugin; +} + + + +///// Event Handlers ////// + + +void +LoadPluginWindow::plugin_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* col) +{ + add_clicked(); +} + + +void +LoadPluginWindow::plugin_selection_changed() +{ + m_plugin_name_offset = 0; + + m_node_name_entry->set_text(generate_module_name()); + + //Gtk::TreeModel::iterator iter = m_selection->get_selected(); + //Gtk::TreeModel::Row row = *iter; + //const PluginModel* plugin = row.get_value(m_plugins_columns.m_col_plugin_model); +} + + +/** Generate an automatic name for this Node. + * + * Offset is an offset of the number that will be appended to the plugin's + * label, needed if the user adds multiple plugins faster than the engine + * sends the notification back. + */ +string +LoadPluginWindow::generate_module_name(int offset) +{ + string name = ""; + + Gtk::TreeModel::iterator iter = m_selection->get_selected(); + + if (iter) { + Gtk::TreeModel::Row row = *iter; + const PluginModel* const plugin = row.get_value(m_plugins_columns.m_col_plugin_model); + char num_buf[3]; + for (uint i=0; i < 99; ++i) { + name = plugin->plug_label(); + if (name == "") + name = plugin->name().substr(0, plugin->name().find(' ')); + if (i+offset != 0) { + snprintf(num_buf, 3, "%d", i+offset+1); + name += "_"; + name += num_buf; + } + if (m_patch_controller->patch_model()->get_node(name) == NULL) + break; + else + name = ""; + } + } + + return name; +} + + +void +LoadPluginWindow::add_clicked() +{ + Gtk::TreeModel::iterator iter = m_selection->get_selected(); + bool polyphonic = m_polyphonic_checkbutton->get_active(); + + if (iter) { // If anything is selected + Gtk::TreeModel::Row row = *iter; + const PluginModel* const plugin = row.get_value(m_plugins_columns.m_col_plugin_model); + string name = m_node_name_entry->get_text(); + if (name == "") { + name = generate_module_name(); + } + if (name == "") { + Gtk::MessageDialog dialog(*this, + "Unable to chose a default name for this node. Please enter a name.", + false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + + dialog.run(); + } else { + const string path = m_patch_controller->model()->base_path() + name; + NodeModel* nm = new NodeModel(path); + nm->plugin(plugin); + nm->polyphonic(polyphonic); + + if (m_new_module_x == 0 && m_new_module_y == 0) { + m_patch_controller->get_new_module_location( + m_new_module_x, m_new_module_y); + } + nm->x(m_new_module_x); + nm->y(m_new_module_y); + + Controller::instance().create_node_from_model(nm); + ++m_plugin_name_offset; + m_node_name_entry->set_text(generate_module_name(m_plugin_name_offset)); + + // Set the next module location 20 over, for a cascade effect + m_new_module_x += 20; + m_new_module_y += 20; + } + } +} + + +void +LoadPluginWindow::close_clicked() +{ + hide(); +} + + +/* +void +LoadPluginWindow::ok_clicked() +{ + add_clicked(); + close_clicked(); +} +*/ + +void +LoadPluginWindow::filter_changed() +{ + m_plugins_liststore->clear(); + + string search = m_search_entry->get_text(); + transform(search.begin(), search.end(), search.begin(), toupper); + + // Get selected criteria + const Gtk::TreeModel::Row row = *(m_filter_combo->get_active()); + CriteriaColumns::Criteria criteria = row[m_criteria_columns.m_col_criteria]; + + string field; + + Gtk::TreeModel::Row model_row; + Gtk::TreeModel::iterator model_iter; + size_t num_visible = 0; + + const PluginModel* plugin = NULL; + for (std::map::const_iterator i = Store::instance().plugins().begin(); + i != Store::instance().plugins().end(); ++i) { + plugin = (*i).second; + + switch (criteria) { + case CriteriaColumns::NAME: + field = plugin->name(); break; + case CriteriaColumns::TYPE: + field = plugin->type_string(); break; + case CriteriaColumns::URI: + field = plugin->uri(); break; + /*case CriteriaColumns::LIBRARY: + field = plugin->lib_name(); break; + case CriteriaColumns::LABEL: + field = plugin->plug_label(); break;*/ + default: + throw; + } + + transform(field.begin(), field.end(), field.begin(), toupper); + + if (field.find(search) != string::npos) { + model_iter = m_plugins_liststore->append(); + model_row = *model_iter; + + model_row[m_plugins_columns.m_col_name] = plugin->name(); + //model_row[m_plugins_columns.m_col_label] = plugin->plug_label(); + model_row[m_plugins_columns.m_col_type] = plugin->type_string(); + model_row[m_plugins_columns.m_col_uri] = plugin->uri(); + model_row[m_plugins_columns.m_col_label] = plugin->plug_label(); + //model_row[m_plugins_columns.m_col_library] = plugin->lib_name(); + model_row[m_plugins_columns.m_col_plugin_model] = plugin; + + ++num_visible; + } + } + + if (num_visible == 1) { + m_selection->unselect_all(); + m_selection->select(model_iter); + } +} + + +void +LoadPluginWindow::clear_clicked() +{ + m_search_entry->set_text(""); + set_plugin_model(Store::instance().plugins()); +} + +bool +LoadPluginWindow::on_key_press_event(GdkEventKey* event) +{ + if (event->keyval == GDK_w && event->state & GDK_CONTROL_MASK) { + hide(); + return true; + } else { + return Gtk::Window::on_key_press_event(event); + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/LoadPluginWindow.h b/src/progs/gtk/LoadPluginWindow.h new file mode 100644 index 00000000..adf11ab4 --- /dev/null +++ b/src/progs/gtk/LoadPluginWindow.h @@ -0,0 +1,145 @@ +/* This file is part of Om. Copyright (C) 2006 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 LOADPLUGINWINDOW_H +#define LOADPLUGINWINDOW_H + +#include "PluginModel.h" +#include +#include +#include +#include + + +using LibOmClient::PluginModel; + +namespace OmGtk { + +class PatchController; + +// Gtkmm _really_ needs to add some helper to abstract away this stupid nonsense + +/** Columns for the plugin list in the load plugin window. + * + * \ingroup OmGtk + */ +class ModelColumns : public Gtk::TreeModel::ColumnRecord +{ +public: + ModelColumns() { + add(m_col_name); + add(m_col_type); + add(m_col_uri); + add(m_col_label); + //add(m_col_library); + //add(m_col_label); + add(m_col_plugin_model); + } + + Gtk::TreeModelColumn m_col_name; + Gtk::TreeModelColumn m_col_type; + Gtk::TreeModelColumn m_col_uri; + + // Not displayed: + Gtk::TreeModelColumn m_col_label; + Gtk::TreeModelColumn m_col_plugin_model; +}; + + +/** Column for the criteria combo box in the load plugin window. + * + * \ingroup OmGtk + */ +class CriteriaColumns : public Gtk::TreeModel::ColumnRecord +{ +public: + enum Criteria { NAME, TYPE, URI, }; + + CriteriaColumns() { add(m_col_label); add(m_col_criteria); } + + Gtk::TreeModelColumn m_col_label; + Gtk::TreeModelColumn m_col_criteria; +}; + + +/** 'Load Plugin' window. + * + * Loaded by glade as a derived object. + * + * \ingroup OmGtk + */ +class LoadPluginWindow : public Gtk::Window +{ +public: + LoadPluginWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); + + void patch_controller(PatchController* pc); + void set_plugin_model(const std::map& m); + + void set_next_module_location(int x, int y) + { m_new_module_x = x; m_new_module_y = y; } + + void add_plugin(const PluginModel* info); + bool has_shown() const { return m_has_shown; } + +protected: + void on_show(); + void on_hide(); + bool on_key_press_event(GdkEventKey* event); + +private: + void add_clicked(); + void close_clicked(); + //void ok_clicked(); + void filter_changed(); + void clear_clicked(); + + void plugin_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* col); + void plugin_selection_changed(); + string generate_module_name(int offset = 0); + + PatchController* m_patch_controller; + bool m_has_shown; // plugin list only populated on show to speed patch window creation + + Glib::RefPtr m_plugins_liststore; + ModelColumns m_plugins_columns; + + Glib::RefPtr m_criteria_liststore; + CriteriaColumns m_criteria_columns; + + Glib::RefPtr m_selection; + + int m_plugin_name_offset; // see comments for generate_plugin_name + + int m_new_module_x; + int m_new_module_y; + + Gtk::TreeView* m_plugins_treeview; + Gtk::CheckButton* m_polyphonic_checkbutton; + Gtk::Entry* m_node_name_entry; + Gtk::Button* m_clear_button; + Gtk::Button* m_add_button; + Gtk::Button* m_close_button; + //Gtk::Button* m_ok_button; + Gtk::ComboBox* m_filter_combo; + Gtk::Entry* m_search_entry; +}; + + +} // namespace OmGtk + +#endif // LOADPLUGINWINDOW_H diff --git a/src/progs/gtk/LoadSubpatchWindow.cpp b/src/progs/gtk/LoadSubpatchWindow.cpp new file mode 100644 index 00000000..fe02d772 --- /dev/null +++ b/src/progs/gtk/LoadSubpatchWindow.cpp @@ -0,0 +1,177 @@ +/* This file is part of Om. Copyright (C) 2006 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 "LoadSubpatchWindow.h" +#include +#include +#include +#include "App.h" +#include "PatchController.h" +#include "NodeModel.h" +#include "Controller.h" +#include "PatchModel.h" +#include "Configuration.h" + +namespace OmGtk { + + +LoadSubpatchWindow::LoadSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::FileChooserDialog(cobject), + m_patch_controller(NULL), + m_new_module_x(0), + m_new_module_y(0) +{ + xml->get_widget("load_subpatch_name_from_file_radio", m_name_from_file_radio); + xml->get_widget("load_subpatch_name_from_user_radio", m_name_from_user_radio); + xml->get_widget("load_subpatch_name_entry", m_name_entry); + xml->get_widget("load_subpatch_poly_from_file_radio", m_poly_from_file_radio); + xml->get_widget("load_subpatch_poly_from_parent_radio", m_poly_from_parent_radio); + xml->get_widget("load_subpatch_poly_from_user_radio", m_poly_from_user_radio); + xml->get_widget("load_subpatch_poly_spinbutton", m_poly_spinbutton); + xml->get_widget("load_subpatch_ok_button", m_ok_button); + xml->get_widget("load_subpatch_cancel_button", m_cancel_button); + + m_name_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_name_entry)); + m_name_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::enable_name_entry)); + m_poly_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_poly_spinner)); + m_poly_from_parent_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_poly_spinner)); + m_poly_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::enable_poly_spinner)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &LoadSubpatchWindow::ok_clicked)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &LoadSubpatchWindow::cancel_clicked)); + + Gtk::FileFilter filt; + filt.add_pattern("*.om"); + filt.set_name("Om patch files (*.om)"); + set_filter(filt); + + // Add global examples directory to "shortcut folders" (bookmarks) + string examples_dir = PKGDATADIR; + examples_dir.append("/patches"); + DIR* d = opendir(examples_dir.c_str()); + if (d != NULL) + add_shortcut_folder(examples_dir); +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +LoadSubpatchWindow::patch_controller(PatchController* pc) +{ + m_patch_controller = pc; + + char temp_buf[4]; + snprintf(temp_buf, 4, "%zd", pc->patch_model()->poly()); + Glib::ustring txt = "Same as parent ("; + txt.append(temp_buf).append(")"); + m_poly_from_parent_radio->set_label(txt); +} + + +void +LoadSubpatchWindow::on_show() +{ + if (App::instance().configuration()->patch_folder().length() > 0) + set_current_folder(App::instance().configuration()->patch_folder()); + Gtk::FileChooserDialog::on_show(); +} + + +///// Event Handlers ////// + + + +void +LoadSubpatchWindow::disable_name_entry() +{ + m_name_entry->property_sensitive() = false; +} + + +void +LoadSubpatchWindow::enable_name_entry() +{ + m_name_entry->property_sensitive() = true; +} + + +void +LoadSubpatchWindow::disable_poly_spinner() +{ + m_poly_spinbutton->property_sensitive() = false; +} + + +void +LoadSubpatchWindow::enable_poly_spinner() +{ + m_poly_spinbutton->property_sensitive() = true; +} + + +void +LoadSubpatchWindow::ok_clicked() +{ + assert(m_patch_controller != NULL); + assert(m_patch_controller->model() != NULL); + + // These values are interpreted by load_patch() as "not defined", ie load from file + string name = ""; + int poly = 0; + + if (m_name_from_user_radio->get_active()) + name = m_name_entry->get_text(); + + if (m_poly_from_user_radio->get_active()) + poly = m_poly_spinbutton->get_value_as_int(); + else if (m_poly_from_parent_radio->get_active()) + poly = m_patch_controller->patch_model()->poly(); + + if (m_new_module_x == 0 && m_new_module_y == 0) { + m_patch_controller->get_new_module_location( + m_new_module_x, m_new_module_y); + } + + PatchModel* pm = new PatchModel(m_patch_controller->model()->base_path() + name, poly); + pm->filename(get_filename()); + pm->set_parent(m_patch_controller->model()); + pm->x(m_new_module_x); + pm->y(m_new_module_y); + if (name == "") + pm->set_path(""); + char temp_buf[16]; + snprintf(temp_buf, 16, "%d", m_new_module_x); + pm->set_metadata("module-x", temp_buf); + snprintf(temp_buf, 16, "%d", m_new_module_y); + pm->set_metadata("module-y", temp_buf); + Controller::instance().load_patch(pm); + + App::instance().configuration()->set_patch_folder(pm->filename().substr(0, pm->filename().find_last_of("/"))); + + hide(); +} + + +void +LoadSubpatchWindow::cancel_clicked() +{ + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/LoadSubpatchWindow.h b/src/progs/gtk/LoadSubpatchWindow.h new file mode 100644 index 00000000..45efdd15 --- /dev/null +++ b/src/progs/gtk/LoadSubpatchWindow.h @@ -0,0 +1,78 @@ +/* This file is part of Om. Copyright (C) 2006 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 LOADSUBPATCHWINDOW_H +#define LOADSUBPATCHWINDOW_H + +#include "PluginModel.h" +#include +#include + + +namespace OmGtk { + +class PatchController; + + +/** 'Add Subpatch' window. + * + * Loaded by glade as a derived object. + * + * \ingroup OmGtk + */ +class LoadSubpatchWindow : public Gtk::FileChooserDialog +{ +public: + LoadSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); + + void patch_controller(PatchController* pc); + + void set_next_module_location(int x, int y) + { m_new_module_x = x; m_new_module_y = y; } + +protected: + void on_show(); + +private: + void disable_name_entry(); + void enable_name_entry(); + void disable_poly_spinner(); + void enable_poly_spinner(); + + void ok_clicked(); + void cancel_clicked(); + + PatchController* m_patch_controller; + + int m_new_module_x; + int m_new_module_y; + + Gtk::RadioButton* m_name_from_file_radio; + Gtk::RadioButton* m_name_from_user_radio; + Gtk::Entry* m_name_entry; + Gtk::RadioButton* m_poly_from_file_radio; + Gtk::RadioButton* m_poly_from_parent_radio; + Gtk::RadioButton* m_poly_from_user_radio; + Gtk::SpinButton* m_poly_spinbutton; + Gtk::Button* m_ok_button; + Gtk::Button* m_cancel_button; +}; + + +} // namespace OmGtk + +#endif // LOADSUBPATCHWINDOW_H diff --git a/src/progs/gtk/Loader.cpp b/src/progs/gtk/Loader.cpp new file mode 100644 index 00000000..643dc3c9 --- /dev/null +++ b/src/progs/gtk/Loader.cpp @@ -0,0 +1,233 @@ +/* This file is part of Om. Copyright (C) 2006 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 "Loader.h" +#include +#include +#include +#include "PatchLibrarian.h" +#include "PatchModel.h" +#include "PatchController.h" +using std::cout; using std::endl; + +namespace OmGtk { + + +// LoadPatchEvent // + +void +LoadPatchEvent::execute() +{ + assert(m_patch_librarian != NULL); + m_patch_librarian->load_patch(m_patch_model, m_wait, m_merge); +} + + + +// SavePatchEvent // + +void +SavePatchEvent::execute() +{ + assert(m_patch_librarian != NULL); + m_patch_librarian->save_patch(m_patch_model, m_filename, m_recursive); +} + +/* +void +LoadSessionEvent::execute() +{ + std::ifstream is; + is.open(m_filename.c_str(), std::ios::in); + + if ( ! is.good()) { + cout << "[Loader] Unable to open session file " << m_filename << endl; + return; + } else { + cout << "[Loader] Loading session from " << m_filename << endl; + } + string s; + + is >> s; + if (s != "version") { + cout << "[Loader] Corrupt session file." << endl; + is.close(); + return; + } + + is >> s; + if (s != "1") { + cout << "[Loader] Unrecognised session file version." << endl; + is.close(); + return; + } + + while (!is.eof()) { + is >> s; + if (s == "") continue; + + if (s != "patch") { + //cerr << "[Loader] Corrupt session file, aborting session load." << endl; + break; + } else { + is >> s; + PatchModel* pm = new PatchModel("", 0); + if (s.substr(0, 1) != "/") + s = m_filename.substr(0, m_filename.find_last_of("/")+1) + s; + pm->filename(s); + pm->parent(NULL); + m_patch_librarian->load_patch(pm); + } + } + + is.close(); +} + + +void +SaveSessionEvent::execute() +{ + assert(m_filename != ""); + string dir = m_filename.substr(0, m_filename.find_last_of("/")); + + string patch_filename; + + std::ofstream os; + os.open(m_filename.c_str(), std::ios::out); + + if ( ! os.good()) { + cout << "[Loader] Unable to write to session file " << m_filename << endl; + return; + } else { + cout << "[Loader] Saving session to " << m_filename << endl; + } + + os << "version 1" << endl; + + for (map::iterator i = app->patches().begin(); + i != app->patches().end(); ++i) + { + if ((*i).second->model()->parent() == NULL) { + patch_filename = (*i).second->model()->filename(); + + // Make path relative if possible + if (patch_filename.length() > dir.length() && + patch_filename.substr(0, dir.length()) == dir) + patch_filename = patch_filename.substr(dir.length()+1); + + os << "patch " << patch_filename << endl; + } + } + + os.close(); +} +*/ + + +//////// Loader ////////// + + +Loader::Loader(PatchLibrarian* const patch_librarian) +: m_patch_librarian(patch_librarian), + m_event(NULL), + m_thread_exit_flag(false) +{ + assert(m_patch_librarian != NULL); + pthread_mutex_init(&m_mutex, NULL); + pthread_cond_init(&m_cond, NULL); +} + + +void +Loader::set_event(LoaderEvent* ev) +{ + assert(ev != NULL); + + pthread_mutex_lock(&m_mutex); + assert(m_event == NULL); + m_event = ev; + pthread_cond_signal(&m_cond); + pthread_mutex_unlock(&m_mutex); +} + + +void +Loader::launch() +{ + pthread_create(&m_thread, NULL, Loader::thread_function, this); +} + + +void* +Loader::thread_function(void* me) +{ + Loader* ct = static_cast(me); + return ct->m_thread_function(NULL); +} + + +void* +Loader::m_thread_function(void *) +{ + while ( ! m_thread_exit_flag) { + pthread_mutex_lock(&m_mutex); + pthread_cond_wait(&m_cond, &m_mutex); + + LoaderEvent* ev = m_event; + ev->execute(); + delete ev; + m_event = NULL; + + pthread_mutex_unlock(&m_mutex); + } + + pthread_exit(NULL); + return NULL; +} + + +void +Loader::load_patch(PatchModel* model, bool wait, bool merge) +{ + set_event(new LoadPatchEvent(m_patch_librarian, model, wait, merge)); +} + + +void +Loader::save_patch(PatchModel* model, const string& filename, bool recursive) +{ + cout << "[Loader] Saving patch " << filename << endl; + set_event(new SavePatchEvent(m_patch_librarian, model, filename, recursive)); +} + + +/* +void +Loader::load_session(const string& filename) +{ + set_event(new LoadSessionEvent(m_patch_librarian, filename)); +} + + +void +Loader::save_session(const string& filename) +{ + cout << "Saving session..." << endl; + set_event(new SaveSessionEvent(m_patch_librarian, filename)); +} +*/ + +} // namespace OmGtk diff --git a/src/progs/gtk/Loader.h b/src/progs/gtk/Loader.h new file mode 100644 index 00000000..46b5f3a8 --- /dev/null +++ b/src/progs/gtk/Loader.h @@ -0,0 +1,154 @@ +/* This file is part of Om. Copyright (C) 2006 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 LOADERTHREAD_H +#define LOADERTHREAD_H + +#include +#include +using std::string; + +namespace LibOmClient { + class PatchLibrarian; + class PatchModel; +} +using LibOmClient::PatchLibrarian; +using LibOmClient::PatchModel; + + +namespace OmGtk { + +/** Event to run in the Loader thread. + * + * \ingroup OmGtk + */ +class LoaderEvent +{ +public: + virtual void execute() = 0; + virtual ~LoaderEvent() {} +protected: + LoaderEvent() {} +}; + + +/** Loader thread patch loading event. + * + * \ingroup OmGtk + */ +class LoadPatchEvent : public LoaderEvent +{ +public: + LoadPatchEvent(PatchLibrarian* pl, PatchModel* model, bool wait, bool merge) + : m_patch_librarian(pl), m_patch_model(model), m_wait(wait), m_merge(merge) {} + virtual ~LoadPatchEvent() {} + void execute(); +private: + PatchLibrarian* m_patch_librarian; + PatchModel* m_patch_model; + bool m_wait; + bool m_merge; +}; + + +/** Loader thread patch loading event. + * + * \ingroup OmGtk + */ +class SavePatchEvent : public LoaderEvent +{ +public: + SavePatchEvent(PatchLibrarian* pl, PatchModel* pm, const string& filename, bool recursive) + : m_patch_librarian(pl), m_patch_model(pm), m_filename(filename), m_recursive(recursive) {} + virtual ~SavePatchEvent() {} + void execute(); +private: + PatchLibrarian* m_patch_librarian; + PatchModel* m_patch_model; + string m_filename; + bool m_recursive; +}; + +/* +class LoadSessionEvent : public LoaderEvent +{ +public: + LoadSessionEvent(PatchLibrarian* pl, const string& filename) + : m_patch_librarian(pl), m_filename(filename) {} + virtual ~LoadSessionEvent() {} + void execute(); +private: + PatchLibrarian* m_patch_librarian; + string m_filename; +}; + + +class SaveSessionEvent : public LoaderEvent +{ +public: + SaveSessionEvent(PatchLibrarian* pl, const string& filename) + : m_patch_librarian(pl), m_filename(filename) {} + virtual ~SaveSessionEvent() {} + void execute(); +private: + PatchLibrarian* m_patch_librarian; + string m_filename; +}; +*/ + +/** Thread for loading patch files. + * + * This is a seperate thread so it can send all the loading message without + * blocking everything else, so the app can respond to the incoming events + * caused as a result of the patch loading. + * + * \ingroup OmGtk + */ +class Loader +{ +public: + Loader(PatchLibrarian* const patch_librarian); + ~Loader() { m_thread_exit_flag = true; } + + void launch(); + void exit() { m_thread_exit_flag = true; } + + void load_patch(PatchModel* model, bool wait, bool merge); + void save_patch(PatchModel* model, const string& filename, bool recursive); + + //void load_session(const string& filename); + //void save_session(const string& filename); + + static void* thread_function(void* me); + +private: + void* m_thread_function(void*); + + void set_event(LoaderEvent* ev); + + PatchLibrarian* const m_patch_librarian; + LoaderEvent* m_event; + bool m_thread_exit_flag; + pthread_t m_thread; + pthread_mutex_t m_mutex; + pthread_cond_t m_cond; + +}; + + +} // namespace OmGtk + +#endif // LOADERRTHREAD_H diff --git a/src/progs/gtk/Makefile.am b/src/progs/gtk/Makefile.am new file mode 100644 index 00000000..c92ae2b2 --- /dev/null +++ b/src/progs/gtk/Makefile.am @@ -0,0 +1,98 @@ +if BUILD_GTK_CLIENT + +EXTRA_DIST = om_gtk.gladep + +sharefilesdir = $(pkgdatadir) +dist_sharefiles_DATA = om_gtk.glade om-icon.png + +AM_CXXFLAGS = -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -I$(top_srcdir)/src/common -I$(top_srcdir)/src/clients -DPKGDATADIR=\"$(pkgdatadir)\" @GTKMM_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @LOSC_CFLAGS@ @LASH_CFLAGS@ @FLOWCANVAS_CFLAGS@ +om_gtk_LDADD = @GTKMM_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @LOSC_LIBS@ @LASH_LIBS@ @FLOWCANVAS_LIBS@ ../libomclient.a +om_gtk_DEPENDENCIES = ../libomclient.a + + +bin_PROGRAMS = om_gtk +om_gtk_SOURCES = \ + cmdline.h \ + cmdline.c \ + main.cpp \ + singletons.cpp \ + ConnectWindow.h \ + ConnectWindow.cpp \ + App.h \ + App.cpp \ + Store.h \ + Store.cpp \ + Configuration.h \ + Configuration.cpp \ + GladeFactory.h \ + GladeFactory.cpp \ + Controller.h \ + Controller.cpp \ + GtkObjectController.h \ + GtkObjectController.cpp \ + PatchController.h \ + PatchController.cpp \ + NodeController.h \ + NodeController.cpp \ + PortController.h \ + PortController.cpp \ + DSSIController.h \ + DSSIController.cpp \ + LoadPluginWindow.h \ + LoadPluginWindow.cpp \ + LoadPatchWindow.h \ + LoadPatchWindow.cpp \ + MessagesWindow.h \ + MessagesWindow.cpp \ + LoadSubpatchWindow.h \ + LoadSubpatchWindow.cpp \ + ControlInterface.h \ + ControlInterface.cpp \ + NodeControlWindow.h \ + NodeControlWindow.cpp \ + ControlPanel.h \ + ControlPanel.cpp \ + ControlGroups.h \ + ControlGroups.cpp \ + PatchView.h \ + PatchView.cpp \ + PatchWindow.h \ + PatchWindow.cpp \ + BreadCrumb.h \ + OmFlowCanvas.h \ + OmFlowCanvas.cpp \ + ../../common/types.h \ + ../../common/Path.h \ + OmModule.h \ + OmModule.cpp \ + DSSIModule.h \ + DSSIModule.cpp \ + SubpatchModule.h \ + SubpatchModule.cpp \ + OmPort.h \ + OmPort.cpp \ + NewSubpatchWindow.h \ + NewSubpatchWindow.cpp \ + ConfigWindow.h \ + ConfigWindow.cpp \ + PatchDescriptionWindow.h \ + PatchDescriptionWindow.cpp \ + Loader.h \ + Loader.cpp \ + RenameWindow.h \ + RenameWindow.cpp \ + NodePropertiesWindow.h \ + NodePropertiesWindow.cpp \ + PatchTreeWindow.h \ + PatchTreeWindow.cpp + +#GtkClientInterface.h +#GtkClientInterface.cpp + + +if WITH_LASH +om_gtk_SOURCES += LashController.h LashController.cpp +endif + + +endif # WITH_GTK_CLIENT diff --git a/src/progs/gtk/MessagesWindow.cpp b/src/progs/gtk/MessagesWindow.cpp new file mode 100644 index 00000000..dfdc3750 --- /dev/null +++ b/src/progs/gtk/MessagesWindow.cpp @@ -0,0 +1,64 @@ +/* This file is part of Om. Copyright (C) 2006 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 "MessagesWindow.h" +#include + +namespace OmGtk { +using std::string; + + +MessagesWindow::MessagesWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml) +: Gtk::Window(cobject) +{ + glade_xml->get_widget("messages_textview", m_textview); + glade_xml->get_widget("messages_clear_button", m_clear_button); + glade_xml->get_widget("messages_close_button", m_close_button); + + m_clear_button->signal_clicked().connect(sigc::mem_fun(this, &MessagesWindow::clear_clicked)); + m_close_button->signal_clicked().connect(sigc::mem_fun(this, &MessagesWindow::close_clicked)); +} + + +void +MessagesWindow::post(const string& msg) +{ + Glib::RefPtr text_buf = m_textview->get_buffer(); + text_buf->insert(text_buf->end(), msg); + text_buf->insert(text_buf->end(), "\n"); + + if (!m_clear_button->is_sensitive()) + m_clear_button->set_sensitive(true); +} + + +void +MessagesWindow::close_clicked() +{ + hide(); +} + + +void +MessagesWindow::clear_clicked() +{ + Glib::RefPtr text_buf = m_textview->get_buffer(); + text_buf->erase(text_buf->begin(), text_buf->end()); + m_clear_button->set_sensitive(false); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/MessagesWindow.h b/src/progs/gtk/MessagesWindow.h new file mode 100644 index 00000000..5f5b86e6 --- /dev/null +++ b/src/progs/gtk/MessagesWindow.h @@ -0,0 +1,55 @@ +/* This file is part of Om. Copyright (C) 2006 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 MESSAGESWINDOW_H +#define MESSAGESWINDOW_H + +#include +#include +#include +using std::string; + + +namespace OmGtk { + + +/** Messages Window. + * + * Loaded by libglade as a derived object. + * This is shown when errors occur (ie during patch loading). + * + * \ingroup OmGtk + */ +class MessagesWindow : public Gtk::Window +{ +public: + MessagesWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); + + void post(const string& str); + +private: + void clear_clicked(); + void close_clicked(); + + Gtk::TextView* m_textview; + Gtk::Button* m_clear_button; + Gtk::Button* m_close_button; +}; + + +} // namespace OmGtk + +#endif // MESSAGESWINDOW_H diff --git a/src/progs/gtk/NewSubpatchWindow.cpp b/src/progs/gtk/NewSubpatchWindow.cpp new file mode 100644 index 00000000..dcc2cd2d --- /dev/null +++ b/src/progs/gtk/NewSubpatchWindow.cpp @@ -0,0 +1,110 @@ +/* This file is part of Om. Copyright (C) 2006 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 "NewSubpatchWindow.h" +#include "PatchController.h" +#include "NodeModel.h" +#include "Controller.h" +#include "PatchModel.h" + +namespace OmGtk { + + +NewSubpatchWindow::NewSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::Window(cobject), + m_new_module_x(0), + m_new_module_y(0) +{ + xml->get_widget("new_subpatch_name_entry", m_name_entry); + xml->get_widget("new_subpatch_message_label", m_message_label); + xml->get_widget("new_subpatch_polyphony_spinbutton", m_poly_spinbutton); + xml->get_widget("new_subpatch_ok_button", m_ok_button); + xml->get_widget("new_subpatch_cancel_button", m_cancel_button); + + m_name_entry->signal_changed().connect(sigc::mem_fun(this, &NewSubpatchWindow::name_changed)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubpatchWindow::ok_clicked)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubpatchWindow::cancel_clicked)); + + m_ok_button->property_sensitive() = false; +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +NewSubpatchWindow::patch_controller(PatchController* pc) +{ + m_patch_controller = pc; +} + + +/** Called every time the user types into the name input box. + * Used to display warning messages, and enable/disable the OK button. + */ +void +NewSubpatchWindow::name_changed() +{ + string name = m_name_entry->get_text(); + if (name.find("/") != string::npos) { + m_message_label->set_text("Name may not contain '/'"); + m_ok_button->property_sensitive() = false; + } else if (m_patch_controller->patch_model()->get_node(name) != NULL) { + m_message_label->set_text("An object already exists with that name."); + m_ok_button->property_sensitive() = false; + } else if (name.length() == 0) { + m_message_label->set_text(""); + m_ok_button->property_sensitive() = false; + } else { + m_message_label->set_text(""); + m_ok_button->property_sensitive() = true; + } +} + + +void +NewSubpatchWindow::ok_clicked() +{ + PatchModel* pm = new PatchModel( + m_patch_controller->model()->base_path() + m_name_entry->get_text(), + m_poly_spinbutton->get_value_as_int()); + + if (m_new_module_x == 0 && m_new_module_y == 0) { + m_patch_controller->get_new_module_location( + m_new_module_x, m_new_module_y); + } + pm->set_parent(m_patch_controller->patch_model()); + pm->x(m_new_module_x); + pm->y(m_new_module_y); + char temp_buf[16]; + snprintf(temp_buf, 16, "%d", m_new_module_x); + pm->set_metadata("module-x", temp_buf); + snprintf(temp_buf, 16, "%d", m_new_module_y); + pm->set_metadata("module-y", temp_buf); + Controller::instance().create_patch_from_model(pm); + hide(); +} + + +void +NewSubpatchWindow::cancel_clicked() +{ + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/NewSubpatchWindow.h b/src/progs/gtk/NewSubpatchWindow.h new file mode 100644 index 00000000..8421ea08 --- /dev/null +++ b/src/progs/gtk/NewSubpatchWindow.h @@ -0,0 +1,67 @@ +/* This file is part of Om. Copyright (C) 2006 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 NEWSUBPATCHWINDOW_H +#define NEWSUBPATCHWINDOW_H + +#include "PluginModel.h" +#include +#include + + +namespace OmGtk { + +class PatchController; + + +/** 'New Subpatch' window. + * + * Loaded by glade as a derived object. + * + * \ingroup OmGtk + */ +class NewSubpatchWindow : public Gtk::Window +{ +public: + NewSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); + + void patch_controller(PatchController* pc); + + void set_next_module_location(int x, int y) + { m_new_module_x = x; m_new_module_y = y; } + +private: + void name_changed(); + void ok_clicked(); + void cancel_clicked(); + + PatchController* m_patch_controller; + + int m_new_module_x; + int m_new_module_y; + + Gtk::Entry* m_name_entry; + Gtk::Label* m_message_label; + Gtk::SpinButton* m_poly_spinbutton; + Gtk::Button* m_ok_button; + Gtk::Button* m_cancel_button; +}; + + +} // namespace OmGtk + +#endif // NEWSUBPATCHWINDOW_H diff --git a/src/progs/gtk/NodeControlWindow.cpp b/src/progs/gtk/NodeControlWindow.cpp new file mode 100644 index 00000000..e40af67f --- /dev/null +++ b/src/progs/gtk/NodeControlWindow.cpp @@ -0,0 +1,127 @@ +/* This file is part of Om. Copyright (C) 2006 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 alongCont + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NodeControlWindow.h" +#include "GladeFactory.h" +#include "NodeController.h" +#include "ControlGroups.h" +#include "PatchWindow.h" +#include +#include +using std::cerr; using std::cout; using std::endl; + +namespace OmGtk { + + +/** Create a node control window and load a new ControlPanel for it. + */ +NodeControlWindow::NodeControlWindow(NodeController* node, size_t poly) +: m_node(node), + m_position_stored(false), + m_x(0), m_y(0) +{ + assert(m_node != NULL); + + property_resizable() = true; + set_border_width(5); + + set_title(m_node->path() + " Controls"); + + Glib::RefPtr xml = GladeFactory::new_glade_reference("warehouse_win"); + xml->get_widget_derived("control_panel_vbox", m_control_panel); + m_control_panel->reparent(*this); + + m_control_panel->init(m_node, poly); + + show_all_children(); + resize(); + + // FIXME: not working + set_icon_from_file(string(PKGDATADIR) + "/om-icon.png"); + + m_callback_enabled = true; +} + + +/** Create a node control window and with an existing ControlPanel. + */ +NodeControlWindow::NodeControlWindow(NodeController* node, ControlPanel* panel) +: m_node(node), + m_control_panel(panel) +{ + assert(m_node != NULL); + + property_resizable() = true; + set_border_width(5); + + set_title(m_node->path() + " Controls"); + + m_control_panel->reparent(*this); + + show_all_children(); + resize(); + + m_callback_enabled = true; +} + + +NodeControlWindow::~NodeControlWindow() +{ + delete m_control_panel; +} + + +void +NodeControlWindow::resize() +{ + pair controls_size = m_control_panel->ideal_size(); + /*int width = 400; + int height = controls_size.second + + ((m_node->polyphonic()) ? 4 : 40);*/ + int width = controls_size.first; + int height = controls_size.second; + + if (height > property_screen().get_value()->get_height() - 64) + height = property_screen().get_value()->get_height() - 64; + if (width > property_screen().get_value()->get_width() - 64) + width = property_screen().get_value()->get_width() - 64; + + //cerr << "Resizing to: " << width << " x " << height << endl; + + Gtk::Window::resize(width, height); +} + + +void +NodeControlWindow::on_show() +{ + if (m_position_stored) + move(m_x, m_y); + + Gtk::Window::on_show(); +} + + +void +NodeControlWindow::on_hide() +{ + m_position_stored = true; + get_position(m_x, m_y); + Gtk::Window::on_hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/NodeControlWindow.h b/src/progs/gtk/NodeControlWindow.h new file mode 100644 index 00000000..a9224de9 --- /dev/null +++ b/src/progs/gtk/NodeControlWindow.h @@ -0,0 +1,69 @@ +/* This file is part of Om. Copyright (C) 2006 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 NODECONTROLWINDOW_H +#define NODECONTROLWINDOW_H + +#include +#include +#include +#include +#include +#include "ControlPanel.h" +using std::string; using std::vector; + +using namespace LibOmClient; + +namespace OmGtk { + +class ControlGroup; +class NodeController; + + +/** Window with controls (sliders) for all control-rate ports on a Node. + * + * \ingroup OmGtk + */ +class NodeControlWindow : public Gtk::Window +{ +public: + NodeControlWindow(NodeController* node, size_t poly); + NodeControlWindow(NodeController* node, ControlPanel* panel); + virtual ~NodeControlWindow(); + + ControlPanel* control_panel() const { return m_control_panel; } + + void resize(); + +protected: + void on_show(); + void on_hide(); + +private: + NodeController* m_node; + ControlPanel* m_control_panel; + bool m_callback_enabled; + + bool m_position_stored; + int m_x; + int m_y; +}; + + +} // namespace OmGtk + +#endif // NODECONTROLWINDOW_H diff --git a/src/progs/gtk/NodeController.cpp b/src/progs/gtk/NodeController.cpp new file mode 100644 index 00000000..57756877 --- /dev/null +++ b/src/progs/gtk/NodeController.cpp @@ -0,0 +1,408 @@ +/* This file is part of Om. Copyright (C) 2006 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 "NodeController.h" +#include +#include +#include "OmModule.h" +#include "NodeModel.h" +#include "PortModel.h" +#include "PortController.h" +#include "GtkObjectController.h" +#include "NodeControlWindow.h" +#include "OmModule.h" +#include "PatchController.h" +#include "OmFlowCanvas.h" +#include "RenameWindow.h" +#include "GladeFactory.h" +#include "Controller.h" +#include "PatchWindow.h" +#include "PatchModel.h" +#include "NodePropertiesWindow.h" +#include "Store.h" +using std::cerr; using std::endl; + +namespace OmGtk { + + +NodeController::NodeController(NodeModel* model) +: GtkObjectController(model), + m_controls_menuitem(NULL), + m_module(NULL), + m_control_window(NULL), + m_properties_window(NULL), + m_bridge_port(NULL) +{ + assert(model->controller() == NULL); + model->set_controller(this); + + // Create port controllers + for (list::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + assert((*i)->controller() == NULL); + assert((*i)->parent() == model); + PortController* const pc = new PortController(*i); + assert((*i)->controller() == pc); // PortController() does this + } + + // Build menu + + Gtk::Menu::MenuList& items = m_menu.items(); + + Gtk::Menu_Helpers::MenuElem controls_elem + = Gtk::Menu_Helpers::MenuElem("Controls", + sigc::mem_fun(this, &NodeController::show_control_window)); + m_controls_menuitem = controls_elem.get_child(); + items.push_back(controls_elem); + items.push_back(Gtk::Menu_Helpers::MenuElem("Properties", + sigc::mem_fun(this, &NodeController::show_properties_window))); + items.push_back(Gtk::Menu_Helpers::SeparatorElem()); + items.push_back(Gtk::Menu_Helpers::MenuElem("Rename...", + sigc::mem_fun(this, &NodeController::show_rename_window))); + items.push_back(Gtk::Menu_Helpers::MenuElem("Clone", + sigc::mem_fun(this, &NodeController::on_menu_clone))); + items.push_back(Gtk::Menu_Helpers::MenuElem("Disconnect All", + sigc::mem_fun(this, &NodeController::on_menu_disconnect_all))); + items.push_back(Gtk::Menu_Helpers::MenuElem("Destroy", + sigc::mem_fun(this, &NodeController::on_menu_destroy))); + + m_controls_menuitem->property_sensitive() = false; + + if (node_model()->plugin()->type() == PluginModel::Internal + && node_model()->plugin()->plug_label() == "midi_control_in") { + Gtk::Menu::MenuList& items = m_menu.items(); + items.push_back(Gtk::Menu_Helpers::MenuElem("Learn", + sigc::mem_fun(this, &NodeController::on_menu_learn))); + } +} + + +NodeController::~NodeController() +{ +} + + +void +NodeController::create_module(OmFlowCanvas* canvas) +{ + //cerr << "Creating node module " << m_model->path() << endl; + + // If this is a DSSI plugin, DSSIController should be doing this + assert(node_model()->plugin()->type() != PluginModel::DSSI); + assert(canvas != NULL); + assert(m_module == NULL); + + m_module = new OmModule(canvas, this); + + create_all_ports(); + + m_module->move_to(node_model()->x(), node_model()->y()); +} + + +void +NodeController::add_to_store() +{ + // Add self + Store::instance().add_object(this); + + // Add ports + for (list::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + //GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); + assert((*i)->controller() != NULL); + ((GtkObjectController*)((*i)->controller()))->add_to_store(); + } +} + + +void +NodeController::remove_from_store() +{ + // Remove ports + for (list::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); + assert(pc != NULL); + pc->remove_from_store(); + } + + // Remove self + Store::instance().remove_object(this); +} + + +void +NodeController::set_path(const Path& new_path) +{ + remove_from_store(); + + // Rename ports + for (list::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); + assert(pc != NULL); + pc->set_path(m_model->path().base_path() + pc->model()->name()); + } + + // Handle bridge port, if this node represents one + if (m_bridge_port != NULL) + m_bridge_port->set_path(new_path); + + if (m_module != NULL) + m_module->canvas()->rename_module(node_model()->path().name(), new_path.name()); + + GtkObjectController::set_path(new_path); + + add_to_store(); +} + + +void +NodeController::destroy() +{ + PatchController* pc = ((PatchController*)m_model->parent()->controller()); + assert(pc != NULL); + + remove_from_store(); + pc->remove_node(m_model->path().name()); + + if (m_bridge_port != NULL) + m_bridge_port->destroy(); + m_bridge_port = NULL; + + //if (m_module != NULL) + // delete m_module; +} + + +void +NodeController::metadata_update(const string& key, const string& value) +{ + //cout << "[NodeController] Metadata update: " << m_model->path() << endl; + + if (m_module != NULL) { + if (key == "module-x") { + float x = atof(value.c_str()); + //if (x > 0 && x < m_canvas->width()) + m_module->move_to(x, m_module->property_y().get_value()); + } else if (key == "module-y") { + float y = atof(value.c_str()); + //if (y > 0 && y < m_canvas->height()) + m_module->move_to(m_module->property_x().get_value(), y); + } + } + + if (m_bridge_port != NULL) + m_bridge_port->metadata_update(key, value); + GtkObjectController::metadata_update(key, value); +} + + +void +NodeController::add_port(PortModel* pm) +{ + assert(pm->parent() == NULL); + + cout << "[NodeController] Adding port " << pm->path() << endl; + + node_model()->add_port(pm); + PortController* pc = new PortController(pm); + assert(pm->controller() == pc); + pc->add_to_store(); + + if (m_module != NULL) { + pc->create_port(m_module); + m_module->resize(); + + // Enable "Controls" menu item on module + if (has_control_inputs()) + enable_controls_menuitem(); + } + + if (m_control_window != NULL) { + assert(m_control_window->control_panel() != NULL); + m_control_window->control_panel()->add_port(pc); + m_control_window->resize(); + } +} + + +void +NodeController::show_control_window() +{ + size_t poly = 1; + if (node_model()->polyphonic()) + poly = node_model()->parent_patch()->poly(); + + if (m_control_window == NULL) + m_control_window = new NodeControlWindow(this, poly); + + if (m_control_window->control_panel()->num_controls() > 0) + m_control_window->present(); +} + + +void +NodeController::on_menu_destroy() +{ + Controller::instance().destroy(node_model()->path()); +} + + +void +NodeController::show_rename_window() +{ + assert(node_model()->parent() != NULL); + + // FIXME: will this be magically cleaned up? + RenameWindow* win = NULL; + Glib::RefPtr xml = GladeFactory::new_glade_reference("rename_win"); + xml->get_widget_derived("rename_win", win); + + PatchController* parent = ((PatchController*)node_model()->parent()->controller()); + assert(parent != NULL); + + if (parent->window() != NULL) + win->set_transient_for(*parent->window()); + + win->set_object(this); + win->show(); +} + +void +NodeController::on_menu_clone() +{ + assert(node_model() != NULL); + //assert(m_parent != NULL); + //assert(m_parent->model() != NULL); + + string clone_name = node_model()->name(); + int i = 2; // postfix number (ie oldname_2) + + // Check if name already has a number postfix + if (clone_name.find_last_of("_") != string::npos) { + string name_postfix = clone_name.substr(clone_name.find_last_of("_")+1); + clone_name = clone_name.substr(0, clone_name.find_last_of("_")); + if (sscanf(name_postfix.c_str(), "%d", &i)) + ++i; + } + + char clone_postfix[4]; + for ( ; i < 100; ++i) { + snprintf(clone_postfix, 4, "_%d", i); + if (node_model()->parent_patch()->get_node(clone_name + clone_postfix) == NULL) + break; + } + + clone_name = clone_name + clone_postfix; + + const string path = node_model()->parent_patch()->base_path() + clone_name; + NodeModel* nm = new NodeModel(path); + nm->plugin(node_model()->plugin()); + nm->polyphonic(node_model()->polyphonic()); + nm->x(node_model()->x() + 20); + nm->y(node_model()->y() + 20); + Controller::instance().create_node_from_model(nm); +} + + +void +NodeController::on_menu_learn() +{ + Controller::instance().midi_learn(node_model()->path()); +} + +void +NodeController::on_menu_disconnect_all() +{ + Controller::instance().disconnect_all(node_model()->path()); +} + + +void +NodeController::show_properties_window() +{ + PatchController* parent = ((PatchController*)node_model()->parent()->controller()); + assert(parent != NULL); + + if (m_properties_window == NULL) { + Glib::RefPtr xml = GladeFactory::new_glade_reference("node_properties_win"); + xml->get_widget_derived("node_properties_win", m_properties_window); + } + assert(m_properties_window != NULL); + assert(parent != NULL); + m_properties_window->set_node(node_model()); + if (parent->window() != NULL) + m_properties_window->set_transient_for(*parent->window()); + m_properties_window->show(); +} + + +/** Create all (visual) ports and add them to module (and resize it). + */ +void +NodeController::create_all_ports() +{ + assert(m_module != NULL); + + PortController* pc = NULL; + for (PortModelList::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + pc = dynamic_cast((*i)->controller()); + assert(pc != NULL); + pc->create_port(m_module); + } + + m_module->resize(); + + if (has_control_inputs()) + enable_controls_menuitem(); +} + + +bool +NodeController::has_control_inputs() +{ + for (PortModelList::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) + if ((*i)->is_input() && (*i)->is_control()) + return true; + + return false; +} + + +void +NodeController::enable_controls_menuitem() +{ + m_controls_menuitem->property_sensitive() = true; +} + + +void +NodeController::disable_controls_menuitem() +{ + m_controls_menuitem->property_sensitive() = false; + + if (m_control_window != NULL) + m_control_window->hide(); +} + + + +} // namespace OmGtk + diff --git a/src/progs/gtk/NodeController.h b/src/progs/gtk/NodeController.h new file mode 100644 index 00000000..ed2a6d59 --- /dev/null +++ b/src/progs/gtk/NodeController.h @@ -0,0 +1,114 @@ +/* This file is part of Om. Copyright (C) 2006 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 NODECONTROLLER_H +#define NODECONTROLLER_H + +#include +#include +#include "util/Path.h" +#include "GtkObjectController.h" + +using std::string; +using Om::Path; +using namespace LibOmClient; + +namespace LibOmClient { + class MetadataModel; + class NodeModel; + class PortModel; +} + +namespace OmGtk { + +class Controller; +class OmModule; +class NodeControlWindow; +class NodePropertiesWindow; +class PortController; +class OmFlowCanvas; + +/** Controller for a Node. + * + * \ingroup OmGtk + */ +class NodeController : public GtkObjectController +{ +public: + NodeController(NodeModel* model); + virtual ~NodeController(); + + virtual void destroy(); + + virtual void add_to_store(); + virtual void remove_from_store(); + + virtual void metadata_update(const string& key, const string& value); + + virtual void create_module(OmFlowCanvas* canvas); + + void set_path(const Path& new_path); + + virtual void add_port(PortModel* pm); + virtual void remove_port(const Path& path, bool resize_module) {} + + virtual void program_add(int bank, int program, const string& name) {} + virtual void program_remove(int bank, int program) {} + + OmModule* module() { return m_module; } + + void bridge_port(PortController* port) { m_bridge_port = port; } + PortController* as_port() { return m_bridge_port; } + + NodeModel* node_model() { return (NodeModel*)m_model; } + + NodeControlWindow* control_window() { return m_control_window; } + void control_window(NodeControlWindow* cw) { m_control_window = cw; } + + virtual void show_control_window(); + void show_rename_window(); + void show_properties_window(); + + bool has_control_inputs(); + + virtual void show_menu(GdkEventButton* event) + { m_menu.popup(event->button, event->time); } + + virtual void enable_controls_menuitem(); + virtual void disable_controls_menuitem(); + +protected: + void create_all_ports(); + + void on_menu_destroy(); + void on_menu_clone(); + void on_menu_learn(); + void on_menu_disconnect_all(); + + Gtk::Menu m_menu; + Glib::RefPtr m_controls_menuitem; + + OmModule* m_module; ///< View (module on a patch canvas) + + NodeControlWindow* m_control_window; + NodePropertiesWindow* m_properties_window; + PortController* m_bridge_port; +}; + + +} // namespace OmGtk + +#endif // NODECONTROLLER_H diff --git a/src/progs/gtk/NodePropertiesWindow.cpp b/src/progs/gtk/NodePropertiesWindow.cpp new file mode 100644 index 00000000..048f2513 --- /dev/null +++ b/src/progs/gtk/NodePropertiesWindow.cpp @@ -0,0 +1,62 @@ +/* This file is part of Om. Copyright (C) 2006 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 "NodePropertiesWindow.h" +#include +#include +#include "NodeModel.h" +#include "PluginModel.h" + +namespace OmGtk { +using std::string; + + +NodePropertiesWindow::NodePropertiesWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml) +: Gtk::Window(cobject) +{ + glade_xml->get_widget("node_properties_path_label", m_node_path_label); + glade_xml->get_widget("node_properties_polyphonic_checkbutton", m_node_polyphonic_toggle); + glade_xml->get_widget("node_properties_plugin_type_label", m_plugin_type_label); + glade_xml->get_widget("node_properties_plugin_uri_label", m_plugin_uri_label); + glade_xml->get_widget("node_properties_plugin_name_label", m_plugin_name_label); +} + + +/** Set the node this window is associated with. + * This function MUST be called before using this object in any way. + */ +void +NodePropertiesWindow::set_node(NodeModel* node_model) +{ + assert(node_model != NULL); + + m_node_model = node_model; + + set_title(node_model->path() + " Properties"); + + m_node_path_label->set_text(node_model->path()); + m_node_polyphonic_toggle->set_active(node_model->polyphonic()); + + const PluginModel* const pm = node_model->plugin(); + + m_plugin_type_label->set_text(pm->type_string()); + m_plugin_uri_label->set_text(pm->uri()); + m_plugin_name_label->set_text(pm->name()); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/NodePropertiesWindow.h b/src/progs/gtk/NodePropertiesWindow.h new file mode 100644 index 00000000..efff01bb --- /dev/null +++ b/src/progs/gtk/NodePropertiesWindow.h @@ -0,0 +1,55 @@ +/* This file is part of Om. Copyright (C) 2006 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 NODEPROPERTIESWINDOW_H +#define NODEPROPERTIESWINDOW_H + +#include +#include + +namespace LibOmClient { class NodeModel; } +using namespace LibOmClient; + +namespace OmGtk { + + +/** 'New Patch' Window. + * + * Loaded by libglade as a derived object. + * + * \ingroup OmGtk + */ +class NodePropertiesWindow : public Gtk::Window +{ +public: + NodePropertiesWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); + + void set_node(NodeModel* node_model); + +private: + + NodeModel* m_node_model; + + Gtk::Label* m_node_path_label; + Gtk::CheckButton* m_node_polyphonic_toggle; + Gtk::Label* m_plugin_type_label; + Gtk::Label* m_plugin_uri_label; + Gtk::Label* m_plugin_name_label; +}; + +} // namespace OmGtk + +#endif // NODEPROPERTIESWINDOW_H diff --git a/src/progs/gtk/OmFlowCanvas.cpp b/src/progs/gtk/OmFlowCanvas.cpp new file mode 100644 index 00000000..a7e41ea2 --- /dev/null +++ b/src/progs/gtk/OmFlowCanvas.cpp @@ -0,0 +1,166 @@ +/* This file is part of Om. Copyright (C) 2006 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 "OmFlowCanvas.h" +#include +#include +#include "Controller.h" +#include "PatchController.h" +#include "PatchModel.h" +#include "PatchWindow.h" +#include "LoadPluginWindow.h" +#include "LoadSubpatchWindow.h" +#include "NewSubpatchWindow.h" +#include "OmPort.h" +#include "NodeModel.h" +#include "OmModule.h" + + +namespace OmGtk { + + +OmFlowCanvas::OmFlowCanvas(PatchController* controller, int width, int height) +: FlowCanvas(width, height), + m_patch_controller(controller), + m_last_click_x(0), + m_last_click_y(0) +{ + assert(controller != NULL); + + Gtk::Menu::MenuList& items = m_menu.items(); + items.push_back(Gtk::Menu_Helpers::MenuElem("Load Plugin...", + sigc::mem_fun(this, &OmFlowCanvas::menu_load_plugin))); + items.push_back(Gtk::Menu_Helpers::MenuElem("Load Subpatch...", + sigc::mem_fun(this, &OmFlowCanvas::menu_load_subpatch))); + items.push_back(Gtk::Menu_Helpers::MenuElem("New Subpatch...", + sigc::mem_fun(this, &OmFlowCanvas::menu_create_subpatch))); +} + + +void +OmFlowCanvas::connect(const Port* src_port, const Port* dst_port) +{ + assert(src_port != NULL); + assert(dst_port != NULL); + + const OmPort* const src = static_cast(src_port); + const OmPort* const dst = static_cast(dst_port); + + // Midi binding/learn shortcut + if (src->model()->type() == PortModel::MIDI && + dst->model()->type() == PortModel::CONTROL) + { + // FIXME: leaks? + NodeModel* nm = new NodeModel(m_patch_controller->model()->base_path() + + src->name() + "-" + dst->name()); + PluginModel* pm = new PluginModel(PluginModel::Internal, "", "midi_control_in", ""); + nm->plugin(pm); + nm->x(dst->module()->property_x() - dst->module()->width() - 20); + nm->y(dst->module()->property_y()); + Controller::instance().create_node_from_model(nm); + Controller::instance().connect(src->model()->path(), nm->path() + "/MIDI In"); + Controller::instance().connect(nm->path() + "/Out (CR)", dst->model()->path()); + Controller::instance().midi_learn(nm->path()); + + // Set control node range to port's user range + + Controller::instance().set_port_value_queued(nm->path().base_path() + "Min", + atof(dst->model()->get_metadata("user-min").c_str())); + Controller::instance().set_port_value_queued(nm->path().base_path() + "Max", + atof(dst->model()->get_metadata("user-max").c_str())); + } else { + Controller::instance().connect(src->model()->path(), + dst->model()->path()); + } +} + + +void +OmFlowCanvas::disconnect(const Port* src_port, const Port* dst_port) +{ + assert(src_port != NULL); + assert(dst_port != NULL); + + Controller::instance().disconnect(((OmPort*)src_port)->model()->path(), + ((OmPort*)dst_port)->model()->path()); +} + + +bool +OmFlowCanvas::canvas_event(GdkEvent* event) +{ + assert(event != NULL); + + switch (event->type) { + + case GDK_BUTTON_PRESS: + if (event->button.button == 3) { + m_last_click_x = (int)event->button.x; + m_last_click_y = (int)event->button.y; + show_menu(event); + } + break; + + /*case GDK_KEY_PRESS: + if (event->key.keyval == GDK_Delete) + destroy_selected(); + break; + */ + + default: + break; + } + + return FlowCanvas::canvas_event(event); +} + + +void +OmFlowCanvas::destroy_selected() +{ + for (list::iterator m = m_selected_modules.begin(); m != m_selected_modules.end(); ++m) + Controller::instance().destroy(((OmModule*)(*m))->node()->path()); +} + + +void +OmFlowCanvas::menu_load_plugin() +{ + m_patch_controller->window()->load_plugin_window()->set_next_module_location( + m_last_click_x, m_last_click_y); + m_patch_controller->window()->load_plugin_window()->show(); +} + + +void +OmFlowCanvas::menu_load_subpatch() +{ + m_patch_controller->window()->load_subpatch_window()->set_next_module_location( + m_last_click_x, m_last_click_y); + m_patch_controller->window()->load_subpatch_window()->show(); +} + + +void +OmFlowCanvas::menu_create_subpatch() +{ + m_patch_controller->window()->new_subpatch_window()->set_next_module_location( + m_last_click_x, m_last_click_y); + m_patch_controller->window()->new_subpatch_window()->show(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/OmFlowCanvas.h b/src/progs/gtk/OmFlowCanvas.h new file mode 100644 index 00000000..2a553f5b --- /dev/null +++ b/src/progs/gtk/OmFlowCanvas.h @@ -0,0 +1,70 @@ +/* This file is part of Om. Copyright (C) 2006 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 OMPATCHBAYAREA_H +#define OMPATCHBAYAREA_H + +#include +#include + + +using std::string; +using namespace LibFlowCanvas; + +using LibFlowCanvas::Port; + +namespace OmGtk { + +class OmModule; +class PatchController; + +/** Patch canvas widget. + * + * \ingroup OmGtk + */ +class OmFlowCanvas : public LibFlowCanvas::FlowCanvas +{ +public: + OmFlowCanvas(PatchController* controller, int width, int height); + + OmModule* find_module(const string& name) + { return (OmModule*)FlowCanvas::find_module(name); } + + void connect(const Port* src_port, const Port* dst_port); + void disconnect(const Port* src_port, const Port* dst_port); + + bool canvas_event(GdkEvent* event); + void destroy_selected(); + + void show_menu(GdkEvent* event) + { m_menu.popup(event->button.button, event->button.time); } + + void menu_load_plugin(); + void menu_load_subpatch(); + void menu_create_subpatch(); + +private: + PatchController* m_patch_controller; + int m_last_click_x; + int m_last_click_y; + + Gtk::Menu m_menu; +}; + + +} // namespace OmGtk + +#endif // OMPATCHBAYAREA_H diff --git a/src/progs/gtk/OmModule.cpp b/src/progs/gtk/OmModule.cpp new file mode 100644 index 00000000..3a31b7f3 --- /dev/null +++ b/src/progs/gtk/OmModule.cpp @@ -0,0 +1,85 @@ +/* This file is part of Om. Copyright (C) 2006 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 "OmModule.h" +#include +#include "Controller.h" +#include "OmFlowCanvas.h" +#include "PatchModel.h" +#include "NodeModel.h" +#include "OmPort.h" +#include "GladeFactory.h" +#include "RenameWindow.h" +#include "PatchController.h" +#include "PatchWindow.h" + +namespace OmGtk { + + +OmModule::OmModule(OmFlowCanvas* canvas, NodeController* node) +: LibFlowCanvas::Module(canvas, node->node_model()->name(), + node->node_model()->x(), node->node_model()->y()), + m_node(node) +{ + assert(m_node != NULL); + + /*if (node_model()->polyphonic() && node_model()->parent() != NULL + && node_model()->parent_patch()->poly() > 1) { + border_width(2.0); + }*/ + if (node->node_model()->polyphonic()) { + border_width(2.0); + } +} + + +void +OmModule::show_control_window() +{ + node()->show_control_window(); +} + + +void +OmModule::store_location() +{ + if (m_node->node_model()->x() == 0 || m_node->node_model()->y() == 0) + return; + + char temp_buf[16]; + + m_node->node_model()->x(property_x()); + snprintf(temp_buf, 16, "%f", m_node->node_model()->x()); + m_node->node_model()->set_metadata("module-x", temp_buf); // just in case? + Controller::instance().set_metadata(m_node->node_model()->path(), "module-x", temp_buf); + + m_node->node_model()->y(property_y()); + snprintf(temp_buf, 16, "%f", m_node->node_model()->y()); + m_node->node_model()->set_metadata("module-y", temp_buf); // just in case? + Controller::instance().set_metadata(m_node->node_model()->path(), "module-y", temp_buf); +} + + +void +OmModule::move_to(double x, double y) +{ + Module::move_to(x, y); + m_node->node_model()->x(x); + m_node->node_model()->y(y); + //store_location(); +} + +} // namespace OmGtk diff --git a/src/progs/gtk/OmModule.h b/src/progs/gtk/OmModule.h new file mode 100644 index 00000000..ebb36fe6 --- /dev/null +++ b/src/progs/gtk/OmModule.h @@ -0,0 +1,77 @@ +/* This file is part of Om. Copyright (C) 2006 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 OMMODULE_H +#define OMMODULE_H + +#include +#include +#include +#include "NodeController.h" +using std::string; + +namespace LibOmClient { +class PortModel; +class NodeModel; +class ControlModel; +} +using namespace LibOmClient; + +namespace OmGtk { + +class PatchController; +class OmFlowCanvas; +class OmPort; + + +/** A module in a patch. + * + * This base class is extended for various types of modules - SubpatchModule, + * DSSIModule, etc. + * + * \ingroup OmGtk + */ +class OmModule : public LibFlowCanvas::Module +{ +public: + OmModule(OmFlowCanvas* canvas, NodeController* node); + virtual ~OmModule() {} + + virtual OmPort* port(const string& port_name) { + return (OmPort*)Module::port(port_name); + } + + virtual void store_location(); + void move_to(double x, double y); + + void on_right_click(GdkEventButton* event) { m_node->show_menu(event); } + + void show_control_window(); + + NodeController* node() const { return m_node; } + +protected: + virtual void on_double_click(GdkEventButton* ev) { show_control_window(); } + virtual void on_middle_click(GdkEventButton* ev) { show_control_window(); } + + NodeController* m_node; +}; + + +} // namespace OmGtk + +#endif // OMMODULE_H diff --git a/src/progs/gtk/OmPort.cpp b/src/progs/gtk/OmPort.cpp new file mode 100644 index 00000000..b43b8294 --- /dev/null +++ b/src/progs/gtk/OmPort.cpp @@ -0,0 +1,57 @@ +/* This file is part of Om. Copyright (C) 2006 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 "OmPort.h" +#include +#include +#include "PortModel.h" +#include "OmModule.h" +#include "ControlModel.h" +#include "Configuration.h" +#include "App.h" +using std::cerr; using std::endl; + +using namespace LibOmClient; + +namespace OmGtk { + +OmPort::OmPort(OmModule* module, PortModel* pm) +: Port(module, pm->name(), pm->is_input(), App::instance().configuration()->get_port_color(pm)), + m_port_model(pm) +{ + assert(module != NULL); + assert(m_port_model != NULL); +} + +#if 0 +void +OmPort::set_name(const string& n) +{ + cerr << "********** OmPort::set_name broken **********************" << endl; + + /* FIXME: move to PortController + string new_path = OmPath::parent(m_port_model->path()) +"/"+ n; + + for (list::iterator i = m_control_panels.begin(); i != m_control_panels.end(); ++i) + (*i)->rename_port(m_port_model->path(), new_path); + + Port::set_name(n); + m_port_model->path(new_path); + */ +} +#endif + +} // namespace OmGtk diff --git a/src/progs/gtk/OmPort.h b/src/progs/gtk/OmPort.h new file mode 100644 index 00000000..69a867d5 --- /dev/null +++ b/src/progs/gtk/OmPort.h @@ -0,0 +1,59 @@ +/* This file is part of Om. Copyright (C) 2006 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 OMPORT_H +#define OMPORT_H + +#include +#include +#include + +namespace LibOmClient { class PortModel; } +using namespace LibOmClient; +using namespace LibFlowCanvas; +using std::string; using std::list; + +namespace OmGtk { + +class FlowCanvas; +class PatchController; +class PatchWindow; +class OmModule; + + +/** A Port on an OmModule. + * + * \ingroup OmGtk + */ +class OmPort : public LibFlowCanvas::Port +{ +public: + OmPort(OmModule* module, PortModel* pm); + + virtual ~OmPort() {} + + //void set_name(const string& n); + + PortModel* model() const { return m_port_model; } + +private: + PortModel* m_port_model; +}; + + +} // namespace OmGtk + +#endif // OMPORT_H diff --git a/src/progs/gtk/PatchController.cpp b/src/progs/gtk/PatchController.cpp new file mode 100644 index 00000000..83ba62d9 --- /dev/null +++ b/src/progs/gtk/PatchController.cpp @@ -0,0 +1,685 @@ +/* This file is part of Om. Copyright (C) 2006 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 "PatchController.h" +#include +#include +#include "GladeFactory.h" +#include "Configuration.h" +#include "util/Path.h" +#include "ControlPanel.h" +#include "ConnectionModel.h" +#include "OmFlowCanvas.h" +#include "PatchView.h" +#include "flowcanvas/Module.h" +#include "PluginModel.h" +#include "Controller.h" +#include "SubpatchModule.h" +#include "DSSIModule.h" +#include "PatchWindow.h" +#include "NodeModel.h" +#include "OmModule.h" +#include "OmPort.h" +#include "ControlModel.h" +#include "NodeControlWindow.h" +#include "NodeController.h" +#include "PortController.h" +#include "App.h" +#include "PatchTreeWindow.h" +#include "DSSIController.h" +#include "PatchModel.h" +#include "Store.h" + +using std::cerr; using std::cout; using std::endl; +using Om::Path; +using namespace LibOmClient; + +namespace OmGtk { + + +PatchController::PatchController(PatchModel* model) +: NodeController(model), + m_window(NULL), + m_patch_view(NULL), + m_module_x(0), + m_module_y(0) +{ + assert(model->path().length() > 0); + assert(model->parent() == NULL); + assert(model->controller() == this); // NodeController() does this + + if (model->path() != "/") { + PatchController* parent = Store::instance().patch(model->path().parent()); + if (parent != NULL) + parent->add_subpatch(this); + else + cerr << "[PatchController] " << path() << " ERROR: Parent not found." << endl; + } +} + + +PatchController::~PatchController() +{ + if (m_patch_view != NULL) { + claim_patch_view(); + m_patch_view->hide(); + delete m_patch_view; + m_patch_view = NULL; + } + + if (m_control_window != NULL) { + m_control_window->hide(); + delete m_control_window; + m_control_window = NULL; + } + + if (m_window != NULL) { + m_window->hide(); + delete m_window; + m_window = NULL; + } +} + + +void +PatchController::add_to_store() +{ + Store::instance().add_object(this); +} + + +void +PatchController::remove_from_store() +{ + Store::instance().remove_object(this); +} + + +void +PatchController::clear() +{ + // Destroy model + // Destroying nodes removes models from patch model, which invalidates any + // iterator to nodes, so avoid the iterator problem by doing it this way: + const NodeModelMap& nodes = patch_model()->nodes(); + size_t remaining = nodes.size(); + + while (remaining > 0) { + NodeController* const nc = (NodeController*)(*nodes.begin()).second->controller(); + assert(nc != NULL); + nc->destroy(); + assert(nodes.size() == remaining - 1); + --remaining; + } + assert(nodes.empty()); + + patch_model()->clear(); + + if (m_patch_view != NULL) { + assert(m_patch_view->canvas() != NULL); + m_patch_view->canvas()->destroy(); + } +} + + +void +PatchController::destroy() +{ + // Destroying nodes removes models from patch model, which invalidates any + // iterator to nodes, so avoid the iterator problem by doing it this way: + const NodeModelMap& nodes = patch_model()->nodes(); + size_t remaining = nodes.size(); + + while (remaining > 0) { + NodeController* const nc = (NodeController*) + (*nodes.begin()).second->controller(); + assert(nc != NULL); + nc->destroy(); + assert(nodes.size() == remaining - 1); + --remaining; + } + assert(nodes.empty()); + + //App::instance().remove_patch(this); + App::instance().patch_tree()->remove_patch(path()); + + // Delete all children models + //patch_model()->clear(); + + // Remove self from object store + Store::instance().remove_object(this); + + // Delete self from parent (this will delete model) + if (patch_model()->parent() != NULL) { + PatchController* const parent = (PatchController*)patch_model()->parent()->controller(); + assert(parent != NULL); + parent->remove_node(name()); + } else { + delete m_model; + } +} + + +void +PatchController::metadata_update(const string& key, const string& value) +{ + NodeController::metadata_update(key, value); + + if (key == "filename") + patch_model()->filename(value); +} + + +void +PatchController::set_path(const Path& new_path) +{ + assert(m_model != NULL); + Path old_path = path(); + + // Rename nodes + for (NodeModelMap::const_iterator i = patch_model()->nodes().begin(); + i != patch_model()->nodes().end(); ++i) { + const NodeModel* const nm = (*i).second; + assert(nm != NULL); + NodeController* const nc = ((NodeController*)nm->controller()); + assert(nc != NULL); + nc->set_path(new_path.base_path() + nc->node_model()->name()); + } + +#ifdef DEBUG + // Be sure ports were renamed by their bridge nodes + for (list::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); + assert(pc != NULL); + assert(pc->path().parent()== new_path); + } +#endif + + App::instance().patch_tree()->patch_renamed(old_path, new_path); + + if (m_window != NULL) + m_window->patch_renamed(new_path); + + if (m_control_window != NULL) + m_control_window->set_title(new_path + " Controls"); + + if (m_module != NULL) { + assert(m_module->canvas() != NULL); + m_module->canvas()->rename_module(old_path.name(), new_path.name()); + assert(m_module->name() == new_path.name()); + } + + PatchController* parent = dynamic_cast( + patch_model()->parent()->controller()); + + if (parent != NULL && parent->window() != NULL) + parent->window()->node_renamed(old_path, new_path); + + remove_from_store(); + GtkObjectController::set_path(new_path); + add_to_store(); + + if (old_path.name() != new_path.name()) + parent->patch_model()->rename_node(old_path, new_path); +} + + +void +PatchController::enable() +{ + if (m_patch_view != NULL) + m_patch_view->enabled(true); + + patch_model()->enabled(true); + + App::instance().patch_tree()->patch_enabled(m_model->path()); +} + + +void +PatchController::disable() +{ + if (m_patch_view != NULL) + m_patch_view->enabled(false); + + patch_model()->enabled(false); + + App::instance().patch_tree()->patch_disabled(m_model->path()); +} + + +void +PatchController::create_module(OmFlowCanvas* canvas) +{ + //cerr << "Creating patch module " << m_model->path() << endl; + + assert(canvas != NULL); + assert(m_module == NULL); + + m_module = new SubpatchModule(canvas, this); + + + m_menu.remove(m_menu.items()[4]); + + // Add navigation menu items + Gtk::Menu::MenuList& items = m_menu.items(); + items.push_front(Gtk::Menu_Helpers::SeparatorElem()); + items.push_front(Gtk::Menu_Helpers::MenuElem("Browse to Patch", + sigc::mem_fun((SubpatchModule*)m_module, &SubpatchModule::browse_to_patch))); + items.push_front(Gtk::Menu_Helpers::MenuElem("Open Patch in New Window", + sigc::mem_fun(this, &PatchController::show_patch_window))); + + create_all_ports(); + + m_module->move_to(node_model()->x(), node_model()->y()); + m_module->store_location(); +} + + +void +PatchController::create_view() +{ + assert(m_patch_view == NULL); + + Glib::RefPtr xml = GladeFactory::new_glade_reference(); + + xml->get_widget_derived("patch_view_vbox", m_patch_view); + assert(m_patch_view != NULL); + m_patch_view->patch_controller(this); + assert(m_patch_view->canvas() != NULL); + + // Create modules for nodes + for (NodeModelMap::const_iterator i = patch_model()->nodes().begin(); + i != patch_model()->nodes().end(); ++i) { + + NodeModel* const nm = (*i).second; + + string val = nm->get_metadata("module-x"); + if (val != "") + nm->x(atof(val.c_str())); + val = nm->get_metadata("module-y"); + if (val != "") + nm->y(atof(val.c_str())); + + /* Set sane default coordinates if not set already yet */ + if (nm->x() == 0.0f && nm->y() == 0.0f) { + int x, y; + get_new_module_location(x, y); + nm->x(x); + nm->y(y); + } + + NodeController* nc = ((NodeController*)nm->controller()); + assert(nc != NULL); + if (nc->module() == NULL); + nc->create_module(m_patch_view->canvas()); + assert(nc->module() != NULL); + m_patch_view->canvas()->add_module(nc->module()); + } + + // Create connections + for (list::const_iterator i = patch_model()->connections().begin(); + i != patch_model()->connections().end(); ++i) { + create_connection(*i); + } + + // Set run checkbox + m_patch_view->enabled(patch_model()->enabled()); +} + + +/** Create a connection in the view (canvas). + */ +void +PatchController::create_connection(const ConnectionModel* cm) +{ + m_patch_view->canvas()->add_connection( + cm->src_port_path().parent().name(), + cm->src_port_path().name(), + cm->dst_port_path().parent().name(), + cm->dst_port_path().name()); + + // Disable control slider from destination node control window + + PortController* p = Store::instance().port(cm->dst_port_path()); + assert(p != NULL); + + if (p->control_panel() != NULL) + p->control_panel()->disable_port(p->path()); + // FIXME: don't use canvas as a model (search object store) + /*OmModule* m = (OmModule*)m_patch_view->canvas()->find_module( + cm->dst_port_path().parent().name()); + + if (m != NULL) { + OmPort* p = m->port(cm->dst_port_path().name()); + if (p != NULL && p->connections().size() == 1) { + p->model()->connected(true); + assert(m->node_model()->controller() != NULL); + NodeControlWindow* cw = (((NodeController*) + m->node_model()->controller())->control_window()); + if (cw != NULL) + cw->control_panel()->disable_port(cm->dst_port_path()); + } + }*/ +} + + +/** Add a subpatch to this patch. + */ +void +PatchController::add_subpatch(PatchController* patch) +{ + assert(patch != NULL); + assert(patch->patch_model() != NULL); + assert(patch->patch_model()->parent() == NULL); + + /*if (pm->x() == 0 && pm->y() == 0) { + int x, y; + parent_pc->get_new_module_location(x, y); + pm->x(x); + pm->y(y); + }*/ + + patch_model()->add_node(patch->patch_model()); + + if (m_patch_view != NULL) { + patch->create_module(m_patch_view->canvas()); + m_patch_view->canvas()->add_module(patch->module()); + patch->module()->resize(); + } +} + + +void +PatchController::add_node(NodeModel* nm) +{ + assert(nm != NULL); + assert(nm->parent() == NULL); + assert(nm->path().parent() == m_model->path()); + + if (patch_model()->get_node(nm->name()) != NULL) { + // Node already exists, ignore + delete nm; + } else { + // FIXME: Should PatchController really be responsible for creating these? + NodeController* nc = NULL; + + if (nm->plugin()->type() == PluginModel::DSSI) + nc = new DSSIController(nm); + else + nc = new NodeController(nm); + + assert(nc != NULL); + assert(nm->controller() == nc); + + // Check if this is a bridge node + PortModel* const pm = patch_model()->get_port(nm->path().name()); + if (pm != NULL) { + cerr << "Bridge node." << endl; + PortController* pc = ((PortController*)pm->controller()); + assert(pc != NULL); + nc->bridge_port(pc); + } + + nc->add_to_store(); + patch_model()->add_node(nm); + + if (m_patch_view != NULL) { + + int x, y; + get_new_module_location(x, y); + nm->x(x); + nm->y(y); + + // Set zoom to 1.0 so module isn't messed up (Death to GnomeCanvas) + float old_zoom = m_patch_view->canvas()->zoom(); + if (old_zoom != 1.0) + m_patch_view->canvas()->zoom(1.0); + + if (nc->module() == NULL) + nc->create_module(m_patch_view->canvas()); + assert(nc->module() != NULL); + m_patch_view->canvas()->add_module(nc->module()); + nc->module()->resize(); + + // Reset zoom + if (old_zoom != 1.0) { + m_patch_view->canvas()->zoom(old_zoom); + nc->module()->zoom(old_zoom); + } + } + } +} + + +/** Removes a node from this patch. + */ +void +PatchController::remove_node(const string& name) +{ + assert(name.find("/") == string::npos); + + // Update breadcrumbs if necessary + if (m_window != NULL) + m_window->node_removed(name); + + if (m_patch_view != NULL) { + assert(m_patch_view->canvas() != NULL); + m_patch_view->canvas()->remove_module(name); + } + + patch_model()->remove_node(name); +} + + +/** Add a port to this patch. + * + * Will add a port to the subpatch module and the control window, if they + * exist. + */ +void +PatchController::add_port(PortModel* pm) +{ + assert(pm != NULL); + assert(pm->parent() == NULL); + + //cerr << "[PatchController] Adding port " << pm->path() << endl; + + if (patch_model()->get_port(pm->name()) != NULL) { + cerr << "[PatchController] Ignoring duplicate port " + << pm->path() << endl; + delete pm; + return; + } + + node_model()->add_port(pm); + PortController* pc = new PortController(pm); + + // Handle bridge ports/nodes (this is uglier than it should be) + NodeController* nc = Store::instance().node(pm->path()); + if (nc != NULL) + nc->bridge_port(pc); + + if (m_module != NULL) { + pc->create_port(m_module); + m_module->resize(); + } + + if (m_control_window != NULL) { + assert(m_control_window->control_panel() != NULL); + m_control_window->control_panel()->add_port(pc); + m_control_window->resize(); + } + + // Enable "Controls" menuitem on module and patch window, if necessary + if (has_control_inputs()) + enable_controls_menuitem(); +} + + +/** Removes a port from this patch + */ +void +PatchController::remove_port(const Path& path, bool resize_module) +{ + assert(path.parent() == m_model->path()); + + //cerr << "[PatchController] Removing port " << path << endl; + + /* FIXME + if (m_control_panel != NULL) { + m_control_panel->remove_port(path); + if (m_control_window != NULL) { + assert(m_control_window->control_panel() == m_control_panel); + m_control_window->resize(); + } + }*/ + + // Remove port on module + if (m_module != NULL) { + assert(m_module->port(path.name()) != NULL); + m_module->remove_port(path.name(), resize_module); + assert(m_module->port(path.name()) == NULL); + } + + patch_model()->remove_port(path); + assert(patch_model()->get_port(path.name()) == NULL); + + // Disable "Controls" menuitem on module and patch window, if necessary + if (!has_control_inputs()) + disable_controls_menuitem(); +} + + +void +PatchController::connection(ConnectionModel* const cm) +{ + assert(cm != NULL); + + patch_model()->add_connection(cm); + + if (m_patch_view != NULL) + create_connection(cm); +} + + + +void +PatchController::disconnection(const Path& src_port_path, const Path& dst_port_path) +{ + const string& src_node_name = src_port_path.parent().name(); + const string& src_port_name = src_port_path.name(); + const string& dst_node_name = dst_port_path.parent().name(); + const string& dst_port_name = dst_port_path.name(); + + if (m_patch_view != NULL) + m_patch_view->canvas()->remove_connection( + src_node_name, src_port_name, dst_node_name, dst_port_name); + + patch_model()->remove_connection(src_port_path, dst_port_path); + + // Enable control slider in destination node control window + PortController* p = Store::instance().port(dst_port_path); + assert(p != NULL); + + if (p->control_panel() != NULL) + p->control_panel()->enable_port(p->path()); +} + + +/** Try to guess a suitable location for a new module. + */ +void +PatchController::get_new_module_location(int& x, int& y) +{ + assert(m_patch_view != NULL); + assert(m_patch_view->canvas() != NULL); + m_patch_view->canvas()->get_scroll_offsets(x, y); + x += 20; + y += 20; +} + + +void +PatchController::show_patch_window() +{ + if (m_window == NULL) { + Glib::RefPtr xml = GladeFactory::new_glade_reference(); + + xml->get_widget_derived("patch_win", m_window); + assert(m_window != NULL); + + if (m_patch_view == NULL) + create_view(); + + m_window->patch_controller(this); + } + + assert(m_window != NULL); + m_window->present(); +} + + +/** Become the parent of the patch view. + * + * Steals the view away from whatever window is currently showing it. + */ +void +PatchController::claim_patch_view() +{ + assert(m_patch_view != NULL); + + m_patch_view->hide(); + m_patch_view->reparent(m_patch_view_bin); +} + + +void +PatchController::show_control_window() +{ + assert(patch_model() != NULL); + + if (m_control_window == NULL) + m_control_window = new NodeControlWindow(this, patch_model()->poly()); + + if (m_control_window->control_panel()->num_controls() > 0) + m_control_window->present(); +} + + +void +PatchController::enable_controls_menuitem() +{ + if (m_window != NULL) + m_window->menu_view_control_window()->property_sensitive() = true; + + NodeController::enable_controls_menuitem(); +} + + +void +PatchController::disable_controls_menuitem() +{ + if (m_window != NULL) + m_window->menu_view_control_window()->property_sensitive() = false; + + NodeController::disable_controls_menuitem(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchController.h b/src/progs/gtk/PatchController.h new file mode 100644 index 00000000..de4af5e4 --- /dev/null +++ b/src/progs/gtk/PatchController.h @@ -0,0 +1,127 @@ +/* This file is part of Om. Copyright (C) 2006 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 PATCHCONTROLLER_H +#define PATCHCONTROLLER_H + +#include +#include +#include "NodeController.h" + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PortModel; +class ControlModel; +class ConnectionModel; +} + +using std::string; +using namespace LibOmClient; + +namespace OmGtk { + +class PatchWindow; +class SubpatchModule; +class Controller; +class OmFlowCanvas; +class NodeControlWindow; +class ControlPanel; +class PatchView; +class NodeController; + + +/** Controller for a patch. + * + * A patch is different from a port or node because there are two + * representations in the Gtk client - the window and the module in the parent + * patch (if applicable). So, this is a master class that contains both of + * those representations, and acts as the recipient of all patch related + * events (being the controller). + * + * \ingroup OmGtk + */ +class PatchController : public NodeController +{ +public: + PatchController(PatchModel* model); + virtual ~PatchController(); + + virtual void add_to_store(); + virtual void remove_from_store(); + + virtual void destroy(); + + virtual void metadata_update(const string& key, const string& value); + + void add_node(NodeModel* nm); + void remove_node(const string& name); + + virtual void add_port(PortModel* pm); + virtual void remove_port(const Path& path, bool resize_module); + + void connection(ConnectionModel* const cm); + void disconnection(const Path& src_port_path, const Path& dst_port_path); + void clear(); + + void add_subpatch(PatchController* patch); + + void get_new_module_location(int& x, int& y); + + void show_control_window(); + void show_patch_window(); + + void claim_patch_view(); + + void create_module(OmFlowCanvas* canvas); + void create_view(); + + PatchView* view() const { return m_patch_view; } + PatchWindow* window() const { return m_window; } + void window(PatchWindow* pw) { m_window = pw; } + + inline string name() const { return m_model->name(); } + inline const string& path() const { return m_model->path(); } + + void set_path(const Path& new_path); + + void enable(); + void disable(); + + PatchModel* patch_model() const { return (PatchModel*)m_model; } + + void enable_controls_menuitem(); + void disable_controls_menuitem(); + +private: + void create_connection(const ConnectionModel* cm); + + PatchWindow* m_window; ///< Window currently showing this patch + PatchView* m_patch_view; ///< View (canvas) of this patch + + /** Invisible bin used to store patch view when not shown by a patch window */ + Gtk::Alignment m_patch_view_bin; + + // Coordinates for next added plugin (used by canvas menu) + // 0 means "not set", ie guess at the best location + int m_module_x; + int m_module_y; +}; + + +} // namespace OmGtk + +#endif // PATCHCONTROLLER_H diff --git a/src/progs/gtk/PatchDescriptionWindow.cpp b/src/progs/gtk/PatchDescriptionWindow.cpp new file mode 100644 index 00000000..d10a9c0e --- /dev/null +++ b/src/progs/gtk/PatchDescriptionWindow.cpp @@ -0,0 +1,72 @@ +/* This file is part of Om. Copyright (C) 2006 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 "PatchDescriptionWindow.h" +#include +#include "PatchModel.h" + +namespace OmGtk { +using std::string; + + +PatchDescriptionWindow::PatchDescriptionWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml) +: Gtk::Window(cobject) +{ + glade_xml->get_widget("description_author_entry", m_author_entry); + glade_xml->get_widget("description_description_textview", m_textview); + glade_xml->get_widget("description_cancel_button", m_cancel_button); + glade_xml->get_widget("description_ok_button", m_ok_button); + + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &PatchDescriptionWindow::cancel_clicked)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &PatchDescriptionWindow::ok_clicked)); +} + + +/** Set the patch model this description is for. + * + * This function is a "post-constructor" - it MUST be called before using + * the window in any way. + */ +void +PatchDescriptionWindow::patch_model(PatchModel* patch_model) +{ + property_title() = patch_model->path() + " Properties"; + m_patch_model = patch_model; + m_author_entry->set_text(m_patch_model->get_metadata("author")); + m_textview->get_buffer()->set_text(m_patch_model->get_metadata("description")); +} + + +void +PatchDescriptionWindow::cancel_clicked() +{ + m_author_entry->set_text(m_patch_model->get_metadata("author")); + m_textview->get_buffer()->set_text(m_patch_model->get_metadata("description")); + hide(); +} + + +void +PatchDescriptionWindow::ok_clicked() +{ + m_patch_model->set_metadata("author", m_author_entry->get_text()); + m_patch_model->set_metadata("description", m_textview->get_buffer()->get_text()); + hide(); +} + + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchDescriptionWindow.h b/src/progs/gtk/PatchDescriptionWindow.h new file mode 100644 index 00000000..7c00faab --- /dev/null +++ b/src/progs/gtk/PatchDescriptionWindow.h @@ -0,0 +1,59 @@ +/* This file is part of Om. Copyright (C) 2006 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 PATCHDESCRIPTIONWINDOW_H +#define PATCHDESCRIPTIONWINDOW_H + +#include +#include +#include +using std::string; + +namespace LibOmClient { class PatchModel; } +using LibOmClient::PatchModel; + +namespace OmGtk { + + +/** Patch Description Window. + * + * Loaded by libglade as a derived object. + * + * \ingroup OmGtk + */ +class PatchDescriptionWindow : public Gtk::Window +{ +public: + PatchDescriptionWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); + + void patch_model(PatchModel* patch_model); + + void cancel_clicked(); + void ok_clicked(); + +private: + PatchModel* m_patch_model; + + Gtk::Entry* m_author_entry; + Gtk::TextView* m_textview; + Gtk::Button* m_cancel_button; + Gtk::Button* m_ok_button; +}; + + +} // namespace OmGtk + +#endif // PATCHDESCRIPTIONWINDOW_H diff --git a/src/progs/gtk/PatchTreeWindow.cpp b/src/progs/gtk/PatchTreeWindow.cpp new file mode 100644 index 00000000..065f4d6a --- /dev/null +++ b/src/progs/gtk/PatchTreeWindow.cpp @@ -0,0 +1,252 @@ +/* This file is part of Om. Copyright (C) 2006 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 "PatchTreeWindow.h" +#include "Controller.h" +#include "PatchController.h" +#include "PatchWindow.h" +#include "SubpatchModule.h" +#include "PatchModel.h" +#include "util/Path.h" + +using Om::Path; + +namespace OmGtk { + + +PatchTreeWindow::PatchTreeWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml) +: Gtk::Window(cobject), + m_enable_signal(true) +{ + xml->get_widget_derived("patches_treeview", m_patches_treeview); + + m_patch_treestore = Gtk::TreeStore::create(m_patch_tree_columns); + m_patches_treeview->set_window(this); + m_patches_treeview->set_model(m_patch_treestore); + Gtk::TreeViewColumn* name_col = Gtk::manage(new Gtk::TreeViewColumn( + "Patch", m_patch_tree_columns.name_col)); + Gtk::TreeViewColumn* enabled_col = Gtk::manage(new Gtk::TreeViewColumn( + "Run", m_patch_tree_columns.enabled_col)); + name_col->set_resizable(true); + name_col->set_expand(true); + + m_patches_treeview->append_column(*name_col); + m_patches_treeview->append_column(*enabled_col); + Gtk::CellRendererToggle* enabled_renderer = dynamic_cast( + m_patches_treeview->get_column_cell_renderer(1)); + enabled_renderer->property_activatable() = true; + + m_patch_tree_selection = m_patches_treeview->get_selection(); + + //m_patch_tree_selection->signal_changed().connect( + // sigc::mem_fun(this, &PatchTreeWindow::event_patch_selected)); + m_patches_treeview->signal_row_activated().connect( + sigc::mem_fun(this, &PatchTreeWindow::event_patch_activated)); + enabled_renderer->signal_toggled().connect( + sigc::mem_fun(this, &PatchTreeWindow::event_patch_enabled_toggled)); + + m_patches_treeview->columns_autosize(); +} + + +void +PatchTreeWindow::add_patch(PatchController* pc) +{ + PatchModel* const pm = pc->patch_model(); + + if (pm->parent() == NULL) { + Gtk::TreeModel::iterator iter = m_patch_treestore->append(); + Gtk::TreeModel::Row row = *iter; + if (pm->path() == "/") { + string root_name = Controller::instance().engine_url(); + // Hack off trailing '/' if it's there (ugly) + //if (root_name.substr(root_name.length()-1,1) == "/") + // root_name = root_name.substr(0, root_name.length()-1); + //root_name.append(":/"); + row[m_patch_tree_columns.name_col] = root_name; + } else { + row[m_patch_tree_columns.name_col] = pm->path().name(); + } + row[m_patch_tree_columns.enabled_col] = false; + row[m_patch_tree_columns.patch_controller_col] = pc; + m_patches_treeview->expand_row(m_patch_treestore->get_path(iter), true); + } else { + Gtk::TreeModel::Children children = m_patch_treestore->children(); + Gtk::TreeModel::iterator c = find_patch(children, pm->parent()->path()); + + if (c != children.end()) { + Gtk::TreeModel::iterator iter = m_patch_treestore->append(c->children()); + Gtk::TreeModel::Row row = *iter; + row[m_patch_tree_columns.name_col] = pm->path().name(); + row[m_patch_tree_columns.enabled_col] = false; + row[m_patch_tree_columns.patch_controller_col] = pc; + m_patches_treeview->expand_row(m_patch_treestore->get_path(iter), true); + } + } +} + + +void +PatchTreeWindow::remove_patch(const Path& path) +{ + Gtk::TreeModel::iterator i = find_patch(m_patch_treestore->children(), path); + if (i != m_patch_treestore->children().end()) + m_patch_treestore->erase(i); +} + + +Gtk::TreeModel::iterator +PatchTreeWindow::find_patch(Gtk::TreeModel::Children root, const Path& path) +{ + PatchController* pc = NULL; + + for (Gtk::TreeModel::iterator c = root.begin(); c != root.end(); ++c) { + pc = (*c)[m_patch_tree_columns.patch_controller_col]; + if (pc->model()->path() == path) { + return c; + } else if ((*c)->children().size() > 0) { + Gtk::TreeModel::iterator ret = find_patch(c->children(), path); + if (ret != c->children().end()) + return ret; + } + } + return root.end(); +} + +/* +void +PatchTreeWindow::event_patch_selected() +{ + Gtk::TreeModel::iterator active = m_patch_tree_selection->get_selected(); + if (active) { + Gtk::TreeModel::Row row = *active; + PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; + } +} +*/ + + +/** Show the context menu for the selected patch in the patches treeview. + */ +void +PatchTreeWindow::show_patch_menu(GdkEventButton* ev) +{ + Gtk::TreeModel::iterator active = m_patch_tree_selection->get_selected(); + if (active) { + Gtk::TreeModel::Row row = *active; + PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; + if (pc != NULL) + pc->show_menu(ev); + } +} + + +void +PatchTreeWindow::event_patch_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col) +{ + Gtk::TreeModel::iterator active = m_patch_treestore->get_iter(path); + Gtk::TreeModel::Row row = *active; + PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; + + pc->show_patch_window(); +} + + +void +PatchTreeWindow::event_patch_enabled_toggled(const Glib::ustring& path_str) +{ + Gtk::TreeModel::Path path(path_str); + Gtk::TreeModel::iterator active = m_patch_treestore->get_iter(path); + Gtk::TreeModel::Row row = *active; + + PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; + Glib::ustring patch_path = pc->model()->path(); + + assert(pc != NULL); + + if ( ! pc->patch_model()->enabled()) { + if (m_enable_signal) + Controller::instance().enable_patch(patch_path); + pc->enable(); + row[m_patch_tree_columns.enabled_col] = true; + } else { + if (m_enable_signal) + Controller::instance().disable_patch(patch_path); + pc->disable(); + row[m_patch_tree_columns.enabled_col] = false; + } +} + + +void +PatchTreeWindow::patch_enabled(const Path& path) +{ + m_enable_signal = false; + + Gtk::TreeModel::iterator i + = find_patch(m_patch_treestore->children(), path); + + if (i != m_patch_treestore->children().end()) { + Gtk::TreeModel::Row row = *i; + row[m_patch_tree_columns.enabled_col] = true; + } else { + cerr << "[PatchTreeWindow] Unable to find patch " << path << endl; + } + + m_enable_signal = true; +} + + +void +PatchTreeWindow::patch_disabled(const Path& path) +{ + m_enable_signal = false; + + Gtk::TreeModel::iterator i + = find_patch(m_patch_treestore->children(), path); + + if (i != m_patch_treestore->children().end()) { + Gtk::TreeModel::Row row = *i; + row[m_patch_tree_columns.enabled_col] = false; + } else { + cerr << "[PatchTreeWindow] Unable to find patch " << path << endl; + } + + m_enable_signal = true; +} + + +void +PatchTreeWindow::patch_renamed(const Path& old_path, const Path& new_path) +{ + m_enable_signal = false; + + Gtk::TreeModel::iterator i + = find_patch(m_patch_treestore->children(), old_path); + + if (i != m_patch_treestore->children().end()) { + Gtk::TreeModel::Row row = *i; + row[m_patch_tree_columns.name_col] = new_path.name(); + } else { + cerr << "[PatchTreeWindow] Unable to find patch " << old_path << endl; + } + + m_enable_signal = true; +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchTreeWindow.h b/src/progs/gtk/PatchTreeWindow.h new file mode 100644 index 00000000..3177e5e2 --- /dev/null +++ b/src/progs/gtk/PatchTreeWindow.h @@ -0,0 +1,105 @@ +/* This file is part of Om. Copyright (C) 2006 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 PATCHTREEWINDOW_H +#define PATCHTREEWINDOW_H + +#include +#include +#include "util/Path.h" + + +using namespace Om; +using Om::Path; + +namespace OmGtk { + +class PatchWindow; +class PatchController; +class PatchTreeView; + + +/** Window with a TreeView of all loaded patches. + * + * \ingroup OmGtk + */ +class PatchTreeWindow : public Gtk::Window +{ +public: + PatchTreeWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); + + void patch_enabled(const Path& path); + void patch_disabled(const Path& path); + void patch_renamed(const Path& old_path, const Path& new_path); + + void add_patch(PatchController* pc); + void remove_patch(const Path& path); + void show_patch_menu(GdkEventButton* ev); + +protected: + //void event_patch_selected(); + void event_patch_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col); + void event_patch_enabled_toggled(const Glib::ustring& path_str); + + Gtk::TreeModel::iterator find_patch(Gtk::TreeModel::Children root, const Path& path); + + PatchTreeView* m_patches_treeview; + + struct PatchTreeModelColumns : public Gtk::TreeModel::ColumnRecord + { + PatchTreeModelColumns() + { add(name_col); add(enabled_col); add(patch_controller_col); } + + Gtk::TreeModelColumn name_col; + Gtk::TreeModelColumn enabled_col; + Gtk::TreeModelColumn patch_controller_col; + }; + + bool m_enable_signal; + PatchTreeModelColumns m_patch_tree_columns; + Glib::RefPtr m_patch_treestore; + Glib::RefPtr m_patch_tree_selection; +}; + + +/** Derived TreeView class to support context menus for patches */ +class PatchTreeView : public Gtk::TreeView +{ +public: + PatchTreeView(BaseObjectType* cobject, const Glib::RefPtr& xml) + : Gtk::TreeView(cobject) + {} + + void set_window(PatchTreeWindow* win) { m_window = win; } + + bool on_button_press_event(GdkEventButton* ev) { + bool ret = Gtk::TreeView::on_button_press_event(ev); + + if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3)) + m_window->show_patch_menu(ev); + + return ret; + } + +private: + PatchTreeWindow* m_window; + +}; // struct PatchTreeView + + +} // namespace OmGtk + +#endif // PATCHTREEWINDOW_H diff --git a/src/progs/gtk/PatchView.cpp b/src/progs/gtk/PatchView.cpp new file mode 100644 index 00000000..e89428e9 --- /dev/null +++ b/src/progs/gtk/PatchView.cpp @@ -0,0 +1,119 @@ +/* This file is part of Om. Copyright (C) 2006 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 "PatchView.h" +#include +#include +#include +#include "App.h" +#include "OmFlowCanvas.h" +#include "PatchController.h" +#include "LoadPluginWindow.h" +#include "PatchModel.h" +#include "NewSubpatchWindow.h" +#include "LoadSubpatchWindow.h" +#include "NodeControlWindow.h" +#include "PatchDescriptionWindow.h" +#include "PatchTreeWindow.h" +#include "Controller.h" + +namespace OmGtk { + + +PatchView::PatchView(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::Box(cobject), + m_patch(NULL), + m_canvas(NULL), + m_enable_signal(true) +{ + property_visible() = false; + + xml->get_widget("patch_canvas_scrolledwindow", m_canvas_scrolledwindow); + xml->get_widget("patch_zoom_scale", m_zoom_slider); + xml->get_widget("patch_polyphony_label", m_polyphony_label); + xml->get_widget("patch_process_checkbutton", m_process_checkbutton); + + m_zoom_slider->signal_value_changed().connect( sigc::mem_fun(this, &PatchView::zoom_changed)); + m_process_checkbutton->signal_toggled().connect(sigc::mem_fun(this, &PatchView::process_toggled)); +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +PatchView::patch_controller(PatchController* pc) +{ + //m_patch = new PatchController(pm, controller); + m_patch = pc; + + m_canvas = new OmFlowCanvas(pc, 1600*2, 1200*2); + + m_canvas_scrolledwindow->add(*m_canvas); + //m_canvas->show(); + //m_canvas_scrolledwindow->show(); + + char txt[4]; + snprintf(txt, 8, "%zd", pc->patch_model()->poly()); + m_polyphony_label->set_text(txt); + + //m_description_window->patch_model(pc->model()); +} + + +void +PatchView::show_control_window() +{ + if (m_patch != NULL) + m_patch->show_control_window(); +} + + +void +PatchView::zoom_changed() +{ + float z = m_zoom_slider->get_value(); + m_canvas->zoom(z); +} + + +void +PatchView::process_toggled() +{ + if (!m_enable_signal) + return; + + if (m_process_checkbutton->get_active()) { + Controller::instance().enable_patch(m_patch->model()->path()); + App::instance().patch_tree()->patch_enabled(m_patch->model()->path()); + } else { + Controller::instance().disable_patch(m_patch->model()->path()); + App::instance().patch_tree()->patch_disabled(m_patch->model()->path()); + } +} + + +void +PatchView::enabled(bool e) +{ + m_enable_signal = false; + m_process_checkbutton->set_active(e); + m_enable_signal = true; +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchView.h b/src/progs/gtk/PatchView.h new file mode 100644 index 00000000..ff6aebf9 --- /dev/null +++ b/src/progs/gtk/PatchView.h @@ -0,0 +1,86 @@ +/* This file is part of Om. Copyright (C) 2006 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 PATCHVIEW_H +#define PATCHVIEW_H + +#include +#include +#include +#include + +using std::string; + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PortModel; +class ControlModel; +class MetadataModel; +} +using namespace LibOmClient; + + +namespace OmGtk { + +class PatchController; +class OmFlowCanvas; +class LoadPluginWindow; +class NewSubpatchWindow; +class LoadSubpatchWindow; +class NewSubpatchWindow; +class NodeControlWindow; +class PatchDescriptionWindow; +class SubpatchModule; +class OmPort; + + +/** The patch specific contents of a PatchWindow (ie the canvas and whatever else). + * + * \ingroup OmGtk + */ +class PatchView : public Gtk::Box +{ +public: + PatchView(BaseObjectType* cobject, const Glib::RefPtr& glade_xml); + + void patch_controller(PatchController* pc); + + OmFlowCanvas* canvas() const { return m_canvas; } + PatchController* patch_controller() const { return m_patch; } + + void show_control_window(); + void zoom_changed(); + void process_toggled(); + + void enabled(bool e); + +private: + PatchController* m_patch; + OmFlowCanvas* m_canvas; + + Gtk::ScrolledWindow* m_canvas_scrolledwindow; + Gtk::HScale* m_zoom_slider; + Gtk::Label* m_polyphony_label; + Gtk::CheckButton* m_process_checkbutton; + + bool m_enable_signal; +}; + + +} // namespace OmGtk + +#endif // PATCHVIEW_H diff --git a/src/progs/gtk/PatchWindow.cpp b/src/progs/gtk/PatchWindow.cpp new file mode 100644 index 00000000..1513d473 --- /dev/null +++ b/src/progs/gtk/PatchWindow.cpp @@ -0,0 +1,532 @@ +/* This file is part of Om. Copyright (C) 2006 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 "PatchWindow.h" +#include +#include +#include +#include "App.h" +#include "PatchView.h" +#include "OmFlowCanvas.h" +#include "PatchController.h" +#include "LoadPluginWindow.h" +#include "PatchModel.h" +#include "NewSubpatchWindow.h" +#include "LoadPatchWindow.h" +#include "LoadSubpatchWindow.h" +#include "NodeControlWindow.h" +#include "PatchDescriptionWindow.h" +#include "ConfigWindow.h" +#include "MessagesWindow.h" +#include "PatchTreeWindow.h" +#include "Controller.h" +#include "BreadCrumb.h" +#include "Store.h" + +namespace OmGtk { + + +PatchWindow::PatchWindow(BaseObjectType* cobject, const Glib::RefPtr& xml) +: Gtk::Window(cobject), + m_patch(NULL), + m_load_plugin_window(NULL), + m_new_subpatch_window(NULL), + m_enable_signal(true), + m_position_stored(false), + m_x(0), + m_y(0) +{ + property_visible() = false; + + xml->get_widget("patch_win_vbox", m_vbox); + xml->get_widget("patch_win_viewport", m_viewport); + xml->get_widget("patch_win_breadcrumb_box", m_breadcrumb_box); + //xml->get_widget("patch_win_status_bar", m_status_bar); + xml->get_widget("patch_open_menuitem", m_menu_open); + xml->get_widget("patch_open_into_menuitem", m_menu_open_into); + xml->get_widget("patch_save_menuitem", m_menu_save); + xml->get_widget("patch_save_as_menuitem", m_menu_save_as); + xml->get_widget("patch_close_menuitem", m_menu_close); + xml->get_widget("patch_configuration_menuitem", m_menu_configuration); + xml->get_widget("patch_quit_menuitem", m_menu_quit); + xml->get_widget("patch_quit_and_kill_menuitem", m_menu_quit_and_kill); + xml->get_widget("patch_view_control_window_menuitem", m_menu_view_control_window); + xml->get_widget("patch_description_menuitem", m_menu_view_patch_description); + xml->get_widget("patch_fullscreen_menuitem", m_menu_fullscreen); + xml->get_widget("patch_clear_menuitem", m_menu_clear); + xml->get_widget("patch_destroy_menuitem", m_menu_destroy_patch); + xml->get_widget("patch_add_plugin_menuitem", m_menu_add_plugin); + xml->get_widget("patch_add_new_subpatch_menuitem", m_menu_new_subpatch); + xml->get_widget("patch_add_subpatch_from_file_menuitem", m_menu_load_subpatch); + xml->get_widget("patch_view_messages_window_menuitem", m_menu_view_messages_window); + xml->get_widget("patch_view_patch_tree_window_menuitem", m_menu_view_patch_tree_window); + xml->get_widget("patch_help_about_menuitem", m_menu_help_about); + + xml->get_widget_derived("load_plugin_win", m_load_plugin_window); + xml->get_widget_derived("new_subpatch_win", m_new_subpatch_window); + xml->get_widget_derived("load_patch_win", m_load_patch_window); + xml->get_widget_derived("load_subpatch_win", m_load_subpatch_window); + xml->get_widget_derived("patch_description_win", m_description_window); + + //m_load_plugin_window->set_transient_for(*this); + m_new_subpatch_window->set_transient_for(*this); + m_load_patch_window->set_transient_for(*this); + m_load_subpatch_window->set_transient_for(*this); + m_description_window->set_transient_for(*this); + + m_menu_view_control_window->property_sensitive() = false; + //m_status_bar->push(Controller::instance().engine_url()); + //m_status_bar->pack_start(*Gtk::manage(new Gtk::Image(Gtk::Stock::CONNECT, Gtk::ICON_SIZE_MENU)), false, false); + + m_menu_open->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_open)); + m_menu_open_into->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_open_into)); + m_menu_save->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_save)); + m_menu_save_as->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_save_as)); + m_menu_close->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_close)); + m_menu_quit->signal_activate().connect( + sigc::mem_fun(App::instance(), &App::quit)); + m_menu_quit_and_kill->signal_activate().connect( + sigc::mem_fun(App::instance(), &App::quit_and_kill)); + m_menu_configuration->signal_activate().connect( + sigc::mem_fun(App::instance().configuration_dialog(), &ConfigWindow::show)); + m_menu_fullscreen->signal_toggled().connect( + sigc::mem_fun(this, &PatchWindow::event_fullscreen_toggled)); + m_menu_view_control_window->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::show_control_window)); + m_menu_view_patch_description->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::show_description_window)); + m_menu_destroy_patch->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_destroy)); + m_menu_clear->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_clear)); + m_menu_add_plugin->signal_activate().connect( + sigc::mem_fun(m_load_plugin_window, &LoadPluginWindow::present)); + m_menu_new_subpatch->signal_activate().connect( + sigc::mem_fun(m_new_subpatch_window, &NewSubpatchWindow::present)); + m_menu_load_subpatch->signal_activate().connect( + sigc::mem_fun(m_load_subpatch_window, &LoadSubpatchWindow::present)); + m_menu_view_messages_window->signal_activate().connect( + sigc::mem_fun(App::instance().messages_dialog(), &MessagesWindow::present)); + m_menu_view_patch_tree_window->signal_activate().connect( + sigc::mem_fun(App::instance().patch_tree(), &PatchTreeWindow::present)); + + // Temporary workaround for Gtkmm 2.4 (no AboutDialog) + if (App::instance().about_dialog() != NULL) + m_menu_help_about->signal_activate().connect( + sigc::mem_fun(App::instance().about_dialog(), &Gtk::Dialog::present)); + + App::instance().add_patch_window(this); +} + + +PatchWindow::~PatchWindow() +{ + App::instance().remove_patch_window(this); + + hide(); + + delete m_new_subpatch_window; + delete m_load_subpatch_window; +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +PatchWindow::patch_controller(PatchController* pc) +{ + m_enable_signal = false; + + assert(pc != NULL); + assert(m_patch != pc); + assert(m_patch == NULL || + pc->model()->path() != m_patch->model()->path()); + + PatchController* old_pc = m_patch; + if (old_pc != NULL) { + assert(old_pc->window() == NULL || old_pc->window() == this); + old_pc->claim_patch_view(); + old_pc->window(NULL); + } + + m_patch = pc; + + if (pc->view() == NULL) + pc->create_view(); + assert(pc->view() != NULL); + + PatchView* const patch_view = pc->view(); + assert(patch_view != NULL); + patch_view->reparent(*m_viewport); + pc->window(this); + show_all(); + + assert(m_load_plugin_window != NULL); + assert(m_new_subpatch_window != NULL); + assert(m_load_patch_window != NULL); + assert(m_load_subpatch_window != NULL); + + m_load_patch_window->patch_controller(m_patch); + m_load_plugin_window->patch_controller(m_patch); + m_new_subpatch_window->patch_controller(m_patch); + m_load_subpatch_window->patch_controller(m_patch); + + m_menu_view_control_window->property_sensitive() = pc->has_control_inputs(); + + int width, height; + get_size(width, height); + patch_view->canvas()->scroll_to( + ((int)patch_view->canvas()->width() - width)/2, + ((int)patch_view->canvas()->height() - height)/2); + + set_title(m_patch->model()->path()); + + m_description_window->patch_model(pc->patch_model()); + + + // Setup breadcrumbs box + // FIXME: this is filthy + + // Moving to a parent patch, depress correct button + if (old_pc != NULL && + old_pc->model()->path().substr(0, pc->model()->path().length()) + == pc->model()->path()) { + for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { + if ((*i)->patch() == pc) + (*i)->set_active(true); + else if ((*i)->patch() == old_pc) + (*i)->set_active(false); + } + + // Rebuild breadcrumbs from scratch (yeah, laziness..) + } else { + rebuild_breadcrumbs(); + } + + if (pc->model()->path() == "/") + m_menu_destroy_patch->set_sensitive(false); + else + m_menu_destroy_patch->set_sensitive(true); + + assert(old_pc == NULL || old_pc->window() != this); + assert(m_patch == pc); + assert(m_patch->window() == this); + + m_enable_signal = true; +} + + +/** Destroys current breadcrumbs and rebuilds from scratch. + * + * (Needs to be called when a patch is cleared to eliminate children crumbs) + */ +void +PatchWindow::rebuild_breadcrumbs() +{ + // Empty existing breadcrumbs + for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) + m_breadcrumb_box->remove(**i); + m_breadcrumbs.clear(); + + // Add new ones + string path = m_patch->path(); // To be chopped up, starting at the left + string but_name; // Name on breadcrumb button + string but_path; // Full path breadcrumb represents + + // Add root + assert(path[0] == '/'); + BreadCrumb* but = manage(new BreadCrumb(this, Store::instance().patch("/"))); + m_breadcrumb_box->pack_start(*but, false, false, 1); + m_breadcrumbs.push_back(but); + path = path.substr(1); // hack off leading slash + + // Add the rest + while (path.length() > 0) { + if (path.find("/") != string::npos) { + but_name = path.substr(0, path.find("/")); + but_path += string("/") + path.substr(0, path.find("/")); + path = path.substr(path.find("/")+1); + } else { + but_name = path; + but_path += string("/") + path; + path = ""; + } + BreadCrumb* but = manage(new BreadCrumb(this, Store::instance().patch(but_path))); + m_breadcrumb_box->pack_start(*but, false, false, 1); + m_breadcrumbs.push_back(but); + } + (*m_breadcrumbs.back()).set_active(true); + +} + + +void +PatchWindow::breadcrumb_clicked(BreadCrumb* crumb) +{ + if (m_enable_signal) { + PatchController* const pc = crumb->patch(); + assert(pc != NULL); + + if (pc == m_patch) { + crumb->set_active(true); + } else if (pc->window() != NULL && pc->window()->is_visible()) { + pc->show_patch_window(); + crumb->set_active(false); + } else { + patch_controller(pc); + } + } +} + + +void +PatchWindow::show_control_window() +{ + if (m_patch != NULL) + m_patch->show_control_window(); +} + + +void +PatchWindow::show_description_window() +{ + m_description_window->show(); +} + + +/** Notification a node has been removed from the PatchView this window + * currently contains. + * + * This is used to update the breadcrumbs in case the Node is a patch which has + * a button present in the breadcrumbs that needs to be removed. + */ +void +PatchWindow::node_removed(const string& name) +{ + for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { + if ((*i)->patch()->path() == m_patch->model()->base_path() + name) { + for (list::iterator j = i; j != m_breadcrumbs.end(); ) { + BreadCrumb* bc = *j; + j = m_breadcrumbs.erase(j); + m_breadcrumb_box->remove(*bc); + } + break; + } + } +} + + +/** Same as @a node_removed, but for renaming. + */ +void +PatchWindow::node_renamed(const string& old_path, const string& new_path) +{ + for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { + if ((*i)->patch()->model()->path() == old_path) + (*i)->path(new_path); + } +} + + +/** Notification the patch this window is currently showing was renamed. + */ +void +PatchWindow::patch_renamed(const string& new_path) +{ + set_title(new_path); + for (list::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { + if ((*i)->patch() == m_patch) + (*i)->path(new_path); + } +} + + +void +PatchWindow::event_open() +{ + m_load_patch_window->set_replace(); + m_load_patch_window->present(); +} + +void +PatchWindow::event_open_into() +{ + m_load_patch_window->set_merge(); + m_load_patch_window->present(); +} + + +void +PatchWindow::event_save() +{ + PatchModel* const model = m_patch->patch_model(); + + if (model->filename() == "") + event_save_as(); + else + Controller::instance().save_patch(model, model->filename(), false); +} + + +void +PatchWindow::event_save_as() +{ + Gtk::FileChooserDialog dialog(*this, "Save Patch", Gtk::FILE_CHOOSER_ACTION_SAVE); + + Gtk::VBox* box = dialog.get_vbox(); + Gtk::Label warning("Warning: Recursively saving will overwrite any subpatch files \ + without confirmation."); + box->pack_start(warning, false, false, 2); + Gtk::CheckButton recursive_checkbutton("Recursively save all subpatches"); + box->pack_start(recursive_checkbutton, false, false, 0); + recursive_checkbutton.show(); + + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + + // Set current folder to most sensible default + const string& current_filename = m_patch->patch_model()->filename(); + if (current_filename.length() > 0) + dialog.set_filename(current_filename); + else if (App::instance().configuration()->patch_folder().length() > 0) + dialog.set_current_folder(App::instance().configuration()->patch_folder()); + + int result = dialog.run(); + bool recursive = recursive_checkbutton.get_active(); + + assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); + + if (result == Gtk::RESPONSE_OK) { + string filename = dialog.get_filename(); + if (filename.length() < 4 || filename.substr(filename.length()-3) != ".om") + filename += ".om"; + + bool confirm = false; + std::fstream fin; + fin.open(filename.c_str(), std::ios::in); + if (fin.is_open()) { // File exists + string msg = "File already exists! Are you sure you want to overwrite "; + msg += filename + "?"; + Gtk::MessageDialog confirm_dialog(*this, + msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + if (confirm_dialog.run() == Gtk::RESPONSE_YES) + confirm = true; + else + confirm = false; + } else { // File doesn't exist + confirm = true; + } + fin.close(); + + if (confirm) { + Controller::instance().save_patch(m_patch->patch_model(), filename, recursive); + m_patch->patch_model()->filename(filename); + } + } + App::instance().configuration()->set_patch_folder(dialog.get_current_folder()); +} + + +void +PatchWindow::on_show() +{ + if (m_position_stored) + move(m_x, m_y); + + Gtk::Window::on_show(); +} + + +void +PatchWindow::on_hide() +{ + m_position_stored = true; + get_position(m_x, m_y); + Gtk::Window::on_hide(); +} + + +bool +PatchWindow::on_delete_event(GdkEventAny* ev) +{ + event_close(); + return true; // destroy window +} + + +bool +PatchWindow::on_key_press_event(GdkEventKey* event) +{ + if (event->keyval == GDK_Delete) { + if (m_patch != NULL && m_patch->view() != NULL) { + assert(m_patch->view()->canvas() != NULL); + m_patch->view()->canvas()->destroy_selected(); + } + return true; + } else { + return Gtk::Window::on_key_press_event(event); + } +} + + +void +PatchWindow::event_close() +{ + if (App::instance().num_open_patch_windows() > 1) { + hide(); + } else { + Gtk::MessageDialog d(*this, "This is the last remaining open Om patch\ +window. Closing this window will exit OmGtk (the engine will remain running).\n\n\ +Are you sure you want to quit?", + true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL, true); + int ret = d.run(); + if (ret == Gtk::RESPONSE_OK) + App::instance().quit(); + } +} + + +void +PatchWindow::event_destroy() +{ + Controller::instance().destroy(m_patch->model()->path()); +} + + +void +PatchWindow::event_clear() +{ + Controller::instance().clear_patch(m_patch->model()->path()); +} + +void +PatchWindow::event_fullscreen_toggled() +{ + if (m_menu_fullscreen->get_active()) + fullscreen(); + else + unfullscreen(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchWindow.h b/src/progs/gtk/PatchWindow.h new file mode 100644 index 00000000..54ea11ef --- /dev/null +++ b/src/progs/gtk/PatchWindow.h @@ -0,0 +1,142 @@ +/* This file is part of Om. Copyright (C) 2006 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 PATCHWINDOW_H +#define PATCHWINDOW_H + +#include +#include +#include +#include +#include + +using std::string; using std::list; + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PortModel; +class ControlModel; +class MetadataModel; +} +using namespace LibOmClient; + + +namespace OmGtk { + +class PatchController; +class OmFlowCanvas; +class PatchView; +class LoadPluginWindow; +class LoadPatchWindow; +class NewSubpatchWindow; +class LoadSubpatchWindow; +class NewSubpatchWindow; +class NodeControlWindow; +class PatchDescriptionWindow; +class SubpatchModule; +class OmPort; +class BreadCrumb; + + +/** A window for a patch. + * + * \ingroup OmGtk + */ +class PatchWindow : public Gtk::Window +{ +public: + PatchWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml); + ~PatchWindow(); + + void patch_controller(PatchController* pc); + + PatchController* patch_controller() const { return m_patch; } + LoadPluginWindow* load_plugin_window() const { return m_load_plugin_window; } + LoadSubpatchWindow* load_subpatch_window() const { return m_load_subpatch_window; } + NewSubpatchWindow* new_subpatch_window() const { return m_new_subpatch_window; } + + void show_control_window(); + void show_description_window(); + + // Breadcrumb management + void node_removed(const string& name); + void node_renamed(const string& old_path, const string& new_path); + void patch_renamed(const string& new_path); + void rebuild_breadcrumbs(); + void breadcrumb_clicked(BreadCrumb* crumb); + + Gtk::MenuItem* menu_view_control_window() { return m_menu_view_control_window; } + +protected: + void on_show(); + void on_hide(); + bool on_delete_event(GdkEventAny* ev); + bool on_key_press_event(GdkEventKey* event); + +private: + void event_open(); + void event_open_into(); + void event_save(); + void event_save_as(); + void event_close(); + void event_destroy(); + void event_clear(); + void event_fullscreen_toggled(); + + PatchController* m_patch; + LoadPluginWindow* m_load_plugin_window; + LoadPatchWindow* m_load_patch_window; + NewSubpatchWindow* m_new_subpatch_window; + LoadSubpatchWindow* m_load_subpatch_window; + PatchDescriptionWindow* m_description_window; + + bool m_enable_signal; + bool m_position_stored; + int m_x; + int m_y; + + Gtk::MenuItem* m_menu_open; + Gtk::MenuItem* m_menu_open_into; + Gtk::MenuItem* m_menu_save; + Gtk::MenuItem* m_menu_save_as; + Gtk::MenuItem* m_menu_configuration; + Gtk::MenuItem* m_menu_close; + Gtk::MenuItem* m_menu_quit; + Gtk::MenuItem* m_menu_quit_and_kill; + Gtk::CheckMenuItem* m_menu_fullscreen; + Gtk::MenuItem* m_menu_clear; + Gtk::MenuItem* m_menu_destroy_patch; + Gtk::MenuItem* m_menu_view_control_window; + Gtk::MenuItem* m_menu_view_patch_description; + Gtk::MenuItem* m_menu_add_plugin; + Gtk::MenuItem* m_menu_new_subpatch; + Gtk::MenuItem* m_menu_load_subpatch; + Gtk::MenuItem* m_menu_view_messages_window; + Gtk::MenuItem* m_menu_view_patch_tree_window; + Gtk::MenuItem* m_menu_help_about; + + Gtk::VBox* m_vbox; + Gtk::Viewport* m_viewport; + Gtk::HBox* m_breadcrumb_box; + list m_breadcrumbs; + //Gtk::Statusbar* m_status_bar; +}; + + +} // namespace OmGtk + +#endif // PATCHWINDOW_H diff --git a/src/progs/gtk/PortController.cpp b/src/progs/gtk/PortController.cpp new file mode 100644 index 00000000..ec05541b --- /dev/null +++ b/src/progs/gtk/PortController.cpp @@ -0,0 +1,143 @@ +/* This file is part of Om. Copyright (C) 2006 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 "PortController.h" +#include "OmModule.h" +#include "PortModel.h" +#include "ControlPanel.h" +#include "OmPort.h" +#include "Store.h" + +namespace OmGtk { + + +PortController::PortController(PortModel* model) +: GtkObjectController(model), + m_port(NULL), + m_control_panel(NULL) +{ + assert(model != NULL); + assert(model->parent() != NULL); + assert(model->controller() == NULL); + + model->set_controller(this); +} + + +void +PortController::add_to_store() +{ + Store::instance().add_object(this); +} + + +void +PortController::remove_from_store() +{ + Store::instance().remove_object(this); +} + + +void +PortController::destroy() +{ + assert(m_model->parent() != NULL); + NodeController* parent = (NodeController*)m_model->parent()->controller(); + assert(parent != NULL); + + if (m_control_panel != NULL) + m_control_panel->remove_port(path()); + + parent->remove_port(path(), false); +} + + +void +PortController::metadata_update(const string& key, const string& value) +{ + // FIXME: double lookups + + //cerr << path() << ": " << key << " = " << value << endl; + + if (key == "user-min") { + port_model()->user_min(atof(value.c_str())); + if (m_control_panel != NULL) + m_control_panel->set_range_min(m_model->path(), atof(value.c_str())); + } else if (key == "user-max") { + port_model()->user_max(atof(value.c_str())); + if (m_control_panel != NULL) + m_control_panel->set_range_max(m_model->path(), atof(value.c_str())); + } + + GtkObjectController::metadata_update(key, value); +} + + +void +PortController::control_change(float value) +{ + // FIXME: double lookups + + port_model()->value(value); + + if (m_control_panel != NULL) + m_control_panel->set_control(port_model()->path(), value); +} + + +/** "Register" a control panel that is monitoring this port. + * + * The OmPort will handle notifying the ControlPanel when state + * changes occur, etc. + */ +void +PortController::set_control_panel(ControlPanel* cp) +{ + assert(m_control_panel == NULL); + m_control_panel = cp; +} + + +void +PortController::set_path(const Path& new_path) +{ + // Change port name on module, if view exists + if (m_port != NULL) + m_port->set_name(new_path.name()); + + if (m_control_panel != NULL) + m_control_panel->rename_port(m_model->path(), new_path); + + m_model->set_path(new_path); +} + + +/** Create the visible port on a canvas module. + * + * Does not resize the module, caller's responsibility to do so if necessary. + */ +void +PortController::create_port(OmModule* module) +{ + assert(module != NULL); + + m_port = new OmPort(module, port_model()); + module->add_port(m_port, false); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/PortController.h b/src/progs/gtk/PortController.h new file mode 100644 index 00000000..cc2f9dc3 --- /dev/null +++ b/src/progs/gtk/PortController.h @@ -0,0 +1,75 @@ +/* This file is part of Om. Copyright (C) 2006 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 PORTCONTROLLER_H +#define PORTCONTROLLER_H + +#include +#include +#include "GtkObjectController.h" + +using std::string; +using namespace LibOmClient; + +namespace LibOmClient { + class MetadataModel; + class PortModel; +} + +namespace OmGtk { + +class Controller; +class OmPort; +class ControlPanel; +class OmModule; + + +/** Controller for a port on a (non-patch) node. + * + * \ingroup OmGtk + */ +class PortController : public GtkObjectController +{ +public: + PortController(PortModel* model); + virtual ~PortController() {} + + virtual void destroy(); + + virtual void add_to_store(); + virtual void remove_from_store(); + + virtual void metadata_update(const string& key, const string& value); + + void create_port(OmModule* module); + void set_path(const Path& new_path); + + void control_change(float value); + + ControlPanel* control_panel() const { return m_control_panel; } + void set_control_panel(ControlPanel* cp); + + PortModel* port_model() const { return (PortModel*)m_model; } + +private: + OmPort* m_port; ///< Canvas module port + ControlPanel* m_control_panel; ///< Control panel that contains this port +}; + + +} // namespace OmGtk + +#endif // PORTCONTROLLER_H diff --git a/src/progs/gtk/RenameWindow.cpp b/src/progs/gtk/RenameWindow.cpp new file mode 100644 index 00000000..bde9a2c1 --- /dev/null +++ b/src/progs/gtk/RenameWindow.cpp @@ -0,0 +1,113 @@ +/* This file is part of Om. Copyright (C) 2006 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 "RenameWindow.h" +#include +#include +#include "Controller.h" +#include "ObjectModel.h" +#include "GtkObjectController.h" +#include "Store.h" +using std::string; + +namespace OmGtk { + + +RenameWindow::RenameWindow(BaseObjectType* cobject, const Glib::RefPtr& glade_xml) +: Gtk::Window(cobject) +{ + glade_xml->get_widget("rename_name_entry", m_name_entry); + glade_xml->get_widget("rename_message_label", m_message_label); + glade_xml->get_widget("rename_cancel_button", m_cancel_button); + glade_xml->get_widget("rename_ok_button", m_ok_button); + + m_name_entry->signal_changed().connect(sigc::mem_fun(this, &RenameWindow::name_changed)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &RenameWindow::cancel_clicked)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &RenameWindow::ok_clicked)); + + m_ok_button->property_sensitive() = false; +} + + +/** Set the object this window is renaming. + * This function MUST be called before using this object in any way. + */ +void +RenameWindow::set_object(GtkObjectController* object) +{ + m_object = object; + m_name_entry->set_text(object->path().name()); +} + + +/** Called every time the user types into the name input box. + * Used to display warning messages, and enable/disable the rename button. + */ +void +RenameWindow::name_changed() +{ + assert(m_name_entry != NULL); + assert(m_message_label != NULL); + assert(m_object->model() != NULL); + assert(m_object->model()->parent() != NULL); + + string name = m_name_entry->get_text(); + if (name.find("/") != string::npos) { + m_message_label->set_text("Name may not contain '/'"); + m_ok_button->property_sensitive() = false; + //} else if (m_object->parent()->patch_model()->get_node(name) != NULL) { + } else if (Store::instance().object(m_object->model()->parent()->base_path() + name) != NULL) { + m_message_label->set_text("An object already exists with that name."); + m_ok_button->property_sensitive() = false; + } else if (name.length() == 0) { + m_message_label->set_text(""); + m_ok_button->property_sensitive() = false; + } else { + m_message_label->set_text(""); + m_ok_button->property_sensitive() = true; + } +} + + +void +RenameWindow::cancel_clicked() +{ + cout << "cancel\n"; + m_name_entry->set_text(""); + hide(); +} + + +/** Rename the object. + * + * It shouldn't be possible for this to be called with an invalid name set + * (since the Rename button should be deactivated). This is just shinification + * though - the engine will handle invalid names gracefully. + */ +void +RenameWindow::ok_clicked() +{ + string name = m_name_entry->get_text(); + assert(name.length() > 0); + assert(name.find("/") == string::npos); + + Controller::instance().rename(m_object->model()->path(), name); + + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/RenameWindow.h b/src/progs/gtk/RenameWindow.h new file mode 100644 index 00000000..81dc96e3 --- /dev/null +++ b/src/progs/gtk/RenameWindow.h @@ -0,0 +1,57 @@ +/* This file is part of Om. Copyright (C) 2006 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 RENAMEWINDOW_H +#define RENAMEWINDOW_H + +#include +#include + + +namespace OmGtk { + +class GtkObjectController; + + +/** 'New Patch' Window. + * + * Loaded by libglade as a derived object. + * + * \ingroup OmGtk + */ +class RenameWindow : public Gtk::Window +{ +public: + RenameWindow(BaseObjectType* cobject, const Glib::RefPtr& refGlade); + + void set_object(GtkObjectController* object); + +private: + void name_changed(); + void cancel_clicked(); + void ok_clicked(); + + GtkObjectController* m_object; + + Gtk::Entry* m_name_entry; + Gtk::Label* m_message_label; + Gtk::Button* m_cancel_button; + Gtk::Button* m_ok_button; +}; + +} // namespace OmGtk + +#endif // RENAMEWINDOW_H diff --git a/src/progs/gtk/Store.cpp b/src/progs/gtk/Store.cpp new file mode 100644 index 00000000..97e556c9 --- /dev/null +++ b/src/progs/gtk/Store.cpp @@ -0,0 +1,155 @@ +/* This file is part of Om. Copyright (C) 2006 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 "Store.h" +#include "GtkObjectController.h" +#include "PatchController.h" +#include "NodeController.h" +#include "PortController.h" +#include "PluginModel.h" +#include "SigClientInterface.h" + +namespace OmGtk { + +Store::Store(SigClientInterface& emitter) +{ + //emitter.new_plugin_sig.connect(sigc::mem_fun(this, &Store::add_plugin)); + emitter.object_destroyed_sig.connect(sigc::mem_fun(this, &Store::destruction_event)); + emitter.new_plugin_sig.connect(sigc::mem_fun(this, &Store::new_plugin_event)); +} + +void +Store::add_object(GtkObjectController* object) +{ + assert(object->path() != ""); + assert(m_objects.find(object->path()) == m_objects.end()); + + m_objects[object->path()] = object; + + cout << "[Store] Added " << object->path() << endl; +} + + +void +Store::remove_object(GtkObjectController* object) +{ + if (!object) + return; + + map::iterator i + = m_objects.find(object->model()->path()); + + if (i != m_objects.end()) { + assert((*i).second == object); + m_objects.erase(i); + } else { + cerr << "[App] Unable to find object " << object->model()->path() + << " to remove." << endl; + } + + cout << "[Store] Removed " << object->path() << endl; +} + + +GtkObjectController* +Store::object(const string& path) const +{ + assert(path.length() > 0); + map::const_iterator i = m_objects.find(path); + if (i == m_objects.end()) + return NULL; + else + return (*i).second; +} + + +PatchController* +Store::patch(const string& path) const +{ + assert(path.length() > 0); + map::const_iterator i = m_objects.find(path); + if (i == m_objects.end()) + return NULL; + else + return dynamic_cast((*i).second); +} + + +NodeController* +Store::node(const string& path) const +{ + assert(path.length() > 0); + map::const_iterator i = m_objects.find(path); + if (i == m_objects.end()) + return NULL; + else + return dynamic_cast((*i).second); +} + + +PortController* +Store::port(const string& path) const +{ + assert(path.length() > 0); + map::const_iterator i = m_objects.find(path); + if (i == m_objects.end()) { + return NULL; + } else { + // Normal port + PortController* const pc = dynamic_cast((*i).second); + if (pc != NULL) + return pc; + + // Patch port (corresponding Node is in store) + NodeController* const nc = dynamic_cast((*i).second); + if (nc != NULL) + return nc->as_port(); // Patch port (maybe) + } + + return NULL; +} + + +void +Store::add_plugin(const PluginModel* pm) +{ + if (m_plugins.find(pm->uri()) != m_plugins.end()) { + cerr << "DUPE! " << pm->uri() << endl; + delete m_plugins[pm->uri()]; + } + + m_plugins[pm->uri()] = pm; +} + + +/* ****** Slots ******** */ + +void +Store::destruction_event(const string& path) +{ + remove_object(object(path)); +} + +void +Store::new_plugin_event(const string& type, const string& uri, const string& name) +{ + PluginModel* const p = new PluginModel(type, uri); + p->name(name); + add_plugin(p); +} + +} // namespace OmGtk + diff --git a/src/progs/gtk/Store.h b/src/progs/gtk/Store.h new file mode 100644 index 00000000..9fb4b270 --- /dev/null +++ b/src/progs/gtk/Store.h @@ -0,0 +1,75 @@ +/* This file is part of Om. Copyright (C) 2006 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 STORE_H +#define STORE_H + +#include +#include +#include +using std::string; using std::map; + +namespace LibOmClient { class PatchModel; class PluginModel; class SigClientInterface; } +using namespace LibOmClient; + +namespace OmGtk { + +class GtkObjectController; +class PatchController; +class NodeController; +class PortController; + +/** Singeton which holds all "Om Objects" for easy/fast lookup + * + * \ingroup OmGtk + */ +class Store { +public: + GtkObjectController* object(const string& path) const; + PatchController* patch(const string& path) const; + NodeController* node(const string& path) const; + PortController* port(const string& path) const; + + void add_object(GtkObjectController* object); + void remove_object(GtkObjectController* object); + + size_t num_objects() { return m_objects.size(); } + + void add_plugin(const PluginModel* pm); + const map& plugins() const { return m_plugins; } + + static void instantiate(SigClientInterface& emitter) + { if (!_instance) _instance = new Store(emitter); } + + inline static Store& instance() { assert(_instance); return *_instance; } + +private: + Store(SigClientInterface& emitter); + + static Store* _instance; + + // Slots for SigClientInterface signals + void destruction_event(const string& path); + void new_plugin_event(const string& type, const string& uri, const string& name); + + map m_objects; ///< Keyed by Om path + map m_plugins; ///< Keyed by URI +}; + + +} // namespace OmGtk + +#endif // STORE_H diff --git a/src/progs/gtk/SubpatchModule.cpp b/src/progs/gtk/SubpatchModule.cpp new file mode 100644 index 00000000..9c0e78e4 --- /dev/null +++ b/src/progs/gtk/SubpatchModule.cpp @@ -0,0 +1,102 @@ +/* This file is part of Om. Copyright (C) 2006 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 "SubpatchModule.h" +#include +#include +#include "OmModule.h" +#include "NodeControlWindow.h" +#include "PatchModel.h" +#include "PatchWindow.h" +#include "OmFlowCanvas.h" +#include "PatchController.h" +#include "OmPort.h" +#include "Controller.h" +using std::cerr; using std::cout; using std::endl; + +namespace OmGtk { + + +SubpatchModule::SubpatchModule(OmFlowCanvas* canvas, PatchController* patch) +: OmModule(canvas, patch), + m_patch(patch) +{ + assert(canvas != NULL); + assert(patch != NULL); +} + + +void +SubpatchModule::add_om_port(PortModel* pm, bool resize_to_fit) +{ + OmPort* port = new OmPort(this, pm); + + port->signal_event().connect( + sigc::bind(sigc::mem_fun(m_canvas, &OmFlowCanvas::port_event), port)); + + Module::add_port(port, resize_to_fit); +} + + +void +SubpatchModule::on_double_click(GdkEventButton* event) +{ + assert(m_patch != NULL); + + // If window is visible + if (m_patch->window() != NULL + && m_patch->window()->is_visible()) { + m_patch->show_patch_window(); // just raise it + // No window visible + } else { + if (event->state & GDK_SHIFT_MASK) + m_patch->show_patch_window(); // open a new window + else + browse_to_patch(); + } +} + + + +/** Browse to this patch in current (parent's) window. */ +void +SubpatchModule::browse_to_patch() +{ + assert(m_patch->model()->parent() != NULL); + PatchController* pc = (PatchController*)m_patch->model()->parent()->controller(); + assert(pc != NULL); + assert(pc->window() != NULL); + + assert(pc->window() != NULL); + pc->window()->patch_controller(m_patch); +} + + + +void +SubpatchModule::show_dialog() +{ + m_patch->show_control_window(); +} + + +void +SubpatchModule::menu_remove() +{ + Controller::instance().destroy(m_patch->model()->path()); +} + +} // namespace OmGtk diff --git a/src/progs/gtk/SubpatchModule.h b/src/progs/gtk/SubpatchModule.h new file mode 100644 index 00000000..162779d7 --- /dev/null +++ b/src/progs/gtk/SubpatchModule.h @@ -0,0 +1,69 @@ +/* This file is part of Om. Copyright (C) 2006 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 SUBPATCHMODULE_H +#define SUBPATCHMODULE_H + +#include +#include +#include "OmModule.h" +#include "PatchController.h" +using std::string; using std::list; + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PortModel; +class PatchWindow; +} +using namespace LibOmClient; + +namespace OmGtk { + +class OmFlowCanvas; +class NodeControlWindow; +class PatchController; + + +/** A module to represent a subpatch + * + * \ingroup OmGtk + */ +class SubpatchModule : public OmModule +{ +public: + SubpatchModule(OmFlowCanvas* canvas, PatchController* controller); + virtual ~SubpatchModule() {} + + void add_om_port(PortModel* pm, bool resize=true); + + void on_double_click(GdkEventButton* ev); + + void show_dialog(); + void browse_to_patch(); + void menu_remove(); + + PatchController* patch() { return m_patch; } + +protected: + PatchController* m_patch; +}; + + +} // namespace OmGtk + +#endif // SUBPATCHMODULE_H diff --git a/src/progs/gtk/cmdline.c b/src/progs/gtk/cmdline.c new file mode 100644 index 00000000..11fcd108 --- /dev/null +++ b/src/progs/gtk/cmdline.c @@ -0,0 +1,149 @@ +/* + File autogenerated by gengetopt version 2.10 + generated with the following command: + gengetopt + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + + +#include +#include +#include + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#include "cmdline.h" + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); +} + +void +cmdline_parser_print_help (void) +{ + cmdline_parser_print_version (); + printf("\n" + "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); + printf(" -h --help Print help and exit\n"); + printf(" -V --version Print version and exit\n"); + printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n"); + printf(" -pINT --client-port=INT Client port to listen on\n"); +} + + +static char *gengetopt_strdup (const char *s); + +/* gengetopt_strdup() */ +/* strdup.c replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) +{ + int c; /* Character of the parsed option. */ + int missing_required_options = 0; + + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->engine_url_given = 0 ; + args_info->client_port_given = 0 ; +#define clear_args() { \ + args_info->engine_url_arg = NULL; \ +} + + clear_args(); + + optarg = 0; + optind = 1; + opterr = 1; + optopt = '?'; + + while (1) + { + int option_index = 0; + char *stop_char; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "engine-url", 1, NULL, 'u' }, + { "client-port", 1, NULL, 'p' }, + { NULL, 0, NULL, 0 } + }; + + stop_char = 0; + c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index); + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + clear_args (); + cmdline_parser_print_help (); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + clear_args (); + cmdline_parser_print_version (); + exit (EXIT_SUCCESS); + + case 'u': /* Om engine URL to connect to. */ + if (args_info->engine_url_given) + { + fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->engine_url_given = 1; + args_info->engine_url_arg = gengetopt_strdup (optarg); + break; + + case 'p': /* Client port to listen on. */ + if (args_info->client_port_given) + { + fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->client_port_given = 1; + args_info->client_port_arg = strtol (optarg,&stop_char,0); + break; + + + case 0: /* Long option with no short option */ + + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + exit (EXIT_FAILURE); + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); + abort (); + } /* switch */ + } /* while */ + + + if ( missing_required_options ) + exit (EXIT_FAILURE); + + return 0; +} diff --git a/src/progs/gtk/cmdline.ggo b/src/progs/gtk/cmdline.ggo new file mode 100644 index 00000000..d62cf521 --- /dev/null +++ b/src/progs/gtk/cmdline.ggo @@ -0,0 +1,7 @@ +# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) + +package "om_gtk - A GUI client for the Om realtime modular synthesizer" + +option "engine-url" u "Om engine URL to connect to" string no +option "client-port" p "Client port to listen on" int no + diff --git a/src/progs/gtk/cmdline.h b/src/progs/gtk/cmdline.h new file mode 100644 index 00000000..e404ac2e --- /dev/null +++ b/src/progs/gtk/cmdline.h @@ -0,0 +1,45 @@ +/* cmdline.h */ + +/* File autogenerated by gengetopt version 2.10 */ + +#ifndef CMDLINE_H +#define CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +#define CMDLINE_PARSER_PACKAGE "om_gtk - A GUI client for the Om realtime modular synthesizer" +#endif + +#ifndef CMDLINE_PARSER_VERSION +#define CMDLINE_PARSER_VERSION VERSION +#endif + +struct gengetopt_args_info +{ + char * engine_url_arg; /* Om engine URL to connect to. */ + int client_port_arg; /* Client port to listen on. */ + + int help_given ; /* Whether help was given. */ + int version_given ; /* Whether version was given. */ + int engine_url_given ; /* Whether engine-url was given. */ + int client_port_given ; /* Whether client-port was given. */ + +} ; + +int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); + +void cmdline_parser_print_help(void); +void cmdline_parser_print_version(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/src/progs/gtk/main.cpp b/src/progs/gtk/main.cpp new file mode 100644 index 00000000..702d52f9 --- /dev/null +++ b/src/progs/gtk/main.cpp @@ -0,0 +1,103 @@ +/* This file is part of Om. Copyright (C) 2006 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 "cmdline.h" +#include "ConnectWindow.h" +#include "App.h" +#include "Store.h" +#include "Controller.h" +#include "Configuration.h" +#include "GtkClientInterface.h" +#ifdef HAVE_LASH + #include "LashController.h" +#endif +#include "ThreadedSigClientInterface.h" +using Om::Shared::ClientInterface; + +using namespace OmGtk; + + +class OSCSigEmitter : public OSCListener, public ThreadedSigClientInterface { +public: + OSCSigEmitter(size_t queue_size, int listen_port) + : Om::Shared::ClientInterface() + , OSCListener(listen_port) + , ThreadedSigClientInterface(queue_size) + { + Glib::signal_timeout().connect( + sigc::mem_fun((ThreadedSigClientInterface*)this, + &ThreadedSigClientInterface::emit_signals), + 5, G_PRIORITY_DEFAULT_IDLE); + } +}; + + +int +main(int argc, char** argv) +{ + string engine_url = "osc.udp://localhost:16180"; + int client_port = 0; + + /* **** Parse command line options **** */ + gengetopt_args_info args_info; + if (cmdline_parser (argc, argv, &args_info) != 0) + return 1; + + if (args_info.engine_url_given) + engine_url = args_info.engine_url_arg; + if (args_info.client_port_given) + client_port = args_info.client_port_arg; + + // FIXME: + client_port = 16181; + + Gnome::Canvas::init(); + Gtk::Main gtk_main(argc, argv); + + OSCSigEmitter* emitter = new OSCSigEmitter(1024, 16181); + + //CountedPtr emitter(new OSCSigEmitter(1024, 16181)); + + /* Instantiate all singletons */ + App::instantiate(); + Store::instantiate(*(SigClientInterface*)emitter); + ControlInterface* gtk_interface = App::instance().control_interface(); + assert(gtk_interface); + + //GtkClientInterface::instantiate(App::instance().control_interface(), client_port); + Controller::instantiate(engine_url); + + /* Load settings */ + App::instance().configuration()->load_settings(); + App::instance().configuration()->apply_settings(); + + #ifdef HAVE_LASH + lash_args_t* lash_args = lash_extract_args(&argc, &argv); + #endif + + //gtk_main.signal_quit().connect(sigc::ptr_fun(cleanup)); + + #ifdef HAVE_LASH + LashController* lash_controller = new LashController(lash_args); + #endif + + App::instance().connect_window()->start(CountedPtr(emitter)); + gtk_main.run(); + + return 0; +} + diff --git a/src/progs/gtk/om-icon.png b/src/progs/gtk/om-icon.png new file mode 100644 index 00000000..b26dd942 Binary files /dev/null and b/src/progs/gtk/om-icon.png differ diff --git a/src/progs/gtk/om_gtk.glade b/src/progs/gtk/om_gtk.glade new file mode 100644 index 00000000..abe5f254 --- /dev/null +++ b/src/progs/gtk/om_gtk.glade @@ -0,0 +1,3555 @@ + + + + + + + 1 + Om + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + GTK_PACK_DIRECTION_LTR + GTK_PACK_DIRECTION_LTR + + + + True + _File + True + + + + + + + True + _Open (Replace)... + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Open _Into (Import)... + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Save this patch + _Save + True + + + + + + True + gtk-save + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save this patch to a specific filename + Save _As... + True + + + + + + True + gtk-save-as + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Configure OmGtk + Confi_guration + True + + + + + + True + gtk-preferences + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Close this window (patch will not be destroyed) + Close _Window + True + + + + + + True + gtk-close + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Quit OmGtk (Om engine will continue running) + _Quit + True + + + + + + True + gtk-quit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Quit OmGtk and kill the Om engine + Quit and _Kill Engine + True + + + + + + True + gtk-stop + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Patch + True + + + + + + + True + Fullscreen + True + False + + + + + + + + True + + + + + + True + View/Edit controls for this patch + _Controls + True + + + + + + True + gtk-preferences + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + View/Edit description for this patch + Descr_iption + True + + + + + True + gtk-edit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Remove all objects from patch + Clear + True + + + + + True + gtk-clear + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Destoy this patch (remove it from the engine) + _Destroy + True + + + + + True + gtk-delete + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Insert + True + + + + + + + + True + Insert a plugin into this patch + _Plugin... + True + + + + + True + gtk-execute + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Insert a new, empty subpatch into this patchch + _New Patch... + True + + + + + + True + gtk-new + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Load a subpatch from a file and insert it into this patch + _Load Patch... + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + False + Using this menu will place items randomly - right click! + Right click on canvas to manually place an object + True + + + + + True + gtk-info + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Windows + True + + + + + + + + True + View all patches in the engine as a heirarchial list + _Patch Tree + True + + + + + + True + gtk-index + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + View error messages from the engine + _Messages + True + + + + + + True + gtk-dialog-error + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Help + True + + + + + + + + True + gtk-about + True + + + + + + + + + + 0 + False + False + + + + + + True + False + 0 + + + + + + + 0 + False + False + + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_NEVER + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_NONE + + + + + + + + + 0 + True + True + + + + + + + + 8 + Load Plugin + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + 640 + 480 + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 10 + + + + True + False + 10 + + + + True + False + 5 + + + + True + False + 1 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + All plugins available for loading + True + True + True + True + True + False + False + False + + + + + 0 + True + True + + + + + + True + 3 + 3 + False + 12 + 0 + + + + True + Clear filter text (show all plugins) + True + gtk-clear + True + GTK_RELIEF_NORMAL + True + + + 2 + 3 + 0 + 1 + fill + + + + + + + True + Module Name: + False + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + Close dialog + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + 2 + 3 + 2 + 3 + fill + + + + + + + True + + + 1 + 2 + 1 + 2 + fill + + + + + + True + + + 0 + 1 + 1 + 2 + fill + fill + + + + + + True + + + 2 + 3 + 1 + 2 + fill + fill + + + + + + True + False + 0 + + + + True + Name of new Module + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + + True + True + Polyphonic + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 8 + False + False + + + + + + True + Add selected plugin to patch + True + gtk-add + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + 1 + 2 + 2 + 3 + 6 + fill + fill + + + + + + True + Search string to filter plugin list + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + 6 + + + + + + + True + Name contains: + False + True + + + 0 + 1 + 0 + 1 + fill + fill + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + 8 + 320 + Create Subpatch + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + 2 + 2 + False + 0 + 0 + + + + True + Name: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + 5 + fill + expand + + + + + + True + Polyphony: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + 5 + fill + expand + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 1 + 2 + 1 + 2 + 4 + fill + + + + + + + True + True + True + True + True + 0 + + True + * + True + + + 1 + 2 + 0 + 1 + 4 + + + + + + 0 + True + True + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_END + 4 + + + + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-ok + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Create + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + True + True + + + + + + + + GTK_FILE_CHOOSER_ACTION_OPEN + True + False + False + False + Load Subpatch + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 10 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + True + gtk-open + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 2 + 4 + False + 4 + 12 + + + + True + <b>Name: </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + <b>Polyphony: </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Use the name stored in the patch file + True + Load from file + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + Use the polyphony value stored in the patch file + True + Load from file + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + False + 0 + + + + True + Specify a custom polyphony value for new patch + True + Specify: + True + GTK_RELIEF_NORMAL + True + False + False + True + load_subpatch_poly_from_file_radio + + + 0 + False + False + + + + + + True + False + Specify a custom polyphony value for new patch + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 1000 1 10 10 + + + 0 + False + True + + + + + 3 + 4 + 1 + 2 + fill + fill + + + + + + True + Set polyphony to the same value as the parent (containing) patch + True + Same as parent (?) + True + GTK_RELIEF_NORMAL + True + False + False + True + load_subpatch_poly_from_file_radio + + + 2 + 3 + 1 + 2 + fill + + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 0 + 1 + fill + + + + + + + True + False + 0 + + + + True + Specify the name for the new patch + True + Specify: + True + GTK_RELIEF_NORMAL + True + False + False + True + load_subpatch_name_from_file_radio + + + 0 + False + False + + + + + + True + False + Specify the name for the new patch + True + True + True + 0 + + True + * + True + + + 0 + False + True + + + + + 3 + 4 + 0 + 1 + fill + + + + + 0 + False + True + + + + + + + + GTK_FILE_CHOOSER_ACTION_OPEN + True + False + False + False + Load Patch + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + + + + False + 8 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + True + gtk-open + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 1 + 4 + False + 4 + 12 + + + + True + <b>Polyphony: </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + Use the same polyphony as the current patch + True + Keep current + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + Use the polyphony value stored in the patch file + True + Load from file + True + GTK_RELIEF_NORMAL + True + False + False + True + load_patch_poly_from_current_radio + + + 2 + 3 + 0 + 1 + fill + + + + + + + True + False + 0 + + + + True + True + Specify: + True + GTK_RELIEF_NORMAL + True + False + False + True + load_patch_poly_from_current_radio + + + 0 + False + False + + + + + + True + False + Specify a custom polyphony value for new patch + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 0 + False + True + + + + + 3 + 4 + 0 + 1 + fill + fill + + + + + 0 + False + True + + + + + + + + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + 2 + 2 + False + 0 + 0 + + + + True + False + 0 + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_NONE + + + + True + False + 0 + + + + + + + + + + + 0 + True + True + + + + + + True + True + 0 + + + + Apply changed controls to all voices + True + All Voices + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + False + 5 + + + + True + Apply changed controls to one voice only + True + Specific Voice: + True + GTK_RELIEF_NORMAL + True + False + False + True + control_panel_all_voices_radio + + + 0 + False + False + + + + + + True + False + Voice control changes are applied to + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + False + False + 1 1 100 1 10 10 + + + 0 + True + True + + + + + 0 + False + False + + + + + 5 + False + True + + + + + 0 + 1 + 0 + 1 + + + + + + True + False + 0 + + + + 1 + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Enable audio processing for this patch + True + Run + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + True + + + + + + True + True + False + True + + + 0 + False + False + + + + + + True + False + 0 + + + + True + Polyphony: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + ? + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 10 + True + False + + + + + + True + True + False + True + + + 0 + False + False + + + + + + True + False + 0 + + + + True + Zoom: + False + True + GTK_JUSTIFY_LEFT + False + False + 0.469999998808 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + False + False + + + + + + 90 + True + True + False + GTK_POS_RIGHT + 1 + GTK_UPDATE_CONTINUOUS + False + 1.10638296604 0.25 2 0.25 0 0 + + + 0 + False + False + + + + + 0 + False + True + + + + + 0 + False + False + + + + + 0 + 1 + 1 + 2 + fill + + + + + + + + 8 + 400 + 180 + Error Messages + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 6 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + Error messages from the engine since the last time "Clear" was pressed + True + False + False + False + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + False + 5 + 5 + 0 + 5 + 5 + 0 + + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_END + 6 + + + + True + False + True + True + gtk-clear + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + + + + + + + + 8 + Configuration + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 6 + + + + True + 2 + 2 + False + 0 + 0 + + + + True + <b>Patch Search Path: </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + + + + + + + True + <i>Example: /foo/bar:/home/john/patches:/usr/share/om/patches</i> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + 0 + True + False + + + + + + True + GTK_BUTTONBOX_END + 6 + + + + True + Save these settings for future sessions + True + gtk-save + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + Apply these settings to this session only + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + + + + + + + + 8 + 400 + 200 + Patch Description + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 6 + + + + True + False + 5 + + + + True + Author: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + A short description of the patch to be included in the patch file + True + True + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + True + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_END + 5 + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + Apply these changes to be saved the next time the patch is saved + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + False + + + + + + + + 250 + Rename + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 0 + + + + True + False + 0 + + + + True + New name: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + True + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 6 + False + True + + + + + + True + GTK_BUTTONBOX_END + 5 + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-ok + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Rename + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + True + + + + + + + + 6 + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + <b>Node</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 12 + True + False + 6 + + + + True + False + 4 + + + + True + Path: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + False + False + + + + + + True + False + True + Polyphonic + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 6 + True + True + + + + + + 240 + True + <b>Plugin</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 12 + True + 3 + 2 + False + 6 + 10 + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + Type: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + URI: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + Name: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 2 + 3 + fill + + + + + + 0 + True + True + + + + + + + + True + OmGtk + Copyright (C) 2005-2006 Dave Robillard + A client for the Om modular synthesizer + Licensed under the GNU GPL, Version 2. + +See COPYING file included with Om, or http://www.gnu.org/licenses/gpl.txt for more information + False + http://om-synth.nongnu.org + + Author: + Dave Robillard <drobilla@connect.carelton.ca> + +Contributors: + Lars Luthman - DSSI enhancements, bugfixes + Mario Lang - SuperCollider bindings, bugfixes + Leonard Ritter - Python bindings + + Usability / UI Design: + Thorsten Wilms + translator-credits + om-icon.png + + + + 8 + 320 + 340 + Patches + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 3 + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + All patches loaded in the engine + True + True + True + False + True + False + False + False + + + + + + + + 6 + Connecting to Engine + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + True + False + 6 + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + + + + True + True + True + GTK_RELIEF_NORMAL + True + 0 + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-execute + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + _Launch Engine + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + 0 + False + False + GTK_PACK_END + + + + + + 2 + True + False + 0 + + + + True + False + 0 + + + + True + om-icon.png + 0.5 + 0.5 + 6 + 0 + + + 0 + False + False + + + + + + 5 + True + True + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.10000000149 + + PANGO_ELLIPSIZE_NONE + + + 0 + False + False + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + Connecting to engine + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 4 + False + False + + + + + 0 + True + True + + + + + + + diff --git a/src/progs/gtk/om_gtk.glade.bak b/src/progs/gtk/om_gtk.glade.bak new file mode 100644 index 00000000..7714d1f3 --- /dev/null +++ b/src/progs/gtk/om_gtk.glade.bak @@ -0,0 +1,3555 @@ + + + + + + + 1 + Om + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + GTK_PACK_DIRECTION_LTR + GTK_PACK_DIRECTION_LTR + + + + True + _File + True + + + + + + + True + _Open (Replace)... + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Open _Into (Import)... + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Save this patch + _Save + True + + + + + + True + gtk-save + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save this patch to a specific filename + Save _As... + True + + + + + + True + gtk-save-as + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Configure OmGtk + Confi_guration + True + + + + + + True + gtk-preferences + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Close this window (patch will not be destroyed) + Close _Window + True + + + + + + True + gtk-close + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + Quit OmGtk (Om engine will continue running) + _Quit + True + + + + + + True + gtk-quit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Quit OmGtk and kill the Om engine + Quit and _Kill Engine + True + + + + + + True + gtk-stop + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Patch + True + + + + + + + True + Fullscreen + True + False + + + + + + + + True + + + + + + True + View/Edit controls for this patch + _Controls + True + + + + + + True + gtk-preferences + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + View/Edit description for this patch + Descr_iption + True + + + + + True + gtk-edit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Remove all objects from patch + Clear + True + + + + + True + gtk-clear + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Destoy this patch (remove it from the engine) + _Destroy + True + + + + + True + gtk-delete + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Insert + True + + + + + + + + True + Insert a plugin into this patch + _Plugin... + True + + + + + True + gtk-execute + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Insert a new, empty subpatch into this patchch + _New Patch... + True + + + + + + True + gtk-new + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Load a subpatch from a file and insert it into this patch + _Load Patch... + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + False + Using this menu will place items randomly - right click! + Right click on canvas to manually place an object + True + + + + + True + gtk-info + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Windows + True + + + + + + + + True + View all patches in the engine as a heirarchial list + _Patch Tree + True + + + + + + True + gtk-index + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + View error messages from the engine + _Messages + True + + + + + + True + gtk-dialog-error + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Help + True + + + + + + + + True + gtk-about + True + + + + + + + + + + 0 + False + False + + + + + + True + False + 0 + + + + + + + 0 + False + False + + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_NEVER + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_NONE + + + + + + + + + 0 + True + True + + + + + + + + 8 + Load Plugin + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + 640 + 480 + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 10 + + + + True + False + 10 + + + + True + False + 5 + + + + True + False + 1 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + All plugins available for loading + True + True + True + True + True + False + False + False + + + + + 0 + True + True + + + + + + True + 3 + 3 + False + 12 + 0 + + + + True + Clear filter text (show all plugins) + True + gtk-clear + True + GTK_RELIEF_NORMAL + True + + + 2 + 3 + 0 + 1 + fill + + + + + + + True + Module Name: + False + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + Close dialog + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + 2 + 3 + 2 + 3 + fill + + + + + + + True + + + 1 + 2 + 1 + 2 + fill + + + + + + True + + + 0 + 1 + 1 + 2 + fill + fill + + + + + + True + + + 2 + 3 + 1 + 2 + fill + fill + + + + + + True + False + 0 + + + + True + Name of new Module + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + + True + True + Polyphonic + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 8 + False + False + + + + + + True + Add selected plugin to patch + True + gtk-add + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + 1 + 2 + 2 + 3 + 6 + fill + fill + + + + + + True + Search string to filter plugin list + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + 6 + + + + + + + True + Name contains: + False + True + + + 0 + 1 + 0 + 1 + fill + fill + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + 8 + 320 + Create Subpatch + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + 2 + 2 + False + 0 + 0 + + + + True + Name: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + 5 + fill + expand + + + + + + True + Polyphony: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + 5 + fill + expand + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 1 + 2 + 1 + 2 + 4 + fill + + + + + + + True + True + True + True + True + 0 + + True + * + True + + + 1 + 2 + 0 + 1 + 4 + + + + + + 0 + True + True + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_END + 4 + + + + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-ok + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Create + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + True + True + + + + + + + + GTK_FILE_CHOOSER_ACTION_OPEN + True + False + False + False + Load Subpatch + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 24 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + True + gtk-open + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 2 + 4 + False + 4 + 12 + + + + True + <b>Name: </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + <b>Polyphony: </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Use the name stored in the patch file + True + Load from file + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + Use the polyphony value stored in the patch file + True + Load from file + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + False + 0 + + + + True + Specify a custom polyphony value for new patch + True + Specify: + True + GTK_RELIEF_NORMAL + True + False + False + True + load_subpatch_poly_from_file_radio + + + 0 + False + False + + + + + + True + False + Specify a custom polyphony value for new patch + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 1000 1 10 10 + + + 0 + False + True + + + + + 3 + 4 + 1 + 2 + fill + fill + + + + + + True + Set polyphony to the same value as the parent (containing) patch + True + Same as parent (?) + True + GTK_RELIEF_NORMAL + True + False + False + True + load_subpatch_poly_from_file_radio + + + 2 + 3 + 1 + 2 + fill + + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 0 + 1 + fill + + + + + + + True + False + 0 + + + + True + Specify the name for the new patch + True + Specify: + True + GTK_RELIEF_NORMAL + True + False + False + True + load_subpatch_name_from_file_radio + + + 0 + False + False + + + + + + True + False + Specify the name for the new patch + True + True + True + 0 + + True + * + True + + + 0 + False + True + + + + + 3 + 4 + 0 + 1 + fill + + + + + 0 + False + True + + + + + + + + GTK_FILE_CHOOSER_ACTION_OPEN + True + False + False + False + Load Patch + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + + + + False + 24 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + True + gtk-open + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 1 + 4 + False + 4 + 12 + + + + True + <b>Polyphony: </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + Use the same polyphony as the current patch + True + Keep current + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + Use the polyphony value stored in the patch file + True + Load from file + True + GTK_RELIEF_NORMAL + True + False + False + True + load_patch_poly_from_current_radio + + + 2 + 3 + 0 + 1 + fill + + + + + + + True + False + 0 + + + + True + True + Specify: + True + GTK_RELIEF_NORMAL + True + False + False + True + load_patch_poly_from_current_radio + + + 0 + False + False + + + + + + True + False + Specify a custom polyphony value for new patch + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 0 + False + True + + + + + 3 + 4 + 0 + 1 + fill + fill + + + + + 0 + False + True + + + + + + + + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + 2 + 2 + False + 0 + 0 + + + + True + False + 0 + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_NONE + + + + True + False + 0 + + + + + + + + + + + 0 + True + True + + + + + + True + True + 0 + + + + Apply changed controls to all voices + True + All Voices + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + False + 5 + + + + True + Apply changed controls to one voice only + True + Specific Voice: + True + GTK_RELIEF_NORMAL + True + False + False + True + control_panel_all_voices_radio + + + 0 + False + False + + + + + + True + False + Voice control changes are applied to + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + False + False + 1 1 100 1 10 10 + + + 0 + True + True + + + + + 0 + False + False + + + + + 5 + False + True + + + + + 0 + 1 + 0 + 1 + + + + + + True + False + 0 + + + + 1 + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + Enable audio processing for this patch + True + Run + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + True + + + + + + True + True + False + True + + + 0 + False + False + + + + + + True + False + 0 + + + + True + Polyphony: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + ? + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 10 + True + False + + + + + + True + True + False + True + + + 0 + False + False + + + + + + True + False + 0 + + + + True + Zoom: + False + True + GTK_JUSTIFY_LEFT + False + False + 0.469999998808 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + False + False + + + + + + 90 + True + True + False + GTK_POS_RIGHT + 1 + GTK_UPDATE_CONTINUOUS + False + 1.10638296604 0.25 2 0.25 0 0 + + + 0 + False + False + + + + + 0 + False + True + + + + + 0 + False + False + + + + + 0 + 1 + 1 + 2 + fill + + + + + + + + 8 + 400 + 180 + Error Messages + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 6 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + Error messages from the engine since the last time "Clear" was pressed + True + False + False + False + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + False + 5 + 5 + 0 + 5 + 5 + 0 + + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_END + 6 + + + + True + False + True + True + gtk-clear + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + + + + + + + + 8 + Configuration + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 6 + + + + True + 2 + 2 + False + 0 + 0 + + + + True + <b>Patch Search Path: </b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + + + + + + + True + <i>Example: /foo/bar:/home/john/patches:/usr/share/om/patches</i> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + 0 + True + False + + + + + + True + GTK_BUTTONBOX_END + 6 + + + + True + Save these settings for future sessions + True + gtk-save + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + Apply these settings to this session only + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + + + + + + + + 8 + 400 + 200 + Patch Description + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 6 + + + + True + False + 5 + + + + True + Author: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + A short description of the patch to be included in the patch file + True + True + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + True + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_END + 5 + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + Apply these changes to be saved the next time the patch is saved + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + False + + + + + + + + 250 + Rename + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 0 + + + + True + False + 0 + + + + True + New name: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + True + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 6 + False + True + + + + + + True + GTK_BUTTONBOX_END + 5 + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-ok + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Rename + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + True + + + + + + + + 6 + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + <b>Node</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 12 + True + False + 6 + + + + True + False + 4 + + + + True + Path: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + False + False + + + + + + True + False + True + Polyphonic + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 6 + True + True + + + + + + 240 + True + <b>Plugin</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 12 + True + 3 + 2 + False + 6 + 10 + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + Type: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + URI: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + Name: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 2 + 3 + fill + + + + + + 0 + True + True + + + + + + + + True + OmGtk + Copyright (C) 2005-2006 Dave Robillard + A client for the Om modular synthesizer + Licensed under the GNU GPL, Version 2. + +See COPYING file included with Om, or http://www.gnu.org/licenses/gpl.txt for more information + False + http://om-synth.nongnu.org + + Author: + Dave Robillard <drobilla@connect.carelton.ca> + +Contributors: + Lars Luthman - DSSI enhancements, bugfixes + Mario Lang - SuperCollider bindings, bugfixes + Leonard Ritter - Python bindings + + Usability / UI Design: + Thorsten Wilms + translator-credits + om-icon.png + + + + 8 + 320 + 340 + Patches + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 3 + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + All patches loaded in the engine + True + True + True + False + True + False + False + False + + + + + + + + 6 + Connecting to Engine + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + om-icon.png + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + True + False + 6 + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + + + + True + True + True + GTK_RELIEF_NORMAL + True + 0 + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-execute + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + _Launch Engine + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + 0 + False + False + GTK_PACK_END + + + + + + 2 + True + False + 0 + + + + True + False + 0 + + + + True + om-icon.png + 0.5 + 0.5 + 6 + 0 + + + 0 + False + False + + + + + + 5 + True + True + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.10000000149 + + PANGO_ELLIPSIZE_NONE + + + 0 + False + False + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + Connecting to engine + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 4 + False + False + + + + + 0 + True + True + + + + + + + diff --git a/src/progs/gtk/om_gtk.gladep b/src/progs/gtk/om_gtk.gladep new file mode 100644 index 00000000..a8bd18bd --- /dev/null +++ b/src/progs/gtk/om_gtk.gladep @@ -0,0 +1,9 @@ + + + + + OmGtk + om_gtk + C++ + FALSE + diff --git a/src/progs/gtk/om_gtk.gladep.bak b/src/progs/gtk/om_gtk.gladep.bak new file mode 100644 index 00000000..a8bd18bd --- /dev/null +++ b/src/progs/gtk/om_gtk.gladep.bak @@ -0,0 +1,9 @@ + + + + + OmGtk + om_gtk + C++ + FALSE + diff --git a/src/progs/gtk/singletons.cpp b/src/progs/gtk/singletons.cpp new file mode 100644 index 00000000..75b441e9 --- /dev/null +++ b/src/progs/gtk/singletons.cpp @@ -0,0 +1,29 @@ +/* This file is part of Om. Copyright (C) 2006 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 "App.h" +#include "Store.h" +#include "Controller.h" +//#include "GtkClientInterface.h" + +namespace OmGtk +{ + App* App::_instance = 0; + Store* Store::_instance = 0; + Controller* Controller::_instance = 0; + //CountedPtr GtkClientInterface::_instance = 0; +} + diff --git a/src/progs/om/Makefile.am b/src/progs/om/Makefile.am index ae0b3e53..2f503130 100644 --- a/src/progs/om/Makefile.am +++ b/src/progs/om/Makefile.am @@ -1,232 +1,15 @@ -SUBDIRS = tests -DIST_SUBDIRS = events - -AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @SLV2_CFLAGS@ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/engine/events -fno-exceptions -fno-rtti +AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @SLV2_CFLAGS@ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/engine -I$(top_srcdir)/src/engine/events -fno-exceptions -fno-rtti MAINTAINERCLEANFILES = Makefile.in -common_SOURCES = \ - util.h \ - tuning.h \ - Node.h \ - NodeBase.h \ - NodeBase.cpp \ - InternalNode.h \ - Patch.h \ - Patch.cpp \ - NodeFactory.h \ - NodeFactory.cpp \ - Om.h \ - Om.cpp \ - OmApp.h \ - OmApp.cpp \ - JackAudioDriver.h \ - JackAudioDriver.cpp \ - OSCReceiver.h \ - OSCReceiver.cpp \ - Responder.h \ - OSCResponder.h \ - OSCResponder.cpp \ - ClientKey.h \ - ClientBroadcaster.h \ - ClientBroadcaster.cpp \ - ObjectSender.h \ - ObjectSender.cpp \ - OSCClient.h \ - OSCClient.cpp \ - Buffer.h \ - Buffer.cpp \ - Port.h \ - Port.cpp \ - PortBase.h \ - PortBase.cpp \ - InputPort.h \ - InputPort.cpp \ - OutputPort.h \ - OutputPort.cpp \ - MidiMessage.h \ - MidiNoteNode.h \ - MidiNoteNode.cpp \ - MidiTriggerNode.h \ - MidiTriggerNode.cpp \ - MidiControlNode.h \ - MidiControlNode.cpp \ - BridgeNode.h \ - BridgeNode.cpp \ - ControlInputNode.h \ - ControlInputNode.cpp \ - ControlOutputNode.h \ - ControlOutputNode.cpp \ - AudioInputNode.h \ - AudioInputNode.cpp \ - AudioOutputNode.h \ - AudioOutputNode.cpp \ - MidiInputNode.h \ - MidiInputNode.cpp \ - MidiOutputNode.h \ - MidiOutputNode.cpp \ - Event.h \ - Event.cpp \ - QueuedEvent.h \ - EventSource.h \ - QueuedEventSource.h \ - QueuedEventSource.cpp \ - QueuedEngineInterface.h \ - QueuedEngineInterface.cpp \ - OmObject.h \ - Maid.h \ - Maid.cpp \ - MaidObject.h \ - Tree.h \ - ClientRecord.h \ - PortInfo.h \ - PluginLibrary.h \ - Plugin.h \ - Array.h \ - List.h \ - PostProcessor.h \ - PostProcessor.cpp \ - Connection.h \ - Connection.cpp \ - ConnectionBase.h \ - ConnectionBase.cpp \ - ObjectStore.h \ - ObjectStore.cpp \ - TransportNode.h \ - TransportNode.cpp \ - Driver.h \ - AudioDriver.h \ - MidiDriver.h \ - midi.h \ - ../common/util/Semaphore.h \ - ../common/util/types.h \ - ../common/util/Path.h \ - ../common/util/Queue.h \ - ../common/interface/ClientInterface.h \ - ../common/interface/EngineInterface.h \ - instantiations.cpp - -# Events -common_SOURCES += \ - events/RegisterClientEvent.h \ - events/RegisterClientEvent.cpp \ - events/UnregisterClientEvent.h \ - events/UnregisterClientEvent.cpp \ - events/PingQueuedEvent.h \ - events/ActivateEvent.h \ - events/ActivateEvent.cpp \ - events/DeactivateEvent.h \ - events/DeactivateEvent.cpp \ - events/SetPortValueEvent.h \ - events/SetPortValueEvent.cpp \ - events/SetPortValueQueuedEvent.h \ - events/SetPortValueQueuedEvent.cpp \ - events/NoteOnEvent.h \ - events/NoteOnEvent.cpp \ - events/NoteOffEvent.h \ - events/NoteOffEvent.cpp \ - events/AllNotesOffEvent.h \ - events/AllNotesOffEvent.cpp \ - events/ConnectionEvent.h \ - events/ConnectionEvent.cpp \ - events/DisconnectionEvent.h \ - events/DisconnectionEvent.cpp \ - events/DisconnectNodeEvent.h \ - events/DisconnectNodeEvent.cpp \ - events/DisconnectPortEvent.h \ - events/DisconnectPortEvent.cpp \ - events/DestroyEvent.h \ - events/DestroyEvent.cpp \ - events/AddNodeEvent.h \ - events/AddNodeEvent.cpp \ - events/SetMetadataEvent.h \ - events/SetMetadataEvent.cpp \ - events/RequestMetadataEvent.h \ - events/RequestMetadataEvent.cpp \ - events/RequestPortValueEvent.h \ - events/RequestPortValueEvent.cpp \ - events/RequestAllObjectsEvent.h \ - events/RequestAllObjectsEvent.cpp \ - events/RequestPluginsEvent.h \ - events/RequestPluginsEvent.cpp \ - events/CreatePatchEvent.h \ - events/CreatePatchEvent.cpp \ - events/LoadPluginsEvent.h \ - events/LoadPluginsEvent.cpp \ - events/EnablePatchEvent.h \ - events/EnablePatchEvent.cpp \ - events/DisablePatchEvent.h \ - events/DisablePatchEvent.cpp \ - events/ClearPatchEvent.h \ - events/ClearPatchEvent.cpp \ - events/RenameEvent.h \ - events/RenameEvent.cpp \ - events/MidiLearnEvent.h \ - events/MidiLearnEvent.cpp - -if WITH_JACK_MIDI -common_SOURCES += \ - JackMidiDriver.h \ - JackMidiDriver.cpp -endif - -if WITH_ALSA_MIDI -common_SOURCES += \ - AlsaMidiDriver.h \ - AlsaMidiDriver.cpp -endif - -if WITH_LADSPA -common_SOURCES += \ - LADSPAPlugin.h \ - LADSPAPlugin.cpp -endif - -if WITH_DSSI -common_SOURCES += \ - DSSIPlugin.h \ - DSSIPlugin.cpp \ - events/DSSIConfigureEvent.cpp \ - events/DSSIConfigureEvent.h \ - events/DSSIControlEvent.cpp \ - events/DSSIControlEvent.h \ - events/DSSIProgramEvent.cpp \ - events/DSSIProgramEvent.h \ - events/DSSIUpdateEvent.cpp \ - events/DSSIUpdateEvent.h -endif - -if WITH_LV2 -common_SOURCES += \ - LV2Plugin.h \ - LV2Plugin.cpp -endif - -if WITH_LASH -common_SOURCES += \ - LashDriver.h \ - LashDriver.cpp \ - LashRestoreDoneEvent.h -endif - - -# -# Non-installed library to link stand-alone and in-process build against -# - -noinst_LTLIBRARIES = libom.la -libom_la_SOURCES = $(common_SOURCES) - - - # # Stand-alone engine # if BUILD_ENGINE bin_PROGRAMS = om -om_DEPENDENCIES = libom.la -om_LDADD = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -lrt libom.la +om_DEPENDENCIES = ../../libs/engine/libom.la +om_LDADD = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -lrt ../../libs/engine/libom.la om_SOURCES = \ main.cpp \ @@ -236,24 +19,25 @@ om_SOURCES = \ endif # BUILD_ENGINE - +## +## Jack internal client +## +#if BUILD_IN_PROCESS_ENGINE # -# Jack internal client # -if BUILD_IN_PROCESS_ENGINE - - -# FIXME: broken - - -# FIXME: Figure out how to get this properly -omdir = $(prefix)/lib/jack +## FIXME: broken +# +# +## FIXME: Figure out how to get this properly +#omdir = $(prefix)/lib/jack +# +#om_la_CFLAGS = -fPIC +#om_LTLIBRARIES = om.la +#om_la_LDFLAGS = -module -avoid-version @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ +#om_la_SOURCES = OmInProcess.cpp +# +#endif # BUILD_IN_PROCESS_ENGINE -om_la_CFLAGS = -fPIC -om_LTLIBRARIES = om.la -om_la_LDFLAGS = -module -avoid-version @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -om_la_SOURCES = OmInProcess.cpp -endif # BUILD_IN_PROCESS_ENGINE diff --git a/src/progs/om/cmdline.c b/src/progs/om/cmdline.c new file mode 100644 index 00000000..6b7ddf6a --- /dev/null +++ b/src/progs/om/cmdline.c @@ -0,0 +1,150 @@ +/* + File autogenerated by gengetopt version 2.10 + generated with the following command: + gengetopt + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + + +#include +#include +#include + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#include "cmdline.h" + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); +} + +void +cmdline_parser_print_help (void) +{ + cmdline_parser_print_version (); + printf("\n" + "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); + printf(" -h --help Print help and exit\n"); + printf(" -V --version Print version and exit\n"); + printf(" -pSTRING --port=STRING OSC port to listen on (default='16180')\n"); + printf(" -i --in-jackd Run engine as in-process JACK client (default=off)\n"); +} + + +static char *gengetopt_strdup (const char *s); + +/* gengetopt_strdup() */ +/* strdup.c replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) +{ + int c; /* Character of the parsed option. */ + int missing_required_options = 0; + + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->port_given = 0 ; + args_info->in_jackd_given = 0 ; +#define clear_args() { \ + args_info->port_arg = gengetopt_strdup("16180") ;\ + args_info->in_jackd_flag = 0;\ +} + + clear_args(); + + optarg = 0; + optind = 1; + opterr = 1; + optopt = '?'; + + while (1) + { + int option_index = 0; + char *stop_char; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "port", 1, NULL, 'p' }, + { "in-jackd", 0, NULL, 'i' }, + { NULL, 0, NULL, 0 } + }; + + stop_char = 0; + c = getopt_long (argc, argv, "hVp:i", long_options, &option_index); + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + clear_args (); + cmdline_parser_print_help (); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + clear_args (); + cmdline_parser_print_version (); + exit (EXIT_SUCCESS); + + case 'p': /* OSC port to listen on. */ + if (args_info->port_given) + { + fprintf (stderr, "%s: `--port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->port_given = 1; + args_info->port_arg = gengetopt_strdup (optarg); + break; + + case 'i': /* Run engine as in-process JACK client. */ + if (args_info->in_jackd_given) + { + fprintf (stderr, "%s: `--in-jackd' (`-i') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->in_jackd_given = 1; + args_info->in_jackd_flag = !(args_info->in_jackd_flag); + break; + + + case 0: /* Long option with no short option */ + + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + exit (EXIT_FAILURE); + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); + abort (); + } /* switch */ + } /* while */ + + + if ( missing_required_options ) + exit (EXIT_FAILURE); + + return 0; +} diff --git a/src/progs/om/cmdline.ggo b/src/progs/om/cmdline.ggo new file mode 100644 index 00000000..8c006ca7 --- /dev/null +++ b/src/progs/om/cmdline.ggo @@ -0,0 +1,7 @@ +# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) + +package "Om - An OSC controlled realtime modular synthesizer" + +option "port" p "OSC port to listen on" string default="16180" no +option "in-jackd" i "Run engine as in-process JACK client" flag off + diff --git a/src/progs/om/cmdline.h b/src/progs/om/cmdline.h new file mode 100644 index 00000000..fe36a969 --- /dev/null +++ b/src/progs/om/cmdline.h @@ -0,0 +1,45 @@ +/* cmdline.h */ + +/* File autogenerated by gengetopt version 2.10 */ + +#ifndef CMDLINE_H +#define CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +#define CMDLINE_PARSER_PACKAGE "Om - An OSC controlled realtime modular synthesizer" +#endif + +#ifndef CMDLINE_PARSER_VERSION +#define CMDLINE_PARSER_VERSION VERSION +#endif + +struct gengetopt_args_info +{ + char * port_arg; /* OSC port to listen on (default='16180'). */ + int in_jackd_flag; /* Run engine as in-process JACK client (default=off). */ + + int help_given ; /* Whether help was given. */ + int version_given ; /* Whether version was given. */ + int port_given ; /* Whether port was given. */ + int in_jackd_given ; /* Whether in-jackd was given. */ + +} ; + +int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); + +void cmdline_parser_print_help(void); +void cmdline_parser_print_version(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/src/progs/om/main.cpp b/src/progs/om/main.cpp new file mode 100644 index 00000000..a69c7e76 --- /dev/null +++ b/src/progs/om/main.cpp @@ -0,0 +1,153 @@ +/* This file is part of Om. Copyright (C) 2006 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 +#include +#include +#include "config.h" +#include "util.h" +#include "cmdline.h" +#include "Om.h" +#include "OmApp.h" +#ifdef HAVE_LASH +#include "LashDriver.h" +#endif +#ifdef BUILD_IN_PROCESS_ENGINE +#include +#include +#endif + +using std::cout; using std::endl; using std::cerr; + + +void +catch_int(int) +{ + signal(SIGINT, catch_int); + signal(SIGTERM, catch_int); + + std::cout << "[Main] Om interrupted." << std::endl; + Om::om->quit(); +} + + +#ifdef BUILD_IN_PROCESS_ENGINE + +jack_client_t* jack_client; +jack_intclient_t jack_intclient; + + +void +unload_in_process_engine(int) +{ + jack_status_t status; + int ret = EXIT_SUCCESS; + + cout << "Unloading..."; + status = jack_internal_client_unload(jack_client, jack_intclient); + if (status & JackFailure) { + cout << "failed" << endl; + ret = EXIT_FAILURE; + } else { + cout << "done" << endl; + } + jack_client_close(jack_client); + exit(ret); +} + + +int +load_in_process_engine(const char* port) +{ + int ret = EXIT_SUCCESS; + + jack_status_t status; + + if ((jack_client = jack_client_open("om_load", JackNoStartServer, + &status)) != NULL) { + jack_intclient = + jack_internal_client_load(jack_client, "Om", + (jack_options_t)(JackLoadName|JackLoadInit), + &status, "om", port); + if (status == 0) { + cout << "Engine loaded" << endl; + signal(SIGINT, unload_in_process_engine); + signal(SIGTERM, unload_in_process_engine); + + while (1) { + sleep(1); + } + } else if (status & JackFailure) { + cerr << "Could not load om.so" << endl; + ret = EXIT_FAILURE; + } + + jack_client_close(jack_client); + } else { + cerr << "jack_client_open failed" << endl; + ret = EXIT_FAILURE; + } +} + +#endif // BUILD_IN_PROCESS_ENGINE + + +int +main(int argc, char** argv) +{ +#ifdef HAVE_LASH + lash_args_t* lash_args = lash_extract_args(&argc, &argv); +#endif + + int ret = EXIT_SUCCESS; + + /* Parse command line options */ + gengetopt_args_info args_info; + if (cmdline_parser (argc, argv, &args_info) != 0) + return EXIT_FAILURE; + + + if (args_info.in_jackd_flag) { +#ifdef BUILD_IN_PROCESS_ENGINE + ret = load_in_process_engine(args_info.port_arg); +#else + cerr << "In-process Jack client support not enabled in this build." << endl; + ret = EXIT_FAILURE; +#endif // JACK_IN_PROCESS_ENGINE + } else { + signal(SIGINT, catch_int); + signal(SIGTERM, catch_int); + + Om::set_denormal_flags(); + + Om::om = new Om::OmApp(args_info.port_arg); + +#ifdef HAVE_LASH + Om::lash_driver = new Om::LashDriver(Om::om, lash_args); +#endif + + Om::om->main(); + +#ifdef HAVE_LASH + delete Om::lash_driver; +#endif + + delete Om::om; + } + + return ret; +} + diff --git a/src/progs/patch_loader/Makefile.am b/src/progs/patch_loader/Makefile.am new file mode 100644 index 00000000..15e0c503 --- /dev/null +++ b/src/progs/patch_loader/Makefile.am @@ -0,0 +1,13 @@ +EXTRA_DIST = README + +om_patch_loader_CXXFLAGS = -I$(top_srcdir)/src/clients -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) +om_patch_loader_LDADD = ../libomclient.a $(LOSC_LIBS) $(LXML2_LIBS) + +bin_PROGRAMS = om_patch_loader + +om_patch_loader_DEPENDENCIES = ../libomclient.a + +om_patch_loader_SOURCES = \ + patch_loader.cpp \ + cmdline.h \ + cmdline.c diff --git a/src/progs/patch_loader/README b/src/progs/patch_loader/README new file mode 100644 index 00000000..9f3b6f4b --- /dev/null +++ b/src/progs/patch_loader/README @@ -0,0 +1,5 @@ +This is a stand-alone patch loader for Om. It has no user interface, it +just launches, loads the patch(es) passed as a parameter, and exits. + +Useful for loading patches from scripts, other apps, etc. or just using +Om patches without loading the GUI. diff --git a/src/progs/patch_loader/cmdline.c b/src/progs/patch_loader/cmdline.c new file mode 100644 index 00000000..0606cb7b --- /dev/null +++ b/src/progs/patch_loader/cmdline.c @@ -0,0 +1,163 @@ +/* + File autogenerated by gengetopt version 2.10 + generated with the following command: + gengetopt -u + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + + +#include +#include +#include + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#include "cmdline.h" + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); +} + +void +cmdline_parser_print_help (void) +{ + cmdline_parser_print_version (); + printf("\n" + "Usage: %s [OPTIONS]... [FILES]...\n", CMDLINE_PARSER_PACKAGE); + printf(" -h --help Print help and exit\n"); + printf(" -V --version Print version and exit\n"); + printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n"); + printf(" -pINT --client-port=INT Client port to listen on\n"); +} + + +static char *gengetopt_strdup (const char *s); + +/* gengetopt_strdup() */ +/* strdup.c replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) +{ + int c; /* Character of the parsed option. */ + int missing_required_options = 0; + + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->engine_url_given = 0 ; + args_info->client_port_given = 0 ; +#define clear_args() { \ + args_info->engine_url_arg = NULL; \ +} + + clear_args(); + + args_info->inputs = NULL; + args_info->inputs_num = 0; + + optarg = 0; + optind = 1; + opterr = 1; + optopt = '?'; + + while (1) + { + int option_index = 0; + char *stop_char; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "engine-url", 1, NULL, 'u' }, + { "client-port", 1, NULL, 'p' }, + { NULL, 0, NULL, 0 } + }; + + stop_char = 0; + c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index); + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + clear_args (); + cmdline_parser_print_help (); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + clear_args (); + cmdline_parser_print_version (); + exit (EXIT_SUCCESS); + + case 'u': /* Om engine URL to connect to. */ + if (args_info->engine_url_given) + { + fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->engine_url_given = 1; + args_info->engine_url_arg = gengetopt_strdup (optarg); + break; + + case 'p': /* Client port to listen on. */ + if (args_info->client_port_given) + { + fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->client_port_given = 1; + args_info->client_port_arg = strtol (optarg,&stop_char,0); + break; + + + case 0: /* Long option with no short option */ + + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + exit (EXIT_FAILURE); + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); + abort (); + } /* switch */ + } /* while */ + + + if ( missing_required_options ) + exit (EXIT_FAILURE); + + if (optind < argc) + { + int i = 0 ; + + args_info->inputs_num = argc - optind ; + args_info->inputs = + (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ; + while (optind < argc) + args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind++]) ; + } + + return 0; +} diff --git a/src/progs/patch_loader/cmdline.ggo b/src/progs/patch_loader/cmdline.ggo new file mode 100644 index 00000000..5acd6737 --- /dev/null +++ b/src/progs/patch_loader/cmdline.ggo @@ -0,0 +1,7 @@ +# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) + +package "om_patch_loader - A command line patch loading client for Om" + +option "engine-url" u "Om engine URL to connect to" string no +option "client-port" p "Client port to listen on" int no + diff --git a/src/progs/patch_loader/cmdline.h b/src/progs/patch_loader/cmdline.h new file mode 100644 index 00000000..b417c664 --- /dev/null +++ b/src/progs/patch_loader/cmdline.h @@ -0,0 +1,47 @@ +/* cmdline.h */ + +/* File autogenerated by gengetopt version 2.10 */ + +#ifndef CMDLINE_H +#define CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +#define CMDLINE_PARSER_PACKAGE "om_patch_loader - A command line patch loading client for the Om realtime modular synthesizer" +#endif + +#ifndef CMDLINE_PARSER_VERSION +#define CMDLINE_PARSER_VERSION VERSION +#endif + +struct gengetopt_args_info +{ + char * engine_url_arg; /* Om engine URL to connect to. */ + int client_port_arg; /* Client port to listen on. */ + + int help_given ; /* Whether help was given. */ + int version_given ; /* Whether version was given. */ + int engine_url_given ; /* Whether engine-url was given. */ + int client_port_given ; /* Whether client-port was given. */ + + char **inputs ; /* unamed options */ + unsigned inputs_num ; /* unamed options number */ +} ; + +int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); + +void cmdline_parser_print_help(void); +void cmdline_parser_print_version(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/src/progs/patch_loader/new_patch_loader.cpp b/src/progs/patch_loader/new_patch_loader.cpp new file mode 100644 index 00000000..8884e85b --- /dev/null +++ b/src/progs/patch_loader/new_patch_loader.cpp @@ -0,0 +1,76 @@ +/* This file is part of Om. 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 +#include +#include "cmdline.h" // generated by gengetopt +#include "util/Path.h" +#include "OSCEngineInterface.h" +#include "PatchLibrarian.h" + +using std::cout; using std::cerr; using std::endl; +using Om::Path; + +using namespace LibOmClient; + + +int +main(int argc, char** argv) +{ + const char* engine_url = NULL; + int client_port = 0; + + /* Parse command line options */ + gengetopt_args_info args_info; + if (cmdline_parser (argc, argv, &args_info) != 0) + return 1; + + if (args_info.engine_url_given) { + engine_url = args_info.engine_url_arg; + } else { + cout << "[Main] No engine URL specified. Attempting to use osc.udp://localhost:16180" << endl; + engine_url = "osc.udp://localhost:16180"; + } + + if (args_info.client_port_given) + client_port = args_info.client_port_arg; + else + client_port = 0; // will choose a free port automatically + + OSCEngineInterface engine(engine_url); + + /* Connect to engine */ + if (!engine.attach()) { + cerr << "Unable to connect to engine" << endl; + return 1; + } + + engine.activate(); + engine.register_client(); + + /*int id = engine.get_next_request_id(); + engine.set_wait_response_id(id); + engine.load_plugins(id); + engine.wait_for_response(); + */ + engine.load_plugins(); + + // Load patches + for (uint i=0; i < args_info.inputs_num; ++i) + PatchLibrarian::load_patch(&engine, args_info.inputs[i]); + + return 0; +} diff --git a/src/progs/patch_loader/patch_loader.cpp b/src/progs/patch_loader/patch_loader.cpp new file mode 100644 index 00000000..e8579ed7 --- /dev/null +++ b/src/progs/patch_loader/patch_loader.cpp @@ -0,0 +1,82 @@ +/* This file is part of Om. 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 "OSCModelEngineInterface.h" +#include "PatchLibrarian.h" +#include "PatchModel.h" +#include "util/Path.h" +#include +#include +#include "cmdline.h" // generated by gengetopt + +using std::cout; using std::endl; +using Om::Path; + +using namespace LibOmClient; + +int main(int argc, char** argv) +{ + const char* engine_url = NULL; + int client_port = 0; + + /* **** Parse command line options **** */ + + gengetopt_args_info args_info; + if (cmdline_parser (argc, argv, &args_info) != 0) + return 1; + + if (args_info.engine_url_given) { + engine_url = args_info.engine_url_arg; + } else { + cout << "[Main] No engine URL specified. Attempting to use osc.udp://localhost:16180" << endl; + engine_url = "osc.udp://localhost:16180"; + } + + if (args_info.client_port_given) + client_port = args_info.client_port_arg; + + + /* **** Mr. Spock.. Engage **** */ + + + OSCModelEngineInterface osc_controller(engine_url); + PatchLibrarian librarian(&osc_controller); + + /* Connect to engine */ + osc_controller.attach(client_port); + osc_controller.activate(); + //osc_controller.register_client(NULL); // FIXME + + //int id = osc_controller.get_next_request_id(); + //osc_controller.set_wait_response_id(id); + //osc_controller.load_plugins(id); + //osc_controller.wait_for_response(); + /* FIXME: Make this work like this: + * osc_controller.load_plugins(); + * osc_controller.wait_for_response(); + */ + + // Load patches + for (uint i=0; i < args_info.inputs_num; ++i) { + PatchModel* pm = new PatchModel("", 0); + pm->filename(args_info.inputs[i]); + librarian.load_patch(pm, true); + delete pm; + } + + return 0; +} diff --git a/src/progs/python/Makefile.am b/src/progs/python/Makefile.am new file mode 100644 index 00000000..017b1f4b --- /dev/null +++ b/src/progs/python/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = scripts + +EXTRA_DIST = omecho.py omsynth.py OSC.py + diff --git a/src/progs/python/OSC.py b/src/progs/python/OSC.py new file mode 100755 index 00000000..74eb5880 --- /dev/null +++ b/src/progs/python/OSC.py @@ -0,0 +1,374 @@ +#!/usr/bin/python +# +# Open SoundControl for Python +# Copyright (C) 2002 Daniel Holth, Clinton McChesney +# Modified by Leonard Ritter +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# For questions regarding this module contact +# Daniel Holth or visit +# http://www.stetson.edu/~ProctoLogic/ + +import socket +import struct +import math +import sys +import string + + +def hexDump(bytes): + """Useful utility; prints the string in hexadecimal""" + for i in range(len(bytes)): + sys.stdout.write("%2x " % (ord(bytes[i]))) + if (i+1) % 8 == 0: + print repr(bytes[i-7:i+1]) + + if(len(bytes) % 8 != 0): + print string.rjust("", 11), repr(bytes[i-7:i+1]) + + +class OSCMessage: + """Builds typetagged OSC messages.""" + def __init__(self): + self.address = "" + self.typetags = "," + self.message = "" + + def setAddress(self, address): + self.address = address + + def setMessage(self, message): + self.message = message + + def setTypetags(self, typetags): + self.typetags = typetags + + def clear(self): + self.address = "" + self.clearData() + + def clearData(self): + self.typetags = "," + self.message = "" + + def append(self, argument, typehint = None): + """Appends data to the message, + updating the typetags based on + the argument's type. + If the argument is a blob (counted string) + pass in 'b' as typehint.""" + + if typehint == 'b': + binary = OSCBlob(argument) + else: + binary = OSCArgument(argument) + + self.typetags = self.typetags + binary[0] + self.rawAppend(binary[1]) + + def rawAppend(self, data): + """Appends raw data to the message. Use append().""" + self.message = self.message + data + + def getBinary(self): + """Returns the binary message (so far) with typetags.""" + address = OSCArgument(self.address)[1] + typetags = OSCArgument(self.typetags)[1] + return address + typetags + self.message + + def __repr__(self): + return self.getBinary() + +def readString(data): + length = string.find(data,"\0") + nextData = int(math.ceil((length+1) / 4.0) * 4) + return (data[0:length], data[nextData:]) + + +def readBlob(data): + length = struct.unpack(">i", data[0:4])[0] + nextData = int(math.ceil((length) / 4.0) * 4) + 4 + return (data[4:length+4], data[nextData:]) + + +def readInt(data): + if(len(data)<4): + print "Error: too few bytes for int", data, len(data) + rest = data + integer = 0 + else: + integer = struct.unpack(">i", data[0:4])[0] + rest = data[4:] + + return (integer, rest) + + + +def readLong(data): + """Tries to interpret the next 8 bytes of the data + as a 64-bit signed integer.""" + high, low = struct.unpack(">ll", data[0:8]) + big = (long(high) << 32) + low + rest = data[8:] + return (big, rest) + + + +def readFloat(data): + if(len(data)<4): + print "Error: too few bytes for float", data, len(data) + rest = data + float = 0 + else: + float = struct.unpack(">f", data[0:4])[0] + rest = data[4:] + + return (float, rest) + + +def OSCBlob(next): + """Convert a string into an OSC Blob, + returning a (typetag, data) tuple.""" + + if type(next) == type(""): + length = len(next) + padded = math.ceil((len(next)) / 4.0) * 4 + binary = struct.pack(">i%ds" % (padded), length, next) + tag = 'b' + else: + tag = '' + binary = '' + + return (tag, binary) + + +def OSCArgument(next): + """Convert some Python types to their + OSC binary representations, returning a + (typetag, data) tuple.""" + + if type(next) == type(""): + OSCstringLength = math.ceil((len(next)+1) / 4.0) * 4 + binary = struct.pack(">%ds" % (OSCstringLength), next) + tag = "s" + elif type(next) == type(42.5): + binary = struct.pack(">f", next) + tag = "f" + elif type(next) == type(13): + binary = struct.pack(">i", next) + tag = "i" + else: + binary = "" + tag = "" + + return (tag, binary) + + +def parseArgs(args): + """Given a list of strings, produces a list + where those strings have been parsed (where + possible) as floats or integers.""" + parsed = [] + for arg in args: + print arg + arg = arg.strip() + interpretation = None + try: + interpretation = float(arg) + if string.find(arg, ".") == -1: + interpretation = int(interpretation) + except: + # Oh - it was a string. + interpretation = arg + pass + parsed.append(interpretation) + return parsed + + + +def decodeOSC(data): + """Converts a typetagged OSC message to a Python list.""" + table = {"i":readInt, "f":readFloat, "s":readString, "b":readBlob} + decoded = [] + address, rest = readString(data) + typetags = "" + + if address == "#bundle": + time, rest = readLong(rest) + decoded.append(address) + decoded.append(time) + while len(rest)>0: + length, rest = readInt(rest) + decoded.append(decodeOSC(rest[:length])) + rest = rest[length:] + + elif len(rest)>0: + typetags, rest = readString(rest) + decoded.append(address) + decoded.append(typetags) + if(typetags[0] == ","): + for tag in typetags[1:]: + value, rest = table[tag](rest) + decoded.append(value) + else: + print "Oops, typetag lacks the magic ," + + # return only the data + return address,decoded[2:] + + +class CallbackManager: + """This utility class maps OSC addresses to callables. + + The CallbackManager calls its callbacks with a list + of decoded OSC arguments, including the address and + the typetags as the first two arguments.""" + + def __init__(self): + self.callbacks = {} + self.addCallback(self.unbundler, "#bundle") + + def handle(self, data, source = None): + """Given OSC data, tries to call the callback with the + right address.""" + decoded = decodeOSC(data) + self.dispatch(decoded) + + def dispatch(self, message): + """Sends decoded OSC data to an appropriate calback""" + try: + address = message[0] + self.callbacks[address](message) + except KeyError, e: + # address not found + print "no handler for '%s'" % address + pass + except None, e: + print "Exception in", address, "callback :", e + + return + + def addCallback(self, callback, name): + """Adds a callback to our set of callbacks, + or removes the callback with name if callback + is None.""" + if callback == None: + del self.callbacks[name] + else: + self.callbacks[name] = callback + + def unbundler(self, messages): + """Dispatch the messages in a decoded bundle.""" + # first two elements are #bundle and the time tag, rest are messages. + for message in messages[2:]: + self.dispatch(message) + + +if __name__ == "__main__": + hexDump("Welcome to the OSC testing program.") + print + message = OSCMessage() + message.setAddress("/foo/play") + message.append(44) + message.append(11) + message.append(4.5) + message.append("the white cliffs of dover") + hexDump(message.getBinary()) + + print "Making and unmaking a message.." + + strings = OSCMessage() + strings.append("Mary had a little lamb") + strings.append("its fleece was white as snow") + strings.append("and everywhere that Mary went,") + strings.append("the lamb was sure to go.") + strings.append(14.5) + strings.append(14.5) + strings.append(-400) + + raw = strings.getBinary() + + hexDump(raw) + + print "Retrieving arguments..." + data = raw + for i in range(6): + text, data = readString(data) + print text + + number, data = readFloat(data) + print number + + number, data = readFloat(data) + print number + + number, data = readInt(data) + print number + + hexDump(raw) + print decodeOSC(raw) + print decodeOSC(message.getBinary()) + + print "Testing Blob types." + + blob = OSCMessage() + blob.append("","b") + blob.append("b","b") + blob.append("bl","b") + blob.append("blo","b") + blob.append("blob","b") + blob.append("blobs","b") + blob.append(42) + + hexDump(blob.getBinary()) + + print decodeOSC(blob.getBinary()) + + def printingCallback(stuff): + sys.stdout.write("Got: ") + for i in stuff: + sys.stdout.write(str(i) + " ") + sys.stdout.write("\n") + + print "Testing the callback manager." + + c = CallbackManager() + c.add(printingCallback, "/print") + + c.handle(message.getBinary()) + message.setAddress("/print") + c.handle(message.getBinary()) + + print1 = OSCMessage() + print1.setAddress("/print") + print1.append("Hey man, that's cool.") + print1.append(42) + print1.append(3.1415926) + + c.handle(print1.getBinary()) + + bundle = OSCMessage() + bundle.setAddress("") + bundle.append("#bundle") + bundle.append(0) + bundle.append(0) + bundle.append(print1.getBinary(), 'b') + bundle.append(print1.getBinary(), 'b') + + bundlebinary = bundle.message + + print "sending a bundle to the callback manager" + c.handle(bundlebinary) diff --git a/src/progs/python/omecho.py b/src/progs/python/omecho.py new file mode 100644 index 00000000..c0d2d3b1 --- /dev/null +++ b/src/progs/python/omecho.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# +# Python bindings for Om +# Copyright (C) 2005 Leonard Ritter +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import omsynth +import os,time,sys + +def main(om): + om.setEnvironment(omsynth.Environment()) + om.engine.activate() + om.engine.register_client(om.getAddressAsString()) + om.request.all_objects(om.getAddressAsString()) + + om.request.all_objects() + time.sleep(3) + om.getEnvironment().printPatch() + om.getEnvironment().printConnections() + print "omecho will now monitor and mirror changes in the structure" + print "hit return to exit when youre done" + sys.stdin.readline() + om.engine.unregister_client(om.getAddressAsString()) + os._exit(0) + +if __name__ == "__main__": + omsynth.startClient(main) diff --git a/src/progs/python/omsynth.py b/src/progs/python/omsynth.py new file mode 100644 index 00000000..d7cfa5ab --- /dev/null +++ b/src/progs/python/omsynth.py @@ -0,0 +1,635 @@ +#!/usr/bin/python +# +# Python bindings for Om +# Copyright (C) 2005 Leonard Ritter +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os,sys,thread,time + +from OSC import OSCMessage, decodeOSC + +from twisted.internet.protocol import DatagramProtocol +from twisted.internet import reactor + +OM_CALL_TIMEOUT = 5 +OM_CALL_POLLTIME = 0.1 + +class TreeElement: + def __init__(self,environment,parent,name): + self.environment = environment + self.parent = parent + self.name = name + self.metadata = {} + + def __del__(self): + print "'%s': gone" % self.name + + def removeChild(self, child): + pass + + def remove(self): + self.parent.removeChild(self.name) + self.parent = None + del self + + def getParent(self): + return self.parent + + def getName(self): + return self.name + + def getPath(self): + if self.parent: + return self.parent.getPath() + "/" + self.name + else: + return self.name + + def getDepth(self): + if self.parent: + return self.parent.getDepth() + 1 + else: + return 0 + + def setMetaData(self,key,value): + if (not self.metadata.has_key(value)) or (self.metadata[key] != value): + print "||| '%s': '%s' = '%s'" % (self.getPath(), key, value) + self.metadata[key] = value + +class Port(TreeElement): + def __init__(self,environment,parent,name): + TreeElement.__init__(self,environment,parent,name) + self.porttype = "" + self.direction = "" + self.hint = "" + self.defaultvalue = 0.0 + self.minvalue = 0.0 + self.maxvalue = 0.0 + self.value = 0.0 + self.connections = {} + print "*** '%s': new port" % self.getPath() + + def remove(self): + for connection in self.getConnections(): + connection.remove() + TreeElement.remove(self) + + def getConnections(self): + return self.connections + + def addConnection(self,target,connection): + self.connections[target] = connection + + def removeConnection(self,target): + del self.connections[target] + + def setPortType(self,porttype): + if self.porttype != porttype: + print "*** '%s': changing porttype from '%s' to '%s'" % (self.getPath(), self.porttype, porttype) + self.porttype = porttype + + def setDirection(self,direction): + if self.direction != direction: + print "*** '%s': changing direction from '%s' to '%s'" % (self.getPath(), self.direction, direction) + self.direction = direction + + def setHint(self,hint): + if self.hint != hint: + print "*** '%s': changing hint from '%s' to '%s'" % (self.getPath(), self.hint, hint) + self.hint = hint + + def setDefaultValue(self,defaultvalue): + if self.defaultvalue != defaultvalue: + print "*** '%s': changing defaultvalue from '%.3f' to '%.3f'" % (self.getPath(), self.defaultvalue, defaultvalue) + self.defaultvalue = defaultvalue + + def setMinValue(self,minvalue): + if self.minvalue != minvalue: + print "*** '%s': changing minvalue from '%.3f' to '%.3f'" % (self.getPath(), self.minvalue, minvalue) + self.minvalue = minvalue + + def setMaxValue(self,maxvalue): + if self.maxvalue != maxvalue: + print "*** '%s': changing maxvalue from '%.3f' to '%.3f'" % (self.getPath(), self.maxvalue, maxvalue) + self.maxvalue = maxvalue + + def setValue(self,value): + if self.value != value: + print "*** '%s': changing value from '%.3f' to '%.3f'" % (self.getPath(), self.value, value) + self.value = value + +class Node(TreeElement): + def __init__(self,environment,parent,name): + TreeElement.__init__(self,environment,parent,name) + self.ports = {} + self.polyphonic = 0 + self.plugintype = "" + self.libname = "" + self.pluginlabel = "" + print "+++ '%s': new node" % self.getPath() + + def remove(self): + for port in self.getPorts(): + port.remove() + TreeElement.remove(self) + + def removeChild(self, child): + del self.ports[child] + + def getPorts(self): + return self.ports.values() + + def setPluginLabel(self,pluginlabel): + if pluginlabel != self.pluginlabel: + print "+++ '%s': changing pluginlabel from '%s' to '%s'" % (self.getPath(), self.pluginlabel, pluginlabel) + self.pluginlabel = pluginlabel + + def setLibName(self,libname): + if libname != self.libname: + print "+++ '%s': changing libname from '%s' to '%s'" % (self.getPath(), self.libname, libname) + self.libname = libname + + def setPluginType(self,plugintype): + if plugintype != self.plugintype: + print "+++ '%s': changing plugintype from '%s' to '%s'" % (self.getPath(), self.plugintype, plugintype) + self.plugintype = plugintype + + def setPolyphonic(self,polyphonic): + if polyphonic != self.polyphonic: + print "+++ '%s': changing polyphony from %i to %i" % (self.getPath(), self.polyphonic, polyphonic) + self.polyphonic = polyphonic + + def hasPort(self,name): + return self.ports.has_key(name) + + def getPort(self,name,mustexist=False): + if not self.hasPort(name): + if mustexist: + return None + self.ports[name] = self.environment.getPortClass()(self.environment,self,name) + return self.ports[name] + +class Patch(Node): + def __init__(self,environment,parent,name): + Node.__init__(self,environment,parent,name) + self.nodes = {} + self.patches = {} + self.poly = 0 + self.enabled = False + print "### '%s': new patch" % self.getPath() + + def remove(self): + for patch in self.getPatches(): + patch.remove() + for node in self.getNodes(): + node.remove() + Node.remove(self) + + def removeChild(self, child): + if self.hasNode(child): + del self.nodes[child] + elif self.hasPatch(child): + del self.patches[child] + else: + Node.removeChild(self,child) + + def getPatches(self): + return self.patches.values() + + def getNodes(self): + return self.nodes.values() + + def getEnabled(self): + return self.enabled + + def setEnabled(self,enabled): + if enabled != self.enabled: + print "### '%s': changing enabled from %s to %s" % (self.getPath(), str(self.enabled), str(enabled)) + enabled = self.enabled + + def getPoly(self): + return self.poly + + def setPoly(self,poly): + if poly != self.poly: + print "### '%s': changing polyphony from %i to %i" % (self.getPath(), self.poly, poly) + self.poly = poly + + def hasNode(self,name): + return self.nodes.has_key(name) + + def getNode(self,name,mustexist=False): + if not self.hasNode(name): + if mustexist: + return None + self.nodes[name] = self.environment.getNodeClass()(self.environment,self,name) + return self.nodes[name] + + def hasPatch(self,name): + return self.patches.has_key(name) + + def getPatch(self,name,mustexist=False): + if not self.hasPatch(name): + if mustexist: + return None + self.patches[name] = self.environment.getPatchClass()(self.environment,self,name) + return self.patches[name] + +class Connection: + def __init__(self,environment,srcport,dstport): + self.environment = environment + self.srcport = srcport + self.dstport = dstport + self.srcport.addConnection(self.dstport,self) + self.dstport.addConnection(self.srcport,self) + print ">>> '%s'->'%s': new connection" % (self.srcport.getPath(),self.dstport.getPath()) + + def __del__(self): + print "connection gone" + + def remove(self): + self.srcport.removeConnection(self.dstport) + self.dstport.removeConnection(self.srcport) + del self + + def getSrcPort(self): + return self.srcport + + def getDstPort(self): + return self.dstport + + def getPortPair(self): + return self.srcport, self.dstport + +class Environment: + def __init__(self): + self.omPatch = self.getPatchClass()(self,None,"") + self.enabled = False + self.connections = {} + + def getConnectionClass(self): + return Connection + + def getPatchClass(self): + return Patch + + def getNodeClass(self): + return Node + + def getPortClass(self): + return Port + + def getConnection(self,srcportpath,dstportpath,mustexist=False): + srcport = self.getPort(srcportpath,True) + if not srcport: + return None + dstport = self.getPort(dstportpath,True) + if not dstport: + return None + if not self.connections.has_key((srcport,dstport)): + if mustexist: + return None + self.connections[(srcport,dstport)] = self.getConnectionClass()(self,srcport,dstport) + return self.connections[(srcport,dstport)] + + def getConnections(self): + return self.connections.values() + + def getPatch(self,path,mustexist=False): + elements = path.split("/") + currentPatch = None + for element in elements: + if element == "": + currentPatch = self.omPatch + else: + currentPatch = currentPatch.getPatch(element,mustexist) + if not currentPatch: + break + return currentPatch + + def getNode(self,path,mustexist=False): + elements = path.split("/") + basepath = "/".join(elements[:-1]) + nodename = elements[-1] + patch = self.getPatch(basepath,True) + if patch: + return patch.getNode(nodename,mustexist) + return None + + def getPort(self,path,mustexist=False): + elements = path.split("/") + basepath = "/".join(elements[:-1]) + portname = elements[-1] + node = self.getNode(basepath,True) + if node: + return node.getPort(portname,mustexist) + patch = self.getPatch(basepath,True) + if patch: + return patch.getPort(portname,mustexist) + return None + + def getObject(self,path): + patch = self.getPatch(path,True) + if patch: + return patch + node = self.getNode(path,True) + if node: + return node + return self.getPort(path,True) + + def printPatch(self,patch=None): + if not patch: + patch = self.omPatch + print patch.getDepth()*' ' + "### " + patch.getPath() + for node in patch.getNodes(): + print node.getDepth()*' ' + "+++ " + node.getPath() + for port in node.getPorts(): + print port.getDepth()*' ' + "*** " + port.getPath() + for port in patch.getPorts(): + print port.getDepth()*' ' + "*** " + port.getPath() + for subpatch in patch.getPatches(): + self.printPatch(subpatch) + + def printConnections(self): + for connection in self.getConnections(): + print ">>> %s -> %s" % (connection.getSrcPort().getPath(), connection.getDstPort().getPath()) + + #~ /om/engine_enabled - Notification engine's DSP has been enabled. + def __om__engine_enabled(self): + self.enabled = True + + #~ /om/engine_disabled - Notification engine's DSP has been disabled. + def __om__engine_disabled(self): + self.enabled = False + + #~ /om/new_node - Notification of a new node's creation. + #~ * path (string) - Path of the new node + #~ * polyphonic (integer-boolean) - Node is polyphonic (1 for yes, 0 for no) + #~ * type (string) - Type of plugin (LADSPA, DSSI, Internal, Patch) + #~ * lib-name (string) - Name of library if a plugin (ie cmt.so) + #~ * plug-label (string) - Label of plugin in library (ie adsr_env) + + #~ * New nodes are sent as a blob. The first message in the blob will be this one (/om/new_node), followed by a series of /om/new_port commands, followed by /om/new_node_end. + def __om__new_node(self,path,polyphonic,plugintype,libname,pluginlabel): + node = self.getNode(path) + node.setPolyphonic(polyphonic) + node.setPluginType(plugintype) + node.setLibName(libname) + node.setPluginLabel(pluginlabel) + + def __om__new_node_end(self): + pass + + #~ /om/node_removal - Notification of a node's destruction. + #~ * path (string) - Path of node (which no longer exists) + def __om__node_removal(self,path): + node = self.getNode(path) + node.remove() + + #~ /om/new_port - Notification of a node's destruction. + + #~ * path (string) - Path of new port + #~ * type (string) - Type of port (CONTROL or AUDIO) + #~ * direction (string) - Direction of data flow (INPUT or OUTPUT) + #~ * hint (string) - Hint (INTEGER, LOGARITHMIC, TOGGLE, or NONE) + #~ * default-value (float) - Default (initial) value + #~ * min-value (float) - Suggested minimum value + #~ * min-value (float) - Suggested maximum value + + #~ * Note that in the event of loading a patch, this message could be followed immediately by a control change, meaning the default-value is not actually the current value of the port (ahem, Lachlan). + #~ * The minimum and maximum values are suggestions only, they are not enforced in any way, and going outside them is perfectly fine. Also note that the port ranges in om_gtk are not these ones! Those ranges are set as metadata. + def __om__new_port(self,path,porttype,direction,hint,defaultvalue,minvalue,maxvalue): + port = self.getPort(path) + port.setPortType(porttype) + port.setDirection(direction) + port.setHint(hint) + port.setDefaultValue(defaultvalue) + port.setMinValue(minvalue) + port.setMaxValue(maxvalue) + + #~ /om/port_removal - Notification of a port's destruction. + #~ * path (string) - Path of port (which no longer exists) + def __om__port_removal(self,path): + port = self.getPort(path) + port.remove() + + #~ /om/patch_destruction - Notification of a patch's destruction. + #~ * path (string) - Path of patch (which no longer exists) + def __om__patch_destruction(self,path): + patch = self.getPatch(path) + patch.remove() + + #~ /om/patch_enabled - Notification a patch's DSP processing has been enabled. + #~ * path (string) - Path of enabled patch + def __om__patch_enabled(self,path): + patch = self.getPatch(path) + patch.setEnabled(True) + + #~ /om/patch_disabled - Notification a patch's DSP processing has been disabled. + #~ * path (string) - Path of disabled patch + def __om__patch_disabled(self,path): + patch = self.getPatch(path) + patch.setEnabled(False) + + #~ /om/new_connection - Notification a new connection has been made. + #~ * src-path (string) - Path of the source port + #~ * dst-path (string) - Path of the destination port + def __om__new_connection(self,srcpath,dstpath): + self.getConnection(srcpath,dstpath) + + #~ /om/disconnection - Notification a connection has been unmade. + #~ * src-path (string) - Path of the source port + #~ * dst-path (string) - Path of the destination port + def __om__disconnection(self,srcpath,dstpath): + connection = self.getConnection(srcpath,dstpath) + portpair = connection.getPortPair() + connection.remove() + del self.connections[portpair] + + #~ /om/metadata/update - Notification of a piece of metadata. + #~ * path (string) - Path of the object associated with metadata (can be a node, patch, or port) + #~ * key (string) + #~ * value (string) + def __om__metadata__update(self,path,key,value): + object = self.getObject(path) + object.setMetaData(key,value) + + #~ /om/control_change - Notification the value of a port has changed + #~ * path (string) - Path of port + #~ * value (float) - New value of port + #~ * This will only send updates for values set by clients of course - not values changing because of connections to other ports! + def __om__control_change(self,path,value): + port = self.getPort(path) + port.setValue(value) + + #~ /om/new_patch - Notification of a new patch + #~ * path (string) - Path of new patch + #~ * poly (int) - Polyphony of new patch (not a boolean like new_node) + def __om__new_patch(self,path,poly): + patch = self.getPatch(path) + patch.setPoly(poly) + +class SocketError: + pass + +class Call: + pass + +class ClientProxy: + def __init__(self, om, name, is_async = False): + self.name = name + self.om = om + self.is_async = is_async + + def __call__(self, *args): + if (self.is_async): + self.om.sendMsg(self.name, *args) + return True + + result = self.om.sendMsgBlocking(self.name, *args) + if not result: + return None + if result[0] == "/om/response/ok": + return True + print "ERROR: %s" % result[1][1] + return False + + def __getattr__(self, name): + if (name[:2] == "__") and (name[-2:] == "__"): # special function + raise AttributeError, name + if name in self.__dict__: + raise AttributeError, name + if name == 'async': + return ClientProxy(self.om, self.name, True) + else: + return ClientProxy(self.om, self.name + '/' + name) + +class Client(DatagramProtocol, ClientProxy): + def __init__(self): + ClientProxy.__init__(self, self, "/om") + + def startProtocol(self): + self.transport.connect("127.0.0.1", 16180) + host = self.transport.getHost() + self.host = host.host + self.port = host.port + self.environment = None + self.handlers = {} + self.calls = {} + #print "opened port at %s" % (str((self.host,self.port))) + self.nextPacketNumber = 1 + + def setEnvironment(self, environment): + self.handlers = {} + self.environment = environment + for name in dir(self.environment): + element = getattr(self.environment,name) + if (type(element).__name__ == 'instancemethod') and (element.__name__[:6] == "__om__"): + handlername = element.__name__.replace("__","/") + print "registering handler for '%s'" % handlername + self.handlers[handlername] = element + + def getEnvironment(self): + return self.environment + + def connectionRefused(self): + print "Noone listening, aborting." + os._exit(-1) + + def messageReceived(self, (msg, args)): + if msg == "/om/error": + print "ERROR: %r" % args + return + if msg == "/om/response/ok": + omcall = self.calls[args[0]] + omcall.result = (msg,args) + omcall.done = True + return + if msg == "/om/response/error": + omcall = self.calls[args[0]] + omcall.result = (msg,args) + omcall.done = True + return + if msg == "#bundle": + for arg in args: + self.messageReceived(arg) + return + if self.handlers.has_key(msg): + try: + self.handlers[msg](*args) + except: + a,b,c = sys.exc_info() + sys.excepthook(a,b,c) + print "with '%s'" % repr((msg,args)) + return + print "no handler for '%s'" % repr((msg,args)) + + def datagramReceived(self, data, (host, port)): + self.messageReceived(decodeOSC(data)) + + def getPacketNumber(self): + packetNumber = self.nextPacketNumber + self.nextPacketNumber = (self.nextPacketNumber + 1) + return packetNumber + + def sendMsg(self,msg,*args): + packetNumber = self.getPacketNumber() + print "Sending %r (#%i)..." % (msg,packetNumber) + omcall = Call() + omcall.result = None + omcall.done = False + self.calls[packetNumber] = omcall + message = OSCMessage() + message.setAddress(msg) + message.append(packetNumber) + for arg in args: + message.append(arg) + self.transport.write(message.getBinary()) + time.sleep(0.01) + return True + + def sendMsgBlocking(self,msg,*args): + packetNumber = self.getPacketNumber() + print "Sending %r (#%i)..." % (msg,packetNumber) + omcall = Call() + omcall.result = None + omcall.done = False + self.calls[packetNumber] = omcall + message = OSCMessage() + message.setAddress(msg) + message.append(packetNumber) + for arg in args: + message.append(arg) + self.transport.write(message.getBinary()) + now = time.time() + while not omcall.done: + time.sleep(OM_CALL_POLLTIME) + distance = time.time() - now + if distance > OM_CALL_TIMEOUT: + print "timeout" + break + del self.calls[packetNumber] + return omcall.result + + def getAddressAsString(self): + return "osc.udp://%s:%d" % (self.host, self.port) + + + +def startClient(func): + om = Client() + reactor.listenUDP(0, om) + thread.start_new_thread(func,(om,)) + reactor.run() diff --git a/src/progs/python/scripts/Makefile.am b/src/progs/python/scripts/Makefile.am new file mode 100644 index 00000000..3e070601 --- /dev/null +++ b/src/progs/python/scripts/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = sillysinepatch.py + diff --git a/src/progs/python/scripts/flatten.py b/src/progs/python/scripts/flatten.py new file mode 100755 index 00000000..eaf8084d --- /dev/null +++ b/src/progs/python/scripts/flatten.py @@ -0,0 +1,232 @@ +#!/usr/bin/python + +############################################################################### +# +# flatten.py - a python script that merges all subpatches in an Om patch +# into the parent patch +# +# Copyright (C) 2005 Lars Luthman +# +# 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 +# +############################################################################### + +import omsynth +import os,time,sys + + +def getPatchBounds(patch): + """Returns the smallest rectangle that contains all modules in the patch.""" + min_x = None + min_y = None + max_x = None + max_y = None + for node in patch.getNodes(): + x = node.metadata['module-x'] + y = node.metadata['module-y'] + if (x != None): + if (min_x == None or float(x) < min_x): + min_x = float(x) + if (max_x == None or float(x) > max_x): + max_x = float(x) + if (y != None): + if (min_y == None or float(y) < min_y): + min_y = float(y) + if (max_y == None or float(y) > max_y): + max_y = float(y) + if min_x == None: + min_x = 0 + max_x = 0 + if min_y == None: + min_y = 0 + max_y = 0 + + return (min_x, min_y, max_x, max_y) + + +def cloneNode(om, node, patch): + """Copy a node into a patch, return the new node's name.""" + + # create a node with a free name in the parent + names = [] + for node2 in patch.getNodes(): + names.append(node2.getName()) + for patch2 in patch.getPatches(): + names.append(patch2.getName()) + names.sort() + name = node.getName() + for name2 in names: + if name2 == name: + name = name + '_' + om.synth.create_node.async(patch.getPath() + '/' + name, + node.plugintype, node.libname, + node.pluginlabel, node.polyphonic) + + # copy port values + for port in node.getPorts(): + path = '%s/%s/%s' % (patch.getPath(), name, port.getName()) + om.synth.set_port_value_slow.async(path, port.value) + om.metadata.set.async(path, 'user-min', '%f' % port.minvalue) + om.metadata.set.async(path, 'user-max', '%f' % port.maxvalue) + return name + + +def flatten(om, patch): + """Merge all subpatches into the parent patch.""" + + # something is wrong, we don't have a patch + if patch == None: + return + + # iterate over all subpatches + for subpatch in patch.getPatches(): + flatten(om, subpatch) + lookup = {} + + # copy all nodes from the subpatch to the parent patch + for node in subpatch.getNodes(): + lookup[node.getName()] = cloneNode(om, node, patch) + + # copy all connections + for node in subpatch.getNodes(): + for port in node.getPorts(): + if port.direction == 'OUTPUT': + for target in port.getConnections().keys(): + targetname = '%s/%s' % (lookup[target.getParent().getName()], target.getName()) + om.synth.connect.async(patch.getPath() + '/' + + lookup[node.getName()] + '/' + + port.getName(), + patch.getPath() + '/' + + targetname) + + # make external connections + for node in subpatch.getNodes(): + if node.libname == '': + lbl = node.pluginlabel + + if lbl == 'audio_input' or lbl == 'control_input': + port1 = node.getPort('in') + for port2 in port1.getConnections().keys(): + dst = '%s/%s/%s' % (patch.getPath(), lookup[port2.getParent().getName()], port2.getName()) + port4 = subpatch.getPort(node.getName()) + conns = port4.getConnections().keys() + if len(conns) == 0: + portValue = port4.value + om.synth.set_port_value_slow.async(dst, portValue) + else: + for port3 in port4.getConnections().keys(): + src = port3.getPath() + om.synth.connect.async(src, dst) + + if lbl == 'audio_output' or lbl == 'control_output': + port2 = node.getPort('out', True) + for port1 in port2.getConnections().keys(): + src = '%s/%s/%s' % (patch.getPath(), lookup[port1.getParent().getName()], port1.getName()) + port3 = subpatch.getPort(node.getName()) + for port4 in port3.getConnections().keys(): + dst = port4.getPath() + om.synth.connect.async(src, dst) + + # destroy all input and output nodes from the subpatch + for node in subpatch.getNodes(): + if node.libname == '': + lbl = node.pluginlabel + if (lbl == 'audio_input' or lbl == 'control_input' or + lbl == 'audio_output' or lbl == 'control_output'): + om.synth.destroy_node.async('%s/%s' % (patch.getPath(), + lookup[node.getName()])) + + # calculate where to move all the new nodes + (min_x, min_y, max_x, max_y) = getPatchBounds(subpatch) + sub_x = subpatch.metadata['module-x'] + if sub_x == None: + sub_x = 0 + sub_y = subpatch.metadata['module-y'] + if sub_y == None: + sub_y = 0 + x_offset = float(sub_x) + if min_x != None: + x_offset = float(sub_x) - min_x + y_offset = float(sub_y) + if min_y != None: + y_offset = float(sub_y) - min_y + + # move the new nodes + for node in subpatch.getNodes(): + x = float(node.metadata['module-x']) + if x == None: + x = 0 + om.metadata.set.async('%s/%s' % (patch.getPath(), + lookup[node.getName()]), + 'module-x', '%f' % (x + x_offset)) + y = float(node.metadata['module-y']) + if y == None: + y = 0 + om.metadata.set.async('%s/%s' % (patch.getPath(), + lookup[node.getName()]), + 'module-y', '%f' % (y + y_offset)) + + # move the old nodes in the patch + x_offset = 0 + if min_x != None and max_x != None: + x_offset = max_x - min_x + y_offset = 0 + if min_y != None and max_y != None: + y_offset = max_y - min_y + for node in patch.getNodes(): + if node.getName() not in lookup.values(): + x = node.metadata['module-x'] + if x != None and float(x) > float(sub_x): + om.metadata.set.async(node.getPath(), 'module-x', + '%f' % (float(x) + x_offset)) + y = node.metadata['module-y'] + if y != None and float(y) > float(sub_y): + om.metadata.set.async(node.getPath(), 'module-y', + '%f' % (float(y) + y_offset)) + # destroy the subpatch + om.synth.destroy_patch(subpatch.getPath()) + + +def main(om): + om.setEnvironment(omsynth.Environment()) + om.engine.activate.async() + om.engine.load_plugins.async() + om.request.all_objects(om.getAddressAsString()) + + # wait for all the data to arrive (there should be a cleaner way) + time.sleep(3) + + patch = om.getEnvironment().getPatch(sys.argv[1], True); + flatten(om, patch) + + os._exit(0) + + +if len(sys.argv) > 1: + if sys.argv[1] == "--name": + print "Flatten patch" + os._exit(0) + elif sys.argv[1] == "--shortdesc": + print "Merge the contents of all subpatches into the parent patch"; + os._exit(0) + elif sys.argv[1] == "--signature": + print "%p"; + os._exit(0) + else: + omsynth.startClient(main) + +else: + print "Which patch do you want to flatten?" + os._exit(0) diff --git a/src/progs/python/scripts/sillysinepatch.py b/src/progs/python/scripts/sillysinepatch.py new file mode 100644 index 00000000..ac51a080 --- /dev/null +++ b/src/progs/python/scripts/sillysinepatch.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +# +# Python bindings for Om +# Copyright (C) 2005 Leonard Ritter +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import omsynth +import os,time,sys + +def main(om): + om.setEnvironment(omsynth.Environment()) + om.engine.activate() + om.engine.load_plugins() + om.engine.register_client(om.getAddressAsString()) + om.request.all_objects(om.getAddressAsString()) + om.synth.create_patch("/silly_sine", 1) + om.synth.create_node("/silly_sine/output", "Internal", "", "audio_output", 0) + om.synth.create_node("/silly_sine/sine", "LADSPA", "cmt.so", "sine_fcac", 0) + om.synth.set_port_value("/silly_sine/sine/Frequency", 440.0) + om.synth.set_port_value("/silly_sine/sine/Amplitude", 1.0) + om.synth.connect("/silly_sine/sine/Output", "/silly_sine/output/out") + om.synth.enable_patch("/silly_sine") + om.engine.enable() + om.engine.unregister_client(om.getAddressAsString()) + os._exit(0) + +if __name__ == "__main__": + omsynth.startClient(main) diff --git a/src/progs/supercollider/Makefile.am b/src/progs/supercollider/Makefile.am new file mode 100644 index 00000000..69661c73 --- /dev/null +++ b/src/progs/supercollider/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = Om.sc example.sc + diff --git a/src/progs/supercollider/Om.sc b/src/progs/supercollider/Om.sc new file mode 100644 index 00000000..cb366d58 --- /dev/null +++ b/src/progs/supercollider/Om.sc @@ -0,0 +1,746 @@ +// TODO: +// * Keep track of established connections. +Om : Model { + classvar <>program = "om", <>patchLoader = "om_patch_loader"; + classvar <>oscURL, uiClass; + var loadIntoJack = true; + var allocator, requestResponders, requestHandlers, notificationResponders; + var creatingNode, newNodeEnd; + var OmInternalNode, + \LADSPA -> OmLADSPANode, + \DSSI -> OmDSSINode + ]; + uiClass = OmEmacsUI + } + *new { | netaddr | + ^super.new.init(netaddr) + } + gui { ^uiClass.new(this) } + init { |netaddr| + addr = netaddr ? NetAddr("127.0.0.1", 16180); + onNewPatch = IdentityDictionary.new; + allocator = StackNumberAllocator(0,1024); + requestHandlers = IdentityDictionary.new; + requestResponders = [ + "response/ok" -> {|id| + requestHandlers.removeAt(id).value; allocator.free(id) }, + "response/error" -> {|id,text| + requestHandlers.removeAt(id); + allocator.free(id); + ("Om"+text).error } + ].collect({|a| + var func = a.value; + OSCresponder(addr, "/om/"++a.key, {|time,resp,msg| + func.value(*msg[1..]) + }) + }); + notificationResponders = [ + "new_patch" -> {|path,poly| + var func = onNewPatch.removeAt(path); + if (func.notNil) { + func.value(this.getPatch(path,false).prSetPoly(poly)) + } + }, + "metadata/update" -> {|path,key,value| + this.getObject(path).metadata.prSetMetadata(key, value) }, + "new_node" -> {|path,poly,type,lib,label| + var patchPath, nodeName, patch, node; + var lastSlash = path.asString.inject(nil,{|last,char,i| + if(char==$/,i,last) + }); + if (lastSlash.notNil) { + patchPath = path.asString.copyFromStart(lastSlash-1); + nodeName = path.asString.copyToEnd(lastSlash+1); + patch = this.getPatch(patchPath); + if (patch.notNil) { + if (patch.hasNode(nodeName).not) { + node = nodeTypeMap[type].new + (nodeName, patch, poly, label, lib); + creatingNode = node; + patch.nodes[nodeName.asSymbol] = node; + patch.changed(\newNode, node); + } { + if (patch.getNode(nodeName).class != nodeTypeMap[type]) { + ("Om sent an existng node with differing type"+path).warn + } + } + } { + ("Om tried to create node in non-existing patch"+patchPath).warn + } + } { + ("Invalid path in node creation"+path).warn + } + }, + "new_node_end" -> { + newNodeEnd.value(creatingNode); + newNodeEnd = nil; + creatingNode = nil }, + "new_port" -> {|path,type,dir,hint,def,min,max| + var basePath, portName, parent, port; + var lastSlash = path.asString.inject(nil,{|last,char,i| + if(char==$/,i,last) + }); + if (lastSlash.notNil) { + basePath = path.asString.copyFromStart(lastSlash-1); + portName = path.asString.copyToEnd(lastSlash+1); + parent = this.getNode(basePath) ? this.getPatch(basePath); + if (parent.notNil) { + if (parent.hasPort(portName).not) { + port = OmPort.new(portName, parent, type, dir, hint, def, min, max); + parent.ports[portName.asSymbol] = port; + parent.changed(\newPort, port) + } { + if (parent.getPort(portName).porttype != type) { + ("Om tried to create an already existing port with differing type" + +path).warn + } + } + } { + ("Om tried to create port on non-existing object"+basePath).warn + } + } { + ("Invalid path in port creation"+path).warn + } + }, + "control_change" -> {|path,value| + this.getPort(path).prSetValue(value) }, + "patch_enabled" -> {|path| this.getPatch(path).prSetEnabled(true) }, + "patch_disabled" -> {|path| this.getPatch(path).prSetEnabled(false) }, + "plugin" -> {|lib,label,name,type| + plugins.add(Event.new(4,nil,pluginParentEvent).putAll( + (type:type, lib:lib, label:label, name:name))) }, + "node_removal" -> {|path| + var node = this.getNode(path); + if (node.notNil) { + node.parent.nodes.removeAt(node.name.asSymbol).free + } { + ("Om attempting to remove non-existing node"+path).warn + } + }, + "port_removal" -> {|path| + var port = this.getPort(path); + if (port.notNil) { + port.parent.ports.removeAt(port.name.asSymbol).free + } { + ("Om attempting to remove non-existing port"+path).warn + } + }, + "patch_destruction" -> {|path| + var patch = this.getPatch(path); + if (patch.notNil) { + patch.parent.patches.removeAt(patch.name.asSymbol).free + } { + ("Om attempting to remove non-existing patch"+path).warn + } + }, + "program_add" -> {|path,bank,program,name| + var node = this.getNode(path); + if (node.respondsTo(\prProgramAdd)) { + node.prProgramAdd(bank,program,name) + } { + ("Om tried to add program info to"+node).warn + } + } + ].collect({|a| + var func = a.value; + OSCresponder(addr, "/om/"++a.key, {|time,resp,msg| + func.value(*msg[1..]) + }) + }); + pluginParentEvent = Event.new(2,nil,nil).putAll(( + engine:this, + new:{|self,path,poly=1,handler|self.engine.createNode(path?("/"++self.name),self.type,self.lib,self.label,poly,created:handler)} + )); + } + *waitForBoot {|func| ^this.new.waitForBoot(func) } + waitForBoot {|func| + var r, id = 727; + requestHandlers[id] = { + r.stop; + booting=false; + this.changed(\running, true); + func.value(this) + }; + if (booting.not) {this.boot}; + r = Routine.run { + 50.do { + 0.1.wait; + addr.sendMsg("/om/ping", id) + }; + requestHandlers.removeAt(id); + "Om engine boot failed".error; + } + } + getPatch {|path, mustExist=true| + var elements, currentPatch; + if (path.class == Array) { elements = path + } { elements = path.asString.split($/) }; + elements.do{|elem| + if (elem=="") { + currentPatch = root + } { + currentPatch = currentPatch.getPatch(elem,mustExist); + if (currentPatch.isNil) { ^nil } + } + }; + ^currentPatch; + } + getNode {|path| + var basePath, nodeName, patch; + if (path.class == Array) { basePath = path + } { basePath = path.asString.split($/) }; + nodeName = basePath.pop; + patch = this.getPatch(basePath,true); + if (patch.notNil) { + ^patch.getNode(nodeName) + }; + ^nil + } + getPort {|path| + var basePath, portName, node, patch; + basePath = path.asString.split($/); + portName = basePath.pop; + node = this.getNode(basePath.copy); + if (node.notNil) { ^node.getPort(portName) }; + patch = this.getPatch(basePath,true); + if (patch.notNil) { ^patch.getPort(portName) }; + ^nil + } + getObject {|path| + var patch,node,port; + patch = this.getPatch(path,true); + if (patch.notNil) { ^patch }; + node = this.getNode(path); + if (node.notNil) { ^node }; + port = this.getPort(path,true); + if (port.notNil) { ^port }; + ^nil + } + at {|path|^this.getObject(path.asString)} + *boot {|func| + ^Om.new.waitForBoot {|e| + e.activate { + e.register { + e.loadPlugins { + e.requestPlugins { + e.requestAllObjects { + func.value(e) + } + } + } + } + } + } + } + boot { + requestResponders.do({|resp| resp.add}); + booting = true; + if (addr.addr == 2130706433) { + if (loadIntoJack) { + ("jack_load"+"-i"+addr.port+"Om"+"om").unixCmd + } { + (program+"-p"+addr.port).unixCmd + } + } { + "You have to manually boot Om now".postln + } + } + loadPatch {|patchPath| (patchLoader + patchPath).unixCmd } + activate { | handler | + this.sendReq("engine/activate", { + root = OmPatch("",nil,this); + this.changed(\newPatch, root); + handler.value + }) + } + register { | handler | + this.sendReq("engine/register_client", { + registered=true; + notificationResponders.do({|resp| resp.add}); + this.changed(\registered, registered); + handler.value(this) + }) + } + unregister { | handler | + this.sendReq("engine/unregister_client", { + registered=false; + notificationResponders.do({|resp| resp.remove}); + this.changed(\registered, registered); + handler.value(this) + }) + } + registered_ {|flag| + if (flag and: registered.not) { + this.register + } { + if (flag.not and: registered) { + this.unregister + } + } + } + loadPlugins { | handler | this.sendReq("engine/load_plugins", handler) } + requestPlugins {|handler| + var startTime = Main.elapsedTime; + plugins = Set.new; + this.sendReq("request/plugins", { + ("Received info about"+plugins.size+"plugins in"+(Main.elapsedTime-startTime)+"seconds").postln; + this.changed(\plugins, plugins); + handler.value(this); + }) + } + requestAllObjects { |handler| + this.sendReq("request/all_objects", handler) + } + createPatch { | path, poly=1, handler | + onNewPatch[path.asSymbol] = handler; + this.sendReq("synth/create_patch", nil, path.asString, poly.asInteger) + } + createNode { | path, type='LADSPA', lib, label, poly=1, created, handler | + newNodeEnd = created; + this.sendReq("synth/create_node",handler,path,type,lib,label,poly) + } + createAudioInput { | path, handler | + this.createNode(path,"Internal","","audio_input",0,handler) + } + createAudioOutput {|path,handler| + this.createNode(path,"Internal","","audio_output",0,handler) + } + createMIDIInput {|path,handler| + this.createNode(path,"Internal","","midi_input",1,handler) + } + createMIDIOutput {|path,handler| + this.createNode(path,"Internal","","midi_output",1,handler) + } + createNoteIn {|path| this.createNode(path,"Internal","","note_in") } + connect {|fromPath,toPath,handler| + this.sendReq("synth/connect",handler,fromPath.asString,toPath.asString) + } + disconnect { | fromPath, toPath, handler | + this.sendReq("synth/disconnect",handler,fromPath.asString,toPath.asString) + } + disconnectAll { | path, handler | + this.sendReq("synth/disconnect_all",handler,path); + } + sendReq { | path, handler...args | + var id = allocator.alloc; + requestHandlers[id] = handler; + addr.sendMsg("/om/"++path, id, *args) + } + quit { + if (loadIntoJack) { + ("jack_unload"+"Om").unixCmd; + booting=false; + requestResponders.do(_.remove); + notificationResponders.do(_.remove); + this.changed(\running, false); + } { + this.sendReq("engine/quit", { + booting=false; + requestResponders.do(_.remove); + notificationResponders.do(_.remove); + this.changed(\running, false); + }) + } + } + ping {| n=1, func | + var id, result, start; + id = allocator.alloc; + result = 0; + requestHandlers[id] = { + var end; + end = Main.elapsedTime; + result=max((end-start).postln,result); + n=n-1; + if (n > 0) { + start = Main.elapsedTime; + addr.sendMsg("/om/ping", id) + } { + allocator.free(id); + func.value(result) + } + }; + start = Main.elapsedTime; + addr.sendMsg("/om/ping", id) + } + setPortValue {|path, val| this.getPort(path.asString).value=val } + jackConnect {|path, jackPort| + this.getPort(path).jackConnect(jackPort) + } + noteOn {|path, note, vel| + var patch,node; + patch = this.getPatch(path,true); + if (patch.notNil) { patch.noteOn(note,vel) }; + node = this.getNode(path); + if (node.notNil) { node.noteOn(note,vel) }; + } + noteOff {|path, note| + var patch,node; + patch = this.getPatch(path,true); + if (patch.notNil) { patch.noteOff(note) }; + node = this.getNode(path); + if (node.notNil) { node.noteOff(note) }; + } + matchPlugins{ | label, lib, name, type | + ^plugins.select{ |p| + label.matchItem(p.label) and: { + lib.matchItem(p.lib) and: { + name.matchItem(p.name) and: { + type.matchItem(p.type) + } + } + } + } + } + dssiMsg {|path,reqType="program" ...args| + addr.sendMsg("/dssi"++path++$/++reqType,*args) + } +} + +OmMetadata { + var object, dict; + *new {|obj|^super.new.metadataInit(obj)} + metadataInit {|obj| + dict=Dictionary.new; + object=obj + } + put {|key,val| + object.engine.sendReq("metadata/set", nil, + object.path, key.asString, val.asString) + } + at {|key|^dict.at(key.asSymbol)} + prSetMetadata {|key,val| + dict.put(key,val); + object.changed(\metadata, key, val) + } +} + +OmObject : Model { + var diff --git a/src/progs/supercollider/example.sc b/src/progs/supercollider/example.sc new file mode 100644 index 00000000..6186e433 --- /dev/null +++ b/src/progs/supercollider/example.sc @@ -0,0 +1,27 @@ +// Boot Om (inside SC) and the scsynth server +( +o=Om.boot { + o.loadPatch("/home/mlang/src/om-synth/src/clients/patches/303.om"); + s.boot; +} +) +// Connect patch output to one SC input +o.jackConnect("/303/output", "SuperCollider:in_3"); +// Play this input on the default output bus (most simple postprocessor) +{AudioIn.ar(3).dup}.play; +// A simple 303 pattern +( +Tempo.bpm=170; +Ppar([ + Pbind(\type, \om, \target, o.getPatch("/303",true), + \dur, 1/1, \octave,2,\degree, Pseq([Pshuf([0,2,4,6],16)],2)), + Pbind(\type, \om, \target, o.getPatch("/303",true), + \dur, Prand([Pshuf([1/2,1/4,1/4],4),Pshuf([1/3,1/3,1/6,1/6],4)],inf), + \legato, Prand((0.5,0.55..0.9),inf), + \octave,3,\degree, Pseq([Pshuf([0,2,4,6],2)],40)), + Pbind(\type, \om, \omcmd, \setPortValue, + \target, o.getPort("/303/cutoff",true), + \dur, 1/10, \portValue, Pseq((0,0.005..1).mirror,2)), + Pbind(\type, \om, \omcmd, \setPortValue, + \target, o.getPort("/303/resonance",true), \portValue, 1)]).play(quant:4) +) -- cgit v1.2.1