push2: start of pad layout editing
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 7 Jul 2016 13:26:06 +0000 (09:26 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 27 Sep 2016 19:59:30 +0000 (14:59 -0500)
libs/surfaces/push2/gui.cc
libs/surfaces/push2/gui.h
libs/surfaces/push2/mode.cc [new file with mode: 0644]
libs/surfaces/push2/mode.h [new file with mode: 0644]
libs/surfaces/push2/push2.cc
libs/surfaces/push2/wscript

index 2606418eabf12eb1a0605fc4b7ed9c5f3ae41e57..78772aeefd252fc03e7bc2f229621c6e5177c27a 100644 (file)
@@ -32,6 +32,8 @@
 #include "ardour/audioengine.h"
 #include "ardour/filesystem_paths.h"
 
+#include "evoral/midi_util.h"
+
 #include "push2.h"
 #include "gui.h"
 
@@ -125,12 +127,26 @@ P2GUI::P2GUI (Push2& p)
 
        hpacker.pack_start (table, true, true);
 
+       pad_table.set_spacings (3);
        build_pad_table ();
 
+       root_note_selector.set_model (build_note_columns());
+       root_note_selector.pack_start (note_columns.name);
+
+       mode_selector.set_model (build_mode_columns());
+       mode_selector.pack_start (mode_columns.name);
+
+       mode_packer.pack_start (root_note_selector, false, false);
+       mode_packer.pack_start (mode_selector, false, false);
+
+       pad_notebook.append_page (pad_table, _("Pad Layout"));
+       pad_notebook.append_page (mode_packer, _("Modes/Scales"));
+       pad_notebook.append_page (custom_packer, _("Custom"));
+
        set_spacing (12);
 
        pack_start (hpacker, false, false);
-       pack_start (pad_table, true, true);
+       pack_start (pad_notebook);
 
        /* update the port connection combos */
 
@@ -413,10 +429,192 @@ P2GUI::build_pad_table ()
        for (int row = 0; row < 8; ++row) {
                for (int col = 0; col < 8; ++col) {
 
-                       Gtk::Button* b = manage (new Button (string_compose ("%1", (int) p2.pad_note (row, col))));
+                       int n = (int) p2.pad_note (row, col);
+
+                       Gtk::Button* b = manage (new Button (string_compose ("%1 (%2)", Evoral::midi_note_name (n), n)));
                        b->show ();
 
                        pad_table.attach (*b, col, col+1, row, row + 1);
                }
        }
 }
