summaryrefslogtreecommitdiffstats
path: root/src/progs/demolition
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-06-10 02:43:54 +0000
committerDavid Robillard <d@drobilla.net>2006-06-10 02:43:54 +0000
commit47246db7e9d71ba694b719001033fba1766a58c4 (patch)
tree25614ea4f2c92033a3cd37f6413df742f09a5369 /src/progs/demolition
parent98fe0e7056e6697396249531785d3899f94d79be (diff)
downloadingen-47246db7e9d71ba694b719001033fba1766a58c4.tar.gz
ingen-47246db7e9d71ba694b719001033fba1766a58c4.tar.bz2
ingen-47246db7e9d71ba694b719001033fba1766a58c4.zip
More juggling
git-svn-id: http://svn.drobilla.net/lad/grauph@16 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/progs/demolition')
-rw-r--r--src/progs/demolition/DemolitionClientInterface.cpp109
-rw-r--r--src/progs/demolition/DemolitionClientInterface.h75
-rw-r--r--src/progs/demolition/DemolitionModel.cpp246
-rw-r--r--src/progs/demolition/DemolitionModel.h60
-rw-r--r--src/progs/demolition/Makefile.am17
-rw-r--r--src/progs/demolition/README7
-rw-r--r--src/progs/demolition/cmdline.c149
-rw-r--r--src/progs/demolition/cmdline.ggo7
-rw-r--r--src/progs/demolition/cmdline.h45
-rw-r--r--src/progs/demolition/demolition.cpp334
10 files changed, 1049 insertions, 0 deletions
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 <cstdlib>
+#include <string>
+#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 <stdlib.h>
+#include <iostream>
+using std::cout; using std::cerr; using std::endl;
+
+
+DemolitionModel::~DemolitionModel()
+{
+ for (vector<PluginModel*>::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i)
+ delete *i;
+
+ for (vector<PatchModel*>::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<PatchModel*>::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<PatchModel*>::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<PatchModel*>::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<PatchModel*>::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 <vector>
+#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<PluginModel*> m_plugins;
+ vector<PatchModel*> 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* 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 <iostream>
+#include <unistd.h>
+#include <stdlib.h>
+#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<DemolitionClientInterface> client
+ = CountedPtr<DemolitionClientInterface>(new DemolitionClientInterface(model));
+
+ engine = new OSCModelEngineInterface(engine_url);
+ engine->activate();
+
+ /* Connect to engine */
+ //engine->attach(engine_url);
+ engine->register_client(ClientKey(), (CountedPtr<ClientInterface>)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());
+ }*/
+}
+