+
+Glib::RefPtr<Gtk::ListStore>
+P2GUI::build_mode_columns ()
+{
+       Glib::RefPtr<Gtk::ListStore> store = ListStore::create (mode_columns);
+       TreeModel::Row row;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Random");
+       row[mode_columns.mode] = MusicalMode::Random;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Dorian");
+       row[mode_columns.mode] = MusicalMode::Dorian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Ionian (\"Minor\")");
+       row[mode_columns.mode] = MusicalMode::Ionian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Phrygian");
+       row[mode_columns.mode] = MusicalMode::Phrygian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Lydian");
+       row[mode_columns.mode] = MusicalMode::Lydian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Mixolydian");
+       row[mode_columns.mode] = MusicalMode::Mixolydian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Aeolian (\"Major\")");
+       row[mode_columns.mode] = MusicalMode::Aeolian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Locrian");
+       row[mode_columns.mode] = MusicalMode::Locrian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Pentatonic Major");
+       row[mode_columns.mode] = MusicalMode::PentatonicMajor;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Pentatonic Minor");
+       row[mode_columns.mode] = MusicalMode::PentatonicMinor;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Major Chord");
+       row[mode_columns.mode] = MusicalMode::MajorChord;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Minor Chord");
+       row[mode_columns.mode] = MusicalMode::MinorChord;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Min7");
+       row[mode_columns.mode] = MusicalMode::Min7;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Sus4");
+       row[mode_columns.mode] = MusicalMode::Sus4;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Chromatic");
+       row[mode_columns.mode] = MusicalMode::Chromatic;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Blues Scale");
+       row[mode_columns.mode] = MusicalMode::BluesScale;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Neapolitan Minor");
+       row[mode_columns.mode] = MusicalMode::NeapolitanMinor;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Neapolitan Major");
+       row[mode_columns.mode] = MusicalMode::NeapolitanMajor;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Oriental");
+       row[mode_columns.mode] = MusicalMode::Oriental;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Double Harmonic");
+       row[mode_columns.mode] = MusicalMode::DoubleHarmonic;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Enigmatic");
+       row[mode_columns.mode] = MusicalMode::Enigmatic;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Hirajoshi");
+       row[mode_columns.mode] = MusicalMode::Hirajoshi;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Hungarian Minor");
+       row[mode_columns.mode] = MusicalMode::HungarianMinor;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Hungarian Major");
+       row[mode_columns.mode] = MusicalMode::HungarianMajor;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Kumoi");
+       row[mode_columns.mode] = MusicalMode::Kumoi;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Iwato");
+       row[mode_columns.mode] = MusicalMode::Iwato;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Hindu");
+       row[mode_columns.mode] = MusicalMode::Hindu;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Spanish 8 Tone");
+       row[mode_columns.mode] = MusicalMode::Spanish8Tone;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Pelog");
+       row[mode_columns.mode] = MusicalMode::Pelog;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Hungarian Gypsy");
+       row[mode_columns.mode] = MusicalMode::HungarianGypsy;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Overtone");
+       row[mode_columns.mode] = MusicalMode::Overtone;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Leading Whole Tone");
+       row[mode_columns.mode] = MusicalMode::LeadingWholeTone;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Arabian");
+       row[mode_columns.mode] = MusicalMode::Arabian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Balinese");
+       row[mode_columns.mode] = MusicalMode::Balinese;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Gypsy");
+       row[mode_columns.mode] = MusicalMode::Gypsy;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Mohammedan");
+       row[mode_columns.mode] = MusicalMode::Mohammedan;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Javanese");
+       row[mode_columns.mode] = MusicalMode::Javanese;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Persian");
+       row[mode_columns.mode] = MusicalMode::Persian;
+
+       row = *store->append();
+       row[mode_columns.name] = _("Algerian");
+       row[mode_columns.mode] = MusicalMode::Algerian;
+
+       return store;
+}
+
+Glib::RefPtr<Gtk::ListStore>
+P2GUI::build_note_columns ()
+{
+       Glib::RefPtr<Gtk::ListStore> store = ListStore::create (note_columns);
+       TreeModel::Row row;
+
+       for (int n = 0; n < 127; ++n) {
+               row = *store->append ();
+               row[note_columns.number] = n;
+               row[note_columns.name] = Evoral::midi_note_name (n);
+       }
+
+       return store;
+}
index 314e8081c6e46acc9e044cfc16fdb2a0ab3cbbfb..2ec6281a52da201426d571b3e6659e2b7714b7e6 100644 (file)
@@ -28,6 +28,7 @@
 #include <gtkmm/image.h>
 #include <gtkmm/table.h>
 #include <gtkmm/treestore.h>
+#include <gtkmm/notebook.h>
 
 namespace Gtk {
        class CellRendererCombo;
@@ -35,6 +36,7 @@ namespace Gtk {
 }
 
 #include "push2.h"
+#include "mode.h"
 
 namespace ArdourSurface {
 
@@ -94,6 +96,38 @@ private:
        /* Pads */
 
        Gtk::Table pad_table;
+
+       /* root notes */
+
+       struct NoteColumns : public Gtk::TreeModel::ColumnRecord {
+               NoteColumns () {
+                       add (number);
+                       add (name);
+               }
+               Gtk::TreeModelColumn<int>         number;
+               Gtk::TreeModelColumn<std::string> name;
+       };
+       NoteColumns note_columns;
+       Glib::RefPtr<Gtk::ListStore> build_note_columns ();
+       Gtk::ComboBox root_note_selector;
+
+       /* modes/scales */
+
+       struct ModeColumns : public Gtk::TreeModel::ColumnRecord {
+               ModeColumns () {
+                       add (mode);
+                       add (name);
+               }
+               Gtk::TreeModelColumn<MusicalMode::Type>  mode;
+               Gtk::TreeModelColumn<std::string> name;
+       };
+       ModeColumns mode_columns;
+       Glib::RefPtr<Gtk::ListStore> build_mode_columns ();
+       Gtk::ComboBox mode_selector;
+
+       Gtk::Notebook pad_notebook;
+       Gtk::VBox     mode_packer;
+       Gtk::VBox     custom_packer;
 };
 
 }
diff --git a/libs/surfaces/push2/mode.cc b/libs/surfaces/push2/mode.cc
new file mode 100644 (file)
index 0000000..324c53c
--- /dev/null
@@ -0,0 +1,313 @@
+#include "mode.h"
+
+MusicalMode::MusicalMode (MusicalMode::Type t)
+{
+       fill (*this, t);
+}
+
+MusicalMode::~MusicalMode()
+{
+}
+
+void
+MusicalMode::fill (MusicalMode& m, MusicalMode::Type t)
+{
+       m.steps.clear ();
+
+       /* scales/modes as distances from root, expressed
+          in fractional whole tones.
+       */
+
+       switch (t) {
+       case Random:
+               m.steps.push_back (0.0); // sekrit code for "random"
+               break;
+       case Dorian:
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (3.0);
+               m.steps.push_back (4.0);
+               m.steps.push_back (4.5);
+               break;
+       case Ionian:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.5);
+               break;
+       case Phrygian:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               break;
+       case Lydian:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (3.0);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.5);
+               break;
+       case Mixolydian:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.0);
+               break;
+       case Aeolian:
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               break;
+       case Locrian:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (3.0);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               break;
+       case PentatonicMajor:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               break;
+       case PentatonicMinor:
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (5.0);
+               break;
+       case  MajorChord:
+               m.steps.push_back (2.0);
+               m.steps.push_back (3.5);
+               break;
+       case  MinorChord:
+               m.steps.push_back (1.5);
+               m.steps.push_back (3.5);
+               break;
+       case  Min7:
+               m.steps.push_back (1.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (5.0);
+               break;
+       case  Sus4:
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               break;
+       case  Chromatic:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.0);
+               m.steps.push_back (5.5);
+               break;
+       case  BluesScale:
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.0);
+               m.steps.push_back (5.5);
+               break;
+       case  NeapolitanMinor:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.5);
+               break;
+       case  NeapolitanMajor:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.5);
+               break;
+       case  Oriental:
+               m.steps.push_back (0.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.0);
+               break;
+       case  DoubleHarmonic:
+               m.steps.push_back (0.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.5);
+               break;
+       case  Enigmatic:
+               m.steps.push_back (0.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (3.0);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               m.steps.push_back (5.5);
+               break;
+       case  Hirajoshi:
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               break;
+       case  HungarianMinor:
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.5);
+               break;
+       case  HungarianMajor:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (3.0);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               break;
+       case  Kumoi:
+               m.steps.push_back (0.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               break;
+       case  Iwato:
+               m.steps.push_back (0.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (5.0);
+               break;
+       case  Hindu:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               break;
+       case  Spanish8Tone:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               break;
+       case  Pelog:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (5.0);
+               break;
+       case  HungarianGypsy:
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               break;
+       case  Overtone:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (3.0);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.0);
+               break;
+       case  LeadingWholeTone:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (3.0);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               m.steps.push_back (5.5);
+               break;
+       case  Arabian:
+               m.steps.push_back (1.0);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.0);
+               break;
+       case  Balinese:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               break;
+       case  Gypsy:
+               m.steps.push_back (0.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.5);
+               break;
+       case  Mohammedan:
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.5);
+               break;
+       case  Javanese:
+               m.steps.push_back (0.5);
+               m.steps.push_back (1.5);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.5);
+               m.steps.push_back (5.0);
+               break;
+       case  Persian:
+               m.steps.push_back (0.5);
+               m.steps.push_back (2.0);
+               m.steps.push_back (2.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.5);
+               break;
+       case  Algerian:
+               m.steps.push_back (1.0);
+               m.steps.push_back (1.5);
+               m.steps.push_back (3.0);
+               m.steps.push_back (3.5);
+               m.steps.push_back (4.0);
+               m.steps.push_back (5.5);
+               m.steps.push_back (6.0);
+               m.steps.push_back (7.0);
+               m.steps.push_back (7.5);
+               m.steps.push_back (8.5);
+               break;
+       }
+}
diff --git a/libs/surfaces/push2/mode.h b/libs/surfaces/push2/mode.h
new file mode 100644 (file)
index 0000000..e638d53
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __ardour_push2_mode_h__
+#define __ardour_push2_mode_h__
+
+#include <vector>
+
+class MusicalMode
+{
+  public:
+       enum Type {
+               Random,
+               Dorian,
+               Ionian,
+               Phrygian,
+               Lydian,
+               Mixolydian,
+               Aeolian,
+               Locrian,
+               PentatonicMajor,
+               PentatonicMinor,
+               MajorChord,
+               MinorChord,
+               Min7,
+               Sus4,
+               Chromatic,
+               BluesScale,
+               NeapolitanMinor,
+               NeapolitanMajor,
+               Oriental,
+               DoubleHarmonic,
+               Enigmatic,
+               Hirajoshi,
+               HungarianMinor,
+               HungarianMajor,
+               Kumoi,
+               Iwato,
+               Hindu,
+               Spanish8Tone,
+               Pelog,
+               HungarianGypsy,
+               Overtone,
+               LeadingWholeTone,
+               Arabian,
+               Balinese,
+               Gypsy,
+               Mohammedan,
+               Javanese,
+               Persian,
+               Algerian
+       };
+
+       MusicalMode (Type t);
+       ~MusicalMode ();
+
+       std::vector<float> steps;
+
+  private:
+       static void fill (MusicalMode&, Type);
+};
+
+#endif /* __ardour_push2_mode_h__ */
index 0eb1d6cfc7aa12f02a9dfd81f12bc6245d6538aa..273c14a3b35181cbf72a798c683a019ed9688248 100644 (file)
@@ -1508,9 +1508,12 @@ Push2::pad_filter (MidiBuffer& in, MidiBuffer& out) const
 
        for (MidiBuffer::iterator ev = in.begin(); ev != in.end(); ++ev) {
                if ((*ev).is_note_on() || (*ev).is_note_off()) {
-                       /* encoder touch start/touch end use note 0-10 */
 
-                       if ((*ev).note() > 10) {
+                       /* encoder touch start/touch end use note
+                        * 0-10. touchstrip uses note 12
+                        */
+
+                       if ((*ev).note() > 10 && (*ev).note() != 12) {
 
                                int n = (*ev).note ();
 
@@ -1600,8 +1603,10 @@ Push2::input_port()
 void
 Push2::build_pad_table ()
 {
-       for (int i = 36; i < 99; ++i) {
-               pad_map[i] = i + (octave_shift*12);
+       for (int row = 0; row < 8; ++row) {
+               for (int col = 7; col >= 0; --col) {
+                       pad_map[row*8+col] = 99 - (row*8+(7-col)) + (octave_shift*12);
+               }
        }
 
        PadChange (); /* emit signal */
index 2a76b10648b14f0efa1180284e6a8d5739d3261f..322b08f07e66374daafe26705215530d8b014b72 100644 (file)
@@ -35,7 +35,7 @@ def build(bld):
     obj.name         = 'libardour_push2'
     obj.target       = 'ardour_push2'
     obj.uselib       = 'CAIROMM PANGOMM USB GTKMM'
-    obj.use          = 'libardour libardour_cp libgtkmm2ext libpbd libtimecode'
+    obj.use          = 'libardour libardour_cp libgtkmm2ext libpbd libevoral libtimecode'
     obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
 
 def shutdown():