[SCM] ardour/master: Sync with upstream VCS r8077.
adiknoth-guest at users.alioth.debian.org
adiknoth-guest at users.alioth.debian.org
Mon Feb 14 17:33:42 UTC 2011
The following commit has been merged in the master branch:
commit 60568198ea658bec2ac3ab6f72a796b2d9e27d1c
Author: Adrian Knoth <adi at drcomp.erfurt.thur.de>
Date: Mon Feb 14 17:32:27 2011 +0100
Sync with upstream VCS r8077.
A few fixes have been incorporated upstream. Let's provide those to our
users.
diff --git a/debian/patches/000_sync_vcs.patch b/debian/patches/000_sync_vcs.patch
new file mode 100644
index 0000000..e1b11ae
--- /dev/null
+++ b/debian/patches/000_sync_vcs.patch
@@ -0,0 +1,4618 @@
+From: Adrian Knoth <adi at drcomp.erfurt.thur.de>
+Description: Sync with upstream VCS revision 8077
+Origin: git://repo.or.cz/ardour2.git
+Forwarded: Not-needed
+--- a/ardour.rc.in
++++ b/ardour.rc.in
+@@ -1,8 +1,8 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+ <Ardour>
+- <MIDI-port tag="%MIDITAG%" device="ardour" type="%MIDITYPE%" mode="duplex"/>
+- <MIDI-port tag="control" device="ardour" type="%MIDITYPE%" mode="duplex"/>
+- <MIDI-port tag="mcu" device="ardour" type="%MIDITYPE%" mode="duplex"/>
++ <MIDI-port tag="%MIDITAG%" device="%MIDI_DEVICE_NAME%" type="%MIDITYPE%" mode="duplex"/>
++ <MIDI-port tag="control" device="%MIDI_DEVICE_NAME%" type="%MIDITYPE%" mode="duplex"/>
++ <MIDI-port tag="mcu" device="%MIDI_DEVICE_NAME%" type="%MIDITYPE%" mode="duplex"/>
+ <Config>
+ <Option name="minimum-disk-io-bytes" value="262144"/>
+ <Option name="track-buffer-seconds" value="5.000000"/>
+--- a/gtk2_ardour/ardev_common.sh.in
++++ b/gtk2_ardour/ardev_common.sh.in
+@@ -11,9 +11,9 @@
+ echo USING OLD CLEARLOOKS
+ export GTK_PATH=~/.ardour2:libs/clearlooks-older
+ fi
+-export VAMP_PATH=libs/vamp-plugins:$VAMP_PATH
++export VAMP_PATH=libs/vamp-plugins${VAMP_PATH:+:$VAMP_PATH}
+
+-export LD_LIBRARY_PATH=libs/vamp-sdk:libs/surfaces/control_protocol:libs/ardour:libs/midi++2:libs/pbd:libs/rubberband:libs/soundtouch:libs/gtkmm2ext:libs/sigc++2:libs/glibmm2:libs/gtkmm2/atk:libs/gtkmm2/pango:libs/gtkmm2/gdk:libs/gtkmm2/gtk:libs/libgnomecanvasmm:libs/libsndfile:libs/appleutility:$LD_LIBRARY_PATH
++export LD_LIBRARY_PATH=libs/vamp-sdk:libs/surfaces/control_protocol:libs/ardour:libs/midi++2:libs/pbd:libs/rubberband:libs/soundtouch:libs/gtkmm2ext:libs/sigc++2:libs/glibmm2:libs/gtkmm2/atk:libs/gtkmm2/pango:libs/gtkmm2/gdk:libs/gtkmm2/gtk:libs/libgnomecanvasmm:libs/libsndfile:libs/appleutility${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
+
+ # DYLD_LIBRARY_PATH is for darwin.
+ export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH
+--- a/gtk2_ardour/ardour.sh.in
++++ b/gtk2_ardour/ardour.sh.in
+@@ -1,8 +1,8 @@
+ #!/bin/sh
+
+-export GTK_PATH=%INSTALL_PREFIX%/%LIBDIR%/ardour2:$GTK_PATH
++export GTK_PATH=%INSTALL_PREFIX%/%LIBDIR%/ardour2${GTK_PATH:+:$GTK_PATH}
+
+-export LD_LIBRARY_PATH=%INSTALL_PREFIX%/%LIBDIR%/ardour2:$LD_LIBRARY_PATH
++export LD_LIBRARY_PATH=%INSTALL_PREFIX%/%LIBDIR%/ardour2${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
+ # DYLD_LIBRARY_PATH is for Darwin
+ export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
+
+--- a/gtk2_ardour/ardour_ui.cc
++++ b/gtk2_ardour/ardour_ui.cc
+@@ -34,6 +34,7 @@
+
+ #include <gtkmm/messagedialog.h>
+ #include <gtkmm/accelmap.h>
++#include <gtkmm2ext/application.h>
+
+ #include <pbd/error.h>
+ #include <pbd/basename.h>
+@@ -643,6 +644,11 @@
+ void
+ ARDOUR_UI::startup ()
+ {
++ Application* app = Application::instance();
++
++ app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
++ app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
++
+ string name, path;
+
+ new_session_dialog = new NewSessionDialog();
+@@ -653,7 +659,9 @@
+ if (audio_setup) {
+ new_session_dialog->engine_control.set_state (*audio_setup);
+ }
+-
++
++ app->ready ();
++
+ if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
+ return;
+ }
+@@ -2347,6 +2355,7 @@
+ ARDOUR_UI::idle_load (const Glib::ustring& path)
+ {
+ if (session) {
++
+ if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
+ /* /path/to/foo => /path/to/foo, foo */
+ load_session (path, basename_nosuffix (path));
+@@ -2354,13 +2363,13 @@
+ /* /path/to/foo/foo.ardour => /path/to/foo, foo */
+ load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
+ }
++
+ } else {
+
+ ARDOUR_COMMAND_LINE::session_name = path;
+
+ if (new_session_dialog) {
+
+-
+ /* make it break out of Dialog::run() and
+ start again.
+ */
+--- a/gtk2_ardour/ardour_ui_ed.cc
++++ b/gtk2_ardour/ardour_ui_ed.cc
+@@ -891,9 +891,6 @@
+ }
+
+ app->set_menu_bar (*menu_bar);
+-
+- app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
+- app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
+ }
+
+ void
+--- a/gtk2_ardour/audio_streamview.cc
++++ b/gtk2_ardour/audio_streamview.cc
+@@ -378,6 +378,8 @@
+ list<RegionView *>::iterator i, tmp;
+ list<CrossfadeView*>::iterator xi, tmpx;
+
++ cerr << "REDISPLAY diskstream\n";
++
+ for (i = region_views.begin(); i != region_views.end(); ++i) {
+ (*i)->set_valid (false);
+ }
+@@ -424,6 +426,7 @@
+ /* now fix layering */
+
+ for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
++ cerr << "Layering call for " << (*i)->region()->name() << endl;
+ region_layered (*i);
+ }
+ }
+--- a/gtk2_ardour/canvas-waveview.c
++++ b/gtk2_ardour/canvas-waveview.c
+@@ -1246,12 +1246,12 @@
+ max = waveview->cache->data[cache_index].max;
+ min = waveview->cache->data[cache_index].min;
+
+- if (max >= 1.0) {
++ if (max >= 0.98853) { // -0.9dBFS
+ max = 1.0;
+ next_clip_max = 1;
+ }
+
+- if (min <= -1.0) {
++ if (min <= -0.98853) { // ditto
+ min = -1.0;
+ next_clip_min = 1;
+ }
+--- a/gtk2_ardour/editor_audio_import.cc
++++ b/gtk2_ardour/editor_audio_import.cc
+@@ -164,7 +164,9 @@
+ }
+
+ SrcQuality quality = sfbrowser->get_src_quality();
++
+
++ cerr << "Start import of " << paths.size() << " at " << where << endl;
+
+ if (sfbrowser->copy_files_btn.get_active()) {
+ do_import (paths, chns, mode, quality, where);
+@@ -289,6 +291,7 @@
+ boost::shared_ptr<AudioTrack> track;
+ vector<ustring> to_import;
+ int nth = 0;
++ bool use_timestamp = (pos == -1);
+
+ if (interthread_progress_window == 0) {
+ build_interthread_progress_window ();
+@@ -339,6 +342,11 @@
+ /* NOTREACHED*/
+ }
+
++ /* have to reset this for every file we handle */
++
++ if (use_timestamp) {
++ pos = -1;
++ }
+
+ switch (chns) {
+ case Editing::ImportDistinctFiles:
+@@ -682,14 +690,6 @@
+
+ use_timestamp = (pos == -1);
+
+- if (use_timestamp) {
+- if (sources[0]->natural_position() != 0) {
+- pos = sources[0]->natural_position();
+- } else {
+- pos = get_preferred_edit_position ();
+- }
+- }
+-
+ if (target_regions == 1) {
+
+ /* take all the sources we have and package them up as a region */
+@@ -699,8 +699,8 @@
+ (RegionFactory::create (sources, 0, sources[0]->length(), region_name, 0,
+ Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External)));
+
+- if (use_timestamp) {
+- ar->special_set_position(sources[0]->natural_position());
++ if (use_timestamp) {
++ ar->special_set_position(sources[0]->natural_position());
+ }
+
+ regions.push_back (ar);
+@@ -750,16 +750,57 @@
+ }
+
+ int n = 0;
++ nframes_t rlen = 0;
++
++ cerr << "About to add " << regions.size() << endl;
+
+ for (vector<boost::shared_ptr<AudioRegion> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
+-
++
++ if (use_timestamp) {
++
++ cerr << "Using timestamp to place region " << (*r)->name() << endl;
++
++ /* get timestamp for this region */
++
++ const boost::shared_ptr<Source> s ((*r)->get_sources().front());
++ const boost::shared_ptr<AudioSource> as = boost::dynamic_pointer_cast<AudioSource> (s);
++
++ assert (as);
++
++ if (as->natural_position() != 0) {
++ pos = as->natural_position();
++ cerr << "\tgot " << pos << " from source TC info\n";
++ } else if (target_tracks == 1) {
++ /* hmm, no timestamp available, put it after the previous region
++ */
++ if (n == 0) {
++ pos = get_preferred_edit_position ();
++ cerr << "\tno timestamp, first file, use edit pos = " << pos << endl;
++ } else {
++ pos += rlen;
++ cerr << "\tpacked-sequence-shuffle to " << pos << endl;
++ }
++ } else {
++ pos = get_preferred_edit_position ();
++ cerr << "\tmultitracks, using edit position = " << pos << endl;
++ }
++
++ }
++
++ cerr << "Actually inserting at " << pos << endl;
++
+ finish_bringing_in_audio (*r, input_chan, output_chan, pos, mode, track);
+
++ rlen = (*r)->length();
++
+ if (target_tracks != 1) {
+ track.reset ();
+- } else {
+- pos += (*r)->length();
+- }
++ } else {
++ if (!use_timestamp) {
++ /* line each one up right after the other */
++ pos += (*r)->length();
++ }
++ }
+ }
+
+ /* setup peak file building in another thread */
+--- a/gtk2_ardour/editor_canvas.cc
++++ b/gtk2_ardour/editor_canvas.cc
+@@ -107,13 +107,8 @@
+ track_canvas->set_center_scroll_region (false);
+ track_canvas->set_dither (Gdk::RGB_DITHER_NONE);
+
+- Glib::RefPtr<Gdk::Screen> screen = get_screen();
+-
+- if (!screen) {
+- screen = Gdk::Screen::get_default();
+- }
+- physical_screen_width = screen->get_width ();
+- physical_screen_height = screen->get_height ();
++ gint phys_width = physical_screen_width (Glib::RefPtr<Gdk::Window>());
++ gint phys_height = physical_screen_height (Glib::RefPtr<Gdk::Window>());
+
+ /* stuff for the verbose canvas cursor */
+
+@@ -144,21 +139,21 @@
+
+ #ifdef GTKOSX
+ /*XXX please don't laugh. this actually improves canvas performance on osx */
+- bogus_background_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, max_canvas_coordinate/3, physical_screen_height);
++ bogus_background_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, max_canvas_coordinate/3, phys_height);
+ bogus_background_rect->property_outline_pixels() = 0;
+ #endif
+- transport_loop_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, physical_screen_height);
++ transport_loop_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, phys_height);
+ transport_loop_range_rect->property_outline_pixels() = 1;
+ transport_loop_range_rect->hide();
+
+- transport_punch_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, physical_screen_height);
++ transport_punch_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, phys_height);
+ transport_punch_range_rect->property_outline_pixels() = 0;
+ transport_punch_range_rect->hide();
+
+ _background_group = new ArdourCanvas::Group (*track_canvas->root());
+ _master_group = new ArdourCanvas::Group (*track_canvas->root());
+
+- range_marker_drag_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, physical_screen_height);
++ range_marker_drag_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, phys_height);
+ range_marker_drag_rect->hide ();
+
+ _trackview_group = new ArdourCanvas::Group (*_master_group);
+@@ -166,60 +161,60 @@
+
+ meter_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ if (Profile->get_sae()) {
+- meter_bar = new ArdourCanvas::SimpleRect (*meter_bar_group, 0.0, 0.0, physical_screen_width, timebar_height - 1);
++ meter_bar = new ArdourCanvas::SimpleRect (*meter_bar_group, 0.0, 0.0, phys_width, timebar_height - 1);
+ meter_bar->property_outline_pixels() = 1;
+ } else {
+- meter_bar = new ArdourCanvas::SimpleRect (*meter_bar_group, 0.0, 0.0, physical_screen_width, timebar_height);
++ meter_bar = new ArdourCanvas::SimpleRect (*meter_bar_group, 0.0, 0.0, phys_width, timebar_height);
+ meter_bar->property_outline_pixels() = 0;
+ }
+ meter_bar->property_outline_what() = (0x1 | 0x8);
+
+ tempo_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ if (Profile->get_sae()) {
+- tempo_bar = new ArdourCanvas::SimpleRect (*tempo_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++ tempo_bar = new ArdourCanvas::SimpleRect (*tempo_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ tempo_bar->property_outline_pixels() = 1;
+ } else {
+- tempo_bar = new ArdourCanvas::SimpleRect (*tempo_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++ tempo_bar = new ArdourCanvas::SimpleRect (*tempo_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ tempo_bar->property_outline_pixels() = 0;
+ }
+ tempo_bar->property_outline_what() = (0x1 | 0x8);
+
+ range_marker_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ if (Profile->get_sae()) {
+- range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++ range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ range_marker_bar->property_outline_pixels() = 1;
+ } else {
+- range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++ range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ range_marker_bar->property_outline_pixels() = 0;
+ }
+ range_marker_bar->property_outline_what() = (0x1 | 0x8);
+
+ transport_marker_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ if (Profile->get_sae()) {
+- transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++ transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ transport_marker_bar->property_outline_pixels() = 1;
+ } else {
+- transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++ transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ transport_marker_bar->property_outline_pixels() = 0;
+ }
+ transport_marker_bar->property_outline_what() = (0x1 | 0x8);
+
+ marker_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ if (Profile->get_sae()) {
+- marker_bar = new ArdourCanvas::SimpleRect (*marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++ marker_bar = new ArdourCanvas::SimpleRect (*marker_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ marker_bar->property_outline_pixels() = 1;
+ } else {
+- marker_bar = new ArdourCanvas::SimpleRect (*marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++ marker_bar = new ArdourCanvas::SimpleRect (*marker_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ marker_bar->property_outline_pixels() = 0;
+ }
+ marker_bar->property_outline_what() = (0x1 | 0x8);
+
+ cd_marker_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ if (Profile->get_sae()) {
+- cd_marker_bar = new ArdourCanvas::SimpleRect (*cd_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++ cd_marker_bar = new ArdourCanvas::SimpleRect (*cd_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ cd_marker_bar->property_outline_pixels() = 1;
+ } else {
+- cd_marker_bar = new ArdourCanvas::SimpleRect (*cd_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++ cd_marker_bar = new ArdourCanvas::SimpleRect (*cd_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ cd_marker_bar->property_outline_pixels() = 0;
+ }
+ cd_marker_bar->property_outline_what() = (0x1 | 0x8);
+@@ -235,7 +230,7 @@
+ cd_marker_group = new ArdourCanvas::Group (*timebar_group, 0.0, 0.0);
+
+ marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0));
+- marker_drag_line_points.push_back(Gnome::Art::Point(0.0, physical_screen_height));
++ marker_drag_line_points.push_back(Gnome::Art::Point(0.0, phys_height));
+
+ marker_drag_line = new ArdourCanvas::Line (*timebar_group);
+ marker_drag_line->property_width_pixels() = 1;
+@@ -258,14 +253,14 @@
+ transport_punchin_line->property_x1() = 0.0;
+ transport_punchin_line->property_y1() = 0.0;
+ transport_punchin_line->property_x2() = 0.0;
+- transport_punchin_line->property_y2() = physical_screen_height;
++ transport_punchin_line->property_y2() = phys_height;
+ transport_punchin_line->hide ();
+
+ transport_punchout_line = new ArdourCanvas::SimpleLine (*_master_group);
+ transport_punchout_line->property_x1() = 0.0;
+ transport_punchout_line->property_y1() = 0.0;
+ transport_punchout_line->property_x2() = 0.0;
+- transport_punchout_line->property_y2() = physical_screen_height;
++ transport_punchout_line->property_y2() = phys_height;
+ transport_punchout_line->hide();
+
+ // used to show zoom mode active zooming
+@@ -382,24 +377,20 @@
+ void
+ Editor::controls_layout_size_request (Requisition* req)
+ {
+- TreeModel::Children rows = route_display_model->children();
+- TreeModel::Children::iterator i;
+ double pos;
+ bool changed = false;
+
+- for (pos = 0, i = rows.begin(); i != rows.end(); ++i) {
+- TimeAxisView *tv = (*i)[route_display_columns.tv];
+- if (tv != 0) {
+- pos += tv->effective_height;
+- }
++ pos = 0;
++ for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
++ pos += (*i)->effective_height;
+ }
+
+- gint height = min ((gint) pos, (gint) (physical_screen_height - 600));
++ gint height = min ((gint) pos, (gint) (physical_screen_height (get_window()) - 600));
+ gint width = max (edit_controls_vbox.get_width(), controls_layout.get_width());
+
+ /* don't get too big. the fudge factors here are just guesses */
+
+- width = min (width, (gint) (physical_screen_width - 300));
++ width = min (width, (gint) (physical_screen_width (get_window()) - 300));
+
+ if ((req->width != width) || (req->height != height)) {
+ changed = true;
+--- a/gtk2_ardour/editor.h
++++ b/gtk2_ardour/editor.h
+@@ -330,10 +330,6 @@
+ void toggle_measure_visibility ();
+ void toggle_logo_visibility ();
+
+- double get_physical_screen_width () const { return physical_screen_width; };
+- double physical_screen_width;
+- double physical_screen_height;
+-
+ /* SMPTE timecode & video sync */
+
+ void smpte_fps_chosen (ARDOUR::SmpteFormat format);
+--- a/gtk2_ardour/editor_mouse.cc
++++ b/gtk2_ardour/editor_mouse.cc
+@@ -3996,8 +3996,6 @@
+ drag_info.x_constrained = !drag_info.x_constrained;
+ }
+
+- cerr << "drag done, copy ? " << drag_info.copy << " x-const ? " << drag_info.x_constrained << endl;
+-
+ if (drag_info.copy) {
+ if (drag_info.x_constrained) {
+ op_string = _("fixed time region copy");
+@@ -4037,8 +4035,6 @@
+ continue;
+ }
+
+- cerr << "drag delta = " << drag_delta << " rpos was " << rv->region()->position() << endl;
+-
+ if (changed_position && !drag_info.x_constrained && (mouse_mode != MouseRange)) {
+ where = rv->region()->position() - drag_delta;
+ } else {
+@@ -4074,8 +4070,6 @@
+ session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
+ }
+
+- cerr << "Adding region @ " << new_region->position() << " at " << where << endl;
+-
+ to_playlist->add_region (new_region, where);
+
+ c.disconnect ();
+@@ -4409,8 +4403,6 @@
+ return;
+ }
+
+- cerr << "got " << new_regions.size() << " regions in selection grab\n";
+-
+ /* XXX fix me one day to use all new regions */
+
+ boost::shared_ptr<Region> region (new_regions.front());
+--- a/gtk2_ardour/editor_selection.cc
++++ b/gtk2_ardour/editor_selection.cc
+@@ -611,8 +611,8 @@
+ */
+
+
+- first_frame = entered_regionview->region()->position();
+- last_frame = entered_regionview->region()->last_frame();
++ first_frame = clicked_regionview->region()->position();
++ last_frame = clicked_regionview->region()->last_frame();
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ if ((*i)->region()->position() < first_frame) {
+@@ -639,9 +639,9 @@
+ the this one and any selected ones.
+ */
+
+- if (!selection->selected (entered_regionview)) {
++ if (!selection->selected (clicked_regionview)) {
+
+- AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&entered_regionview->get_time_axis_view());
++ AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&clicked_regionview->get_time_axis_view());
+
+ if (atv) {
+
+--- a/gtk2_ardour/editor_tempodisplay.cc
++++ b/gtk2_ardour/editor_tempodisplay.cc
+@@ -45,6 +45,7 @@
+ #include "ardour_ui.h"
+ #include "time_axis_view.h"
+ #include "tempo_lines.h"
++#include "utils.h"
+
+ #include "i18n.h"
+
+@@ -196,7 +197,7 @@
+ }
+
+ if (tempo_lines == 0) {
+- tempo_lines = new TempoLines(*track_canvas, time_line_group, physical_screen_height);
++ tempo_lines = new TempoLines(*track_canvas, time_line_group, physical_screen_height (get_window()));
+ }
+
+ tempo_lines->draw(*current_bbt_points, frames_per_unit);
+--- a/gtk2_ardour/engine_dialog.cc
++++ b/gtk2_ardour/engine_dialog.cc
+@@ -3,9 +3,11 @@
+ #include <fstream>
+ #include <map>
+
++#include <boost/scoped_ptr.hpp>
+ #include <glibmm.h>
+ #include <gtkmm/messagedialog.h>
+ #include <pbd/xml++.h>
++#include <pbd/epa.h>
+
+ #ifdef __APPLE__
+ #include <CoreAudio/CoreAudio.h>
+@@ -400,6 +402,8 @@
+ cmd.push_back ("-R");
+ cmd.push_back ("-P");
+ cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
++ } else {
++ cmd.push_back ("-r"); /* override jackd's default --realtime */
+ }
+
+ if (unlock_memory_button.get_active()) {
+@@ -558,6 +562,17 @@
+ bool
+ EngineControl::engine_running ()
+ {
++ EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa ();
++ boost::scoped_ptr<EnvironmentalProtectionAgency> current_epa;
++
++ /* revert all environment settings back to whatever they were when ardour started
++ */
++
++ if (global_epa) {
++ current_epa.reset (new EnvironmentalProtectionAgency(true)); /* will restore settings when we leave scope */
++ global_epa->restore ();
++ }
++
+ jack_status_t status;
+ jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
+
+--- a/gtk2_ardour/export_range_markers_dialog.cc
++++ b/gtk2_ardour/export_range_markers_dialog.cc
+@@ -111,7 +111,6 @@
+ ExportRangeMarkersDialog::get_target_filepath(string path, string filename, string postfix)
+ {
+ string target_filepath = Glib::build_filename (path, filename + postfix);
+- struct stat statbuf;
+
+ for (int counter=1; Glib::file_test (target_filepath, Glib::FILE_TEST_EXISTS); counter++) {
+ // while file exists
+--- a/gtk2_ardour/lv2_plugin_ui.cc
++++ b/gtk2_ardour/lv2_plugin_ui.cc
+@@ -18,11 +18,16 @@
+
+ */
+
++#include <pbd/pthread_utils.h>
++
+ #include <ardour/insert.h>
+ #include <ardour/lv2_plugin.h>
+
++#include <gtkmm2ext/gtk_ui.h>
++
+ #include "ardour_ui.h"
+ #include "lv2_plugin_ui.h"
++#include "gui_thread.h"
+
+ using namespace Gtk;
+ using namespace ARDOUR;
+@@ -35,10 +40,14 @@
+ uint32_t format,
+ const void* buffer)
+ {
+- //cout << "lv2_ui_write" << endl;
+ LV2PluginUI* me = (LV2PluginUI*)controller;
++
++ if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
++ PBD::notify_gui_about_thread_creation (pthread_self(), me->_lv2->name());
++ }
++
+ if (*(float*)buffer != me->_values[port_index]) {
+- //cout << "set_parameter " << port_index << ":" << *(float*)buffer << endl;
++ // cout << "set_parameter " << port_index << ":" << *(float*)buffer << endl;
+ me->_lv2->set_parameter(port_index, *(float*)buffer);
+ }
+ }
+@@ -66,6 +75,8 @@
+ return;
+ }
+
++ ENSURE_GUI_THREAD(bind (mem_fun (*this, &LV2PluginUI::parameter_update), port_index, val));
++
+ const LV2UI_Descriptor* ui_desc = slv2_ui_instance_get_descriptor(_inst);
+ LV2UI_Handle ui_handle = slv2_ui_instance_get_handle(_inst);
+ if (ui_desc->port_event) {
+@@ -120,6 +131,7 @@
+ LV2PluginUI::LV2PluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<LV2Plugin> lv2p)
+ : PlugUIBase (pi)
+ , _lv2(lv2p)
++ , _current_ui_thread (0)
+ , _inst(NULL)
+ , _values(NULL)
+ , _external_ui_ptr(NULL)
+--- a/gtk2_ardour/lv2_plugin_ui.h
++++ b/gtk2_ardour/lv2_plugin_ui.h
+@@ -58,11 +58,11 @@
+ boost::shared_ptr<ARDOUR::LV2Plugin> _lv2;
+ std::vector<int> _output_ports;
+ sigc::connection _screen_update_connection;
+-
+- Gtk::Widget* _gui_widget;
+- SLV2UIInstance _inst;
+- float* _values;
+-
++ pthread_t _current_ui_thread;
++ Gtk::Widget* _gui_widget;
++ SLV2UIInstance _inst;
++ float* _values;
++
+ struct lv2_external_ui_host _external_ui_host;
+ LV2_Feature _external_ui_feature;
+ struct lv2_external_ui* _external_ui_ptr;
+--- a/gtk2_ardour/main.cc
++++ b/gtk2_ardour/main.cc
+@@ -19,6 +19,8 @@
+
+ #include <cstdlib>
+ #include <signal.h>
++#include <cerrno>
++#include <fstream>
+
+ #include <sigc++/bind.h>
+ #include <gtkmm/settings.h>
+@@ -28,6 +30,7 @@
+ #include <pbd/textreceiver.h>
+ #include <pbd/failed_constructor.h>
+ #include <pbd/pthread_utils.h>
++#include <pbd/epa.h>
+
+ #include <jack/jack.h>
+
+@@ -66,17 +69,18 @@
+
+ #include <mach-o/dyld.h>
+ #include <sys/param.h>
+-#include <fstream>
+
+ extern void set_language_preference (); // cocoacarbon.mm
+
+ void
+-fixup_bundle_environment ()
++fixup_bundle_environment (int argc, char* argv[])
+ {
+ if (!getenv ("ARDOUR_BUNDLED")) {
+ return;
+ }
+
++ EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true));
++
+ set_language_preference ();
+
+ char execpath[MAXPATHLEN+1];
+@@ -95,6 +99,15 @@
+ */
+
+ path = dir_path;
++
++ /* JACK is often in /usr/local/bin and since Info.plist refuses to
++ set PATH, we have to force this in order to discover a running
++ instance of JACK ...
++ */
++
++ path += ':';
++ path += "/usr/local/bin";
++
+ if (cstr) {
+ path += ':';
+ path += cstr;
+@@ -102,15 +115,17 @@
+ setenv ("PATH", path.c_str(), 1);
+
+ path = dir_path;
+- path += "/../Resources";
++ path += "/../Resources:";
+ path += dir_path;
+- path += "/../Resources/Surfaces";
++ path += "/../Resources/Surfaces:";
+ path += dir_path;
+- path += "/../Resources/Panners";
++ path += "/../Resources/Panners:";
+
+ setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
+
+- path = dir_path;
++ path = get_user_ardour_path ();
++ path += ':';
++ path += dir_path;
+ path += "/../Resources/icons:";
+ path += dir_path;
+ path += "/../Resources/pixmaps:";
+@@ -163,23 +178,16 @@
+
+ setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
+
+- cstr = getenv ("LV2_PATH");
+- if (cstr) {
+- path = cstr;
+- path += ':';
+- } else {
+- path = "";
+- }
+- path += dir_path;
+- path += "/../Plugins";
+-
+- setenv ("LV2_PATH", path.c_str(), 1);
+-
+ path = dir_path;
+ path += "/../Frameworks/clearlooks";
+
+ setenv ("GTK_PATH", path.c_str(), 1);
+
++ /* unset GTK_RC_FILES so that we only load the RC files that we define
++ */
++
++ unsetenv ("GTK_RC_FILES");
++
+ if (!ARDOUR::translations_are_disabled ()) {
+
+ path = dir_path;
+@@ -249,6 +257,152 @@
+ }
+ }
+
++#else
++
++void
++fixup_bundle_environment (int argc, char* argv[])
++{
++ if (!getenv ("ARDOUR_BUNDLED")) {
++ return;
++ }
++
++ EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
++
++ Glib::ustring exec_path = argv[0];
++ Glib::ustring dir_path = Glib::path_get_dirname (Glib::path_get_dirname (exec_path));
++ Glib::ustring path;
++ const char *cstr = getenv ("PATH");
++
++ /* ensure that we find any bundled executables (e.g. JACK),
++ and find them before any instances of the same name
++ elsewhere in PATH
++ */
++
++ /* note that this function is POSIX/Linux specific, so using / as
++ a dir separator in this context is just fine.
++ */
++
++ path = dir_path;
++ path += "/etc:";
++ path += dir_path;
++ path += "/lib/surfaces:";
++ path += dir_path;
++ path += "/lib/panners:";
++
++ setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
++
++ path = get_user_ardour_path ();
++ path += ':';
++ path += dir_path;
++ path += "/etc/icons:";
++ path += dir_path;
++ path += "/etc/pixmaps:";
++ path += dir_path;
++ path += "/share:";
++ path += dir_path;
++ path += "/etc";
++
++ setenv ("ARDOUR_PATH", path.c_str(), 1);
++ setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
++ setenv ("ARDOUR_DATA_PATH", path.c_str(), 1);
++
++ path = dir_path;
++ path += "/etc";
++ setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
++
++ cstr = getenv ("LADSPA_PATH");
++ if (cstr) {
++ path = cstr;
++ path += ':';
++ } else {
++ path = "";
++ }
++ path += dir_path;
++ path += "/lib/plugins";
++
++ setenv ("LADSPA_PATH", path.c_str(), 1);
++
++ cstr = getenv ("VAMP_PATH");
++ if (cstr) {
++ path = cstr;
++ path += ':';
++ } else {
++ path = "";
++ }
++ path += dir_path;
++ path += "/lib";
++
++ setenv ("VAMP_PATH", path.c_str(), 1);
++
++ cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
++ if (cstr) {
++ path = cstr;
++ path += ':';
++ } else {
++ path = "";
++ }
++ path += dir_path;
++ path += "/lib/surfaces";
++
++ setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
++
++ path = dir_path;
++ path += "/lib/clearlooks";
++
++ setenv ("GTK_PATH", path.c_str(), 1);
++
++ /* unset GTK_RC_FILES so that we only load the RC files that we define
++ */
++
++ unsetenv ("GTK_RC_FILES");
++
++ if (!ARDOUR::translations_are_disabled ()) {
++ path = dir_path;
++ path += "/share/locale";
++
++ localedir = strdup (path.c_str());
++ setenv ("GTK_LOCALEDIR", localedir, 1);
++ }
++
++ /* write a pango.rc file and tell pango to use it. we'd love
++ to put this into the Ardour.app bundle and leave it there,
++ but the user may not have write permission. so ...
++
++ we also have to make sure that the user ardour directory
++ actually exists ...
++ */
++
++ if (g_mkdir_with_parents (ARDOUR::get_user_ardour_path().c_str(), 0755) < 0) {
++ error << string_compose (_("cannot create user ardour folder %1 (%2)"), ARDOUR::get_user_ardour_path(), strerror (errno))
++ << endmsg;
++ } else {
++
++ Glib::ustring mpath;
++
++ path = Glib::build_filename (ARDOUR::get_user_ardour_path(), "pango.rc");
++
++ std::ofstream pangorc (path.c_str());
++ if (!pangorc) {
++ error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
++ } else {
++ mpath = Glib::build_filename (ARDOUR::get_user_ardour_path(), "pango.modules");
++
++ pangorc << "[Pango]\nModuleFiles=";
++ pangorc << mpath << endl;
++ pangorc.close ();
++ }
++
++ setenv ("PANGO_RC_FILE", path.c_str(), 1);
++
++ /* similar for GDK pixbuf loaders, but there's no RC file required
++ to specify where it lives.
++ */
++
++ mpath = Glib::build_filename (ARDOUR::get_user_ardour_path(), "gdk-pixbuf.loaders");
++ setenv ("GDK_PIXBUF_MODULE_FILE", mpath.c_str(), 1);
++ }
++}
++
+ #endif
+
+ static gboolean
+@@ -312,10 +466,8 @@
+ #endif
+ {
+ vector<Glib::ustring> null_file_list;
+-
+-#ifdef __APPLE__
+- fixup_bundle_environment ();
+-#endif
++
++ fixup_bundle_environment (argc, argv);
+
+ Glib::thread_init();
+
+--- a/gtk2_ardour/po/cs.po
++++ b/gtk2_ardour/po/cs.po
+@@ -8,7 +8,7 @@
+ #, fuzzy
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: gtk-ardour 0.347.2\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2008-10-20 19:01+0100\n"
+ "PO-Revision-Date: 2010-02-03 13:57-0500\n"
+--- a/gtk2_ardour/po/de.po
++++ b/gtk2_ardour/po/de.po
+@@ -7,7 +7,7 @@
+ # Robert Schwede <robert-schwede at gmx.de>, 2009.
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: gtk-ardour 0.347.2\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2009-07-05 19:46+0100\n"
+ "PO-Revision-Date: 2009-08-12 10:14+0100\n"
+--- a/gtk2_ardour/po/el.po
++++ b/gtk2_ardour/po/el.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: gtk-ardour 0.347.2\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2005-01-11 13:00+0200\n"
+ "PO-Revision-Date: 2007-04-11 02:27+0200\n"
+--- a/gtk2_ardour/po/es.po
++++ b/gtk2_ardour/po/es.po
+@@ -1,6 +1,6 @@
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: Ardour gtk2 translation\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-01-22 19:05+0100\n"
+ "PO-Revision-Date: \n"
+--- a/gtk2_ardour/po/fr.po
++++ b/gtk2_ardour/po/fr.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: PACKAGE VERSION\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-04-27 16:38+0200\n"
+ "PO-Revision-Date: 2010-04-27 16:39+0100\n"
+--- a/gtk2_ardour/po/it.po
++++ b/gtk2_ardour/po/it.po
+@@ -1,6 +1,6 @@
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: 2.8.1\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "POT-Creation-Date: \n"
+ "PO-Revision-Date: \n"
+ "Last-Translator: Emanuele Costantini <sound at ecciproduzioni.com>\n"
+--- a/gtk2_ardour/po/nn.po
++++ b/gtk2_ardour/po/nn.po
+@@ -5,12 +5,12 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: PACKAGE VERSION\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2009-12-24 15:13+0100\n"
+ "PO-Revision-Date: 2010-01-17 21:11+0100\n"
+ "Last-Translator: Eivind Ødegård <gingermig at yahoo.no>\n"
+-"Language-Team: LANGUAGE <LL at li.org>\n"
++"Language-Team: \n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+--- a/gtk2_ardour/po/pt.po
++++ b/gtk2_ardour/po/pt.po
+@@ -8,7 +8,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: ardour 0.688.4\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2006-06-27 13:00-0400\n"
+ "PO-Revision-Date: 2005-08-15 21:50-0000\n"
+--- a/gtk2_ardour/po/pt_PT.po
++++ b/gtk2_ardour/po/pt_PT.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: gtk2_ardour rev.1702\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2007-04-08 13:00+0100\n"
+ "PO-Revision-Date: 2007-04-15 19:00+0100\n"
+--- a/gtk2_ardour/po/ru.po
++++ b/gtk2_ardour/po/ru.po
+@@ -6,7 +6,7 @@
+ # Alexandre Prokoudine <alexandre.prokoudine at gmail.com>, 2006, 2007, 2009
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: ru_RU\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-01-20 01:34+0300\n"
+ "PO-Revision-Date: 2010-01-20 04:25+0300\n"
+--- a/gtk2_ardour/po/sv.po
++++ b/gtk2_ardour/po/sv.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: ardour-gtk 1.0.2\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2006-06-12 22:09+0200\n"
+ "PO-Revision-Date: 2006-06-26 23:57+GMT+1\n"
+--- a/gtk2_ardour/public_editor.h
++++ b/gtk2_ardour/public_editor.h
+@@ -152,7 +152,6 @@
+ virtual void toggle_follow_playhead () = 0;
+ virtual bool follow_playhead() const = 0;
+ virtual bool dragging_playhead() const = 0;
+- virtual double get_physical_screen_width() const = 0;
+ virtual void ensure_float (Gtk::Window&) = 0;
+ virtual void show_window () = 0;
+ virtual TrackViewList* get_valid_views (TimeAxisView*, ARDOUR::RouteGroup* grp = 0) = 0;
+--- a/gtk2_ardour/SConscript
++++ b/gtk2_ardour/SConscript
+@@ -291,6 +291,7 @@
+ extra_sources += lv2_files
+ gtkardour.Append (CCFLAGS="-DHAVE_LV2")
+ gtkardour.Merge ([libraries['slv2']])
++ gtkardour.Merge ([libraries['rasqal']])
+
+
+ if gtkardour['GTKOSX']:
+--- a/gtk2_ardour/sfdb_ui.cc
++++ b/gtk2_ardour/sfdb_ui.cc
+@@ -979,6 +979,7 @@
+ }
+ if (same_size) {
+ channel_strings.push_back (_("all files in one track"));
++ channel_strings.push_back (_("merge files"));
+ }
+
+ }
+--- a/gtk2_ardour/streamview.cc
++++ b/gtk2_ardour/streamview.cc
+@@ -61,7 +61,7 @@
+ canvas_rect = new ArdourCanvas::SimpleRect (*_background_group);
+ canvas_rect->property_x1() = 0.0;
+ canvas_rect->property_y1() = 0.0;
+- canvas_rect->property_x2() = _trackview.editor.get_physical_screen_width();
++ canvas_rect->property_x2() = physical_screen_width (_trackview.editor.get_window());
+ canvas_rect->property_y2() = (double) tv.current_height();
+
+ canvas_rect->property_outline_what() = (guint32) (0x1|0x2|0x8); // outline ends and bottom
+--- a/gtk2_ardour/utils.cc
++++ b/gtk2_ardour/utils.cc
+@@ -861,6 +861,7 @@
+ return alpha ? ((guint (src) << 8) - src) / alpha : 0;
+ }
+
++
+ void
+ convert_bgra_to_rgba (guint8 const* src,
+ guint8* dst,
+@@ -870,20 +871,42 @@
+ guint8 const* src_pixel = src;
+ guint8* dst_pixel = dst;
+
+- for (int y = 0; y < height; y++)
+- for (int x = 0; x < width; x++)
+- {
+- dst_pixel[0] = convert_color_channel (src_pixel[2],
+- src_pixel[3]);
+- dst_pixel[1] = convert_color_channel (src_pixel[1],
+- src_pixel[3]);
+- dst_pixel[2] = convert_color_channel (src_pixel[0],
+- src_pixel[3]);
+- dst_pixel[3] = src_pixel[3];
+-
+- dst_pixel += 4;
+- src_pixel += 4;
+- }
++ for (int y = 0; y < height; y++) {
++ for (int x = 0; x < width; x++) {
++#if G_BYTE_ORDER == G_LITTLE_ENDIAN
++ /* Cairo [ B G R A ] is actually [ B G R A ] in memory SOURCE
++ 0 1 2 3
++ Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
++ */
++ dst_pixel[0] = convert_color_channel (src_pixel[2],
++ src_pixel[3]); // R [0] <= [ 2 ]
++ dst_pixel[1] = convert_color_channel (src_pixel[1],
++ src_pixel[3]); // G [1] <= [ 1 ]
++ dst_pixel[2] = convert_color_channel (src_pixel[0],
++ src_pixel[3]); // B [2] <= [ 0 ]
++ dst_pixel[3] = src_pixel[3]; // alpha
++
++#elif G_BYTE_ORDER == G_BIG_ENDIAN
++ /* Cairo [ B G R A ] is actually [ A R G B ] in memory SOURCE
++ 0 1 2 3
++ Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
++ */
++ dst_pixel[0] = convert_color_channel (src_pixel[1],
++ src_pixel[0]); // R [0] <= [ 1 ]
++ dst_pixel[1] = convert_color_channel (src_pixel[2],
++ src_pixel[0]); // G [1] <= [ 2 ]
++ dst_pixel[2] = convert_color_channel (src_pixel[3],
++ src_pixel[0]); // B [2] <= [ 3 ]
++ dst_pixel[3] = src_pixel[0]; // alpha
++
++#else
++#error ardour does not currently support PDP-endianess
++#endif
++
++ dst_pixel += 4;
++ src_pixel += 4;
++ }
++ }
+ }
+
+ Glib::RefPtr<Gdk::Pixbuf>
+@@ -917,3 +940,33 @@
+
+ return buf;
+ }
++
++int
++physical_screen_height (Glib::RefPtr<Gdk::Window> win)
++{
++ GdkScreen* scr = gdk_screen_get_default();
++
++ if (win) {
++ GdkRectangle r;
++ gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
++ gdk_screen_get_monitor_geometry (scr, monitor, &r);
++ return r.height;
++ } else {
++ return gdk_screen_get_height (scr);
++ }
++}
++
++int
++physical_screen_width (Glib::RefPtr<Gdk::Window> win)
++{
++ GdkScreen* scr = gdk_screen_get_default();
++
++ if (win) {
++ GdkRectangle r;
++ gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
++ gdk_screen_get_monitor_geometry (scr, monitor, &r);
++ return r.width;
++ } else {
++ return gdk_screen_get_width (scr);
++ }
++}
+--- a/gtk2_ardour/utils.h
++++ b/gtk2_ardour/utils.h
+@@ -100,4 +100,7 @@
+ int clip_width,
+ int clip_height);
+
++int physical_screen_height (Glib::RefPtr<Gdk::Window>);
++int physical_screen_width (Glib::RefPtr<Gdk::Window>);
++
+ #endif /* __ardour_gtk_utils_h__ */
+--- a/libs/ardour/ardour/automation_event.h
++++ b/libs/ardour/ardour/automation_event.h
+@@ -83,6 +83,7 @@
+
+ void freeze();
+ void thaw ();
++ int8_t frozen() const { return _frozen; }
+
+ AutomationEventList::size_type size() const { return events.size(); }
+ bool empty() const { return events.empty(); }
+--- a/libs/ardour/ardour/configuration_variable.h
++++ b/libs/ardour/ardour/configuration_variable.h
+@@ -24,6 +24,7 @@
+ #include <ostream>
+
+ #include <pbd/xml++.h>
++#include <pbd/enumwriter.h>
+
+ #include "ardour/utils.h"
+
+@@ -113,9 +114,9 @@
+ if ((prop = child->property ("name")) != 0) {
+ if (prop->value() == _name) {
+ if ((prop = child->property ("value")) != 0) {
+- std::stringstream ss;
+- ss << prop->value();
+- ss >> value;
++ std::stringstream ss;
++ ss << enum_validate (value, prop->value());
++ ss >> value;
+ _owner = (ConfigVariableBase::Owner)(_owner |owner);
+ return true;
+ }
+@@ -138,12 +139,12 @@
+ for (oiter = olist.begin(); oiter != olist.end(); ++oiter) {
+
+ option = *oiter;
+-
++
+ if (option->name() == _name) {
+ if ((opt_prop = option->property ("val")) != 0) {
+- std::stringstream ss;
+- ss << opt_prop->value();
+- ss >> value;
++ std::stringstream ss;
++ ss << enum_validate (value, opt_prop->value());
++ ss >> value;
+ _owner = (ConfigVariableBase::Owner)(_owner |owner);
+ return true;
+ }
+--- a/libs/ardour/audioengine.cc
++++ b/libs/ardour/audioengine.cc
+@@ -22,9 +22,12 @@
+ #include <vector>
+ #include <sstream>
+
++#include <boost/scoped_ptr.hpp>
++
+ #include <glibmm/timer.h>
+ #include <pbd/pthread_utils.h>
+ #include <pbd/stacktrace.h>
++#include <pbd/epa.h>
+
+ #include <ardour/audioengine.h>
+ #include <ardour/buffer.h>
+@@ -332,7 +335,10 @@
+
+ IO::CycleStart (nframes);
+
+- if (_freewheeling) {
++ /* test if we are freewheeling and there are freewheel signals connected.
++ ardour should act normally even when freewheeling unless /it/ is exporting */
++
++ if (_freewheeling && !Freewheel.empty()) {
+ if (Freewheel (nframes)) {
+ jack_set_freewheel (_priv_jack, false);
+ }
+@@ -667,7 +673,7 @@
+ AudioEngine::connect (const string& source, const string& destination)
+ {
+ GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
+-
++
+ string s = make_port_name_non_relative (source);
+ string d = make_port_name_non_relative (destination);
+
+@@ -1116,10 +1122,20 @@
+ int
+ AudioEngine::connect_to_jack (string client_name)
+ {
++ EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa ();
++ boost::scoped_ptr<EnvironmentalProtectionAgency> current_epa;
+ jack_options_t options = JackNullOption;
+ jack_status_t status;
+ const char *server_name = NULL;
+
++ /* revert all environment settings back to whatever they were when ardour started
++ */
++
++ if (global_epa) {
++ current_epa.reset (new EnvironmentalProtectionAgency(true)); /* will restore settings when we leave scope */
++ global_epa->restore ();
++ }
++
+ jack_client_name = client_name; /* might be reset below */
+ _jack = jack_client_open (jack_client_name.c_str(), options, &status, server_name);
+
+@@ -1276,7 +1292,7 @@
+ error << string_compose (_("Disconnected from JACK while reconnecting. You should quit %1 now."), PROGRAM_NAME) << endmsg;
+ return -1;
+ }
+-
++
+ if ((err = jack_connect (_priv_jack, (*i).first.c_str(), (*i).second.c_str())) != 0) {
+ if (err != EEXIST) {
+ error << string_compose (_("could not reconnect %1 and %2 (err = %3)"),
+--- a/libs/ardour/audioregion.cc
++++ b/libs/ardour/audioregion.cc
+@@ -735,7 +735,7 @@
+ child->add_child_nocopy (_fade_in.get_state ());
+ }
+
+- child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes"));
++ child->add_property (X_("active"), (_flags & FadeIn) ? X_("yes") : X_("no"));
+
+ child = node.add_child (X_("FadeOut"));
+
+@@ -745,7 +745,7 @@
+ child->add_child_nocopy (_fade_out.get_state ());
+ }
+
+- child->add_property (X_("active"), _fade_out_disabled ? X_("no") : X_("yes"));
++ child->add_property (X_("active"), (_flags & FadeOut) ? X_("yes") : X_("no"));
+ }
+
+ child = node.add_child ("Envelope");
+--- a/libs/ardour/audio_unit.cc
++++ b/libs/ardour/audio_unit.cc
+@@ -446,17 +446,26 @@
+ throw failed_constructor ();
+ }
+
+- AURenderCallbackStruct renderCallbackInfo;
+-
+- renderCallbackInfo.inputProc = _render_callback;
+- renderCallbackInfo.inputProcRefCon = this;
++ TRACE_API ("count global elements\n");
++ unit->GetElementCount (kAudioUnitScope_Global, global_elements);
++ TRACE_API ("count input elements\n");
++ unit->GetElementCount (kAudioUnitScope_Input, input_elements);
++ TRACE_API ("count output elements\n");
++ unit->GetElementCount (kAudioUnitScope_Output, output_elements);
+
+- TRACE_API ("set render callback in input scope\n");
+- if ((err = unit->SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
+- 0, (void*) &renderCallbackInfo, sizeof(renderCallbackInfo))) != 0) {
+- cerr << "cannot install render callback (err = " << err << ')' << endl;
+- throw failed_constructor();
+- }
++ if (input_elements > 0) {
++ AURenderCallbackStruct renderCallbackInfo;
++
++ renderCallbackInfo.inputProc = _render_callback;
++ renderCallbackInfo.inputProcRefCon = this;
++
++ TRACE_API ("set render callback in input scope\n");
++ if ((err = unit->SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
++ 0, (void*) &renderCallbackInfo, sizeof(renderCallbackInfo))) != 0) {
++ cerr << "cannot install render callback (err = " << err << ')' << endl;
++ throw failed_constructor();
++ }
++ }
+
+ /* tell the plugin about tempo/meter/transport callbacks in case it wants them */
+
+@@ -475,13 +484,6 @@
+ &info,
+ sizeof (HostCallbackInfo));
+
+- TRACE_API ("count global elements\n");
+- unit->GetElementCount (kAudioUnitScope_Global, global_elements);
+- TRACE_API ("count input elements\n");
+- unit->GetElementCount (kAudioUnitScope_Input, input_elements);
+- TRACE_API ("count output elements\n");
+- unit->GetElementCount (kAudioUnitScope_Output, output_elements);
+-
+ /* these keep track of *configured* channel set up,
+ not potential set ups.
+ */
+--- a/libs/ardour/crossfade.cc
++++ b/libs/ardour/crossfade.cc
+@@ -711,10 +711,13 @@
+ nframes_t val;
+
+ if ((prop = node.property ("position")) != 0) {
+- sscanf (prop->value().c_str(), "%" PRIu32, &val);
+- if (val != _position) {
+- _position = val;
+- what_changed = Change (what_changed | PositionChanged);
++ if (sscanf (prop->value().c_str(), "%" PRIu32, &val) == 1) {
++ if (val != _position) {
++ _position = val;
++ what_changed = Change (what_changed | PositionChanged);
++ }
++ } else {
++ warning << _("can't read value from crossfade position property") << endmsg;
+ }
+ } else {
+ warning << _("old-style crossfade information - no position information") << endmsg;
+@@ -751,12 +754,14 @@
+
+ if ((prop = node.property ("length")) != 0) {
+
+- sscanf (prop->value().c_str(), "%" PRIu32, &val);
+- if (val != _length) {
+- _length = atol (prop->value().c_str());
+- what_changed = Change (what_changed | LengthChanged);
++ if (sscanf (prop->value().c_str(), "%" PRIu32, &val) == 1) {
++ if (val != _length) {
++ _length = atol (prop->value().c_str());
++ what_changed = Change (what_changed | LengthChanged);
++ }
++ } else {
++ warning << _("can't read value from crossfade length property") << endmsg;
+ }
+-
+ } else {
+
+ /* XXX this branch is legacy code from before
+@@ -798,6 +803,11 @@
+ }
+ }
+
++ if (_fade_in.size() < 2) {
++ cerr << "Fade in data missing any points! Crossfade will be lost!\n";
++ return -1;
++ }
++
+ _fade_in.front()->value=0.0;
+ _fade_in.back()->value=1.0;
+
+@@ -826,6 +836,11 @@
+ }
+ }
+
++ if (_fade_out.size() < 2) {
++ cerr << "Fade out data missing any points! Crossfade will be lost!\n";
++ return -1;
++ }
++
+ _fade_out.front()->value=1.0;
+ _fade_out.back()->value=0.0;
+
+--- a/libs/ardour/curve.cc
++++ b/libs/ardour/curve.cc
+@@ -312,7 +312,7 @@
+ return;
+ }
+
+- if (npoints == 1 ) {
++ if (npoints == 1) {
+
+ for (i = 0; i < veclen; ++i) {
+ vec[i] = events.front()->value;
+@@ -355,17 +355,18 @@
+
+ rx = lx;
+
++ /* note: if there are veclen elements in the output,
++ there are only veclen-1 steps between them.
++ */
++
+ if (veclen > 1) {
+-
+- /* note: if there are veclen elements in the output,
+- there are only veclen-1 steps between them.
+- */
+-
+ dx = (hx - lx) / (veclen-1);
+-
+- for (i = 0; i < veclen; ++i, rx += dx) {
+- vec[i] = multipoint_eval (rx);
+- }
++ } else {
++ dx = 0;
++ }
++
++ for (i = 0; i < veclen; ++i, rx += dx) {
++ vec[i] = multipoint_eval (rx);
+ }
+ }
+
+--- a/libs/ardour/enums.cc
++++ b/libs/ardour/enums.cc
+@@ -147,6 +147,7 @@
+
+ REGISTER_ENUM (Slide);
+ REGISTER_ENUM (Splice);
++ REGISTER_ENUM (Lock);
+ REGISTER (_EditMode);
+
+ REGISTER_ENUM (Start);
+--- a/libs/ardour/po/el.po
++++ b/libs/ardour/po/el.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: libardour 0.664.0\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2003-06-29 21:03+0200\n"
+ "PO-Revision-Date: 2007-04-16 00:38+0200\n"
+--- a/libs/ardour/po/es.po
++++ b/libs/ardour/po/es.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: Ardour\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-01-17 23:34+0100\n"
+ "PO-Revision-Date: \n"
+--- a/libs/ardour/po/fr.po
++++ b/libs/ardour/po/fr.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: PACKAGE VERSION\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-04-27 16:38+0200\n"
+ "PO-Revision-Date: 2010-04-27 16:39+0100\n"
+--- a/libs/ardour/po/it.po
++++ b/libs/ardour/po/it.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: libardour 0.664.0\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2006-06-29 21:03-0400\n"
+ "PO-Revision-Date: 2003-05-21 12:50+0500\n"
+--- a/libs/ardour/po/nn.po
++++ b/libs/ardour/po/nn.po
+@@ -6,7 +6,7 @@
+ # Eivind Ødegård <gingermig at yahoo.no>, 2009.
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: nn_NO\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2009-12-24 15:13+0100\n"
+ "PO-Revision-Date: 2010-01-09 23:28+0100\n"
+--- a/libs/ardour/po/pl.po
++++ b/libs/ardour/po/pl.po
+@@ -5,7 +5,7 @@
+ # Piotr Zaryk <pzaryk at gmail.com>, 2008.
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: libardour2\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: Piotr Zaryk <pzaryk at gmail.com>\n"
+ "POT-Creation-Date: 2008-04-03 16:16+0200\n"
+ "PO-Revision-Date: 2008-04-10 10:51+0100\n"
+--- a/libs/ardour/po/ru.po
++++ b/libs/ardour/po/ru.po
+@@ -6,7 +6,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: libardour 0.716.1\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2009-10-05 17:23+0400\n"
+ "PO-Revision-Date: 2009-10-06 02:59+0300\n"
+--- a/libs/ardour/po/sv.po
++++ b/libs/ardour/po/sv.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: ardour\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2006-10-03 00:39+0200\n"
+ "PO-Revision-Date: 2006-10-03 01:09+GMT+1\n"
+--- a/libs/ardour/SConscript
++++ b/libs/ardour/SConscript
+@@ -320,6 +320,7 @@
+
+ if ardour['LV2']:
+ ardour.Merge ([ libraries['slv2'] ])
++ ardour.Merge ([ libraries['rasqal'] ])
+
+ if ardour['LIBLO']:
+ ardour.Merge ([ libraries['lo'] ])
+--- a/libs/ardour/session.cc
++++ b/libs/ardour/session.cc
+@@ -2631,7 +2631,7 @@
+
+ nframes_t max = get_maximum_extent ();
+
+- if (max > end_location->end()) {
++ if ( (max > end_location->end() ) && _end_location_is_free ) {
+ end_location->set_end (max);
+ set_dirty();
+ DurationChanged(); /* EMIT SIGNAL */
+--- a/libs/ardour/session_transport.cc
++++ b/libs/ardour/session_transport.cc
+@@ -941,7 +941,6 @@
+ for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
+ if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
+ todo = PostTransportWork (todo | PostTransportSpeed);
+- break;
+ }
+ }
+
+--- a/libs/ardour/tempo.cc
++++ b/libs/ardour/tempo.cc
+@@ -299,7 +299,21 @@
+ void
+ TempoMap::move_tempo (TempoSection& tempo, const BBT_Time& when)
+ {
+- if (move_metric_section (tempo, when) == 0) {
++ /* a new tempo always starts a new bar on the first beat */
++ BBT_Time when_rounded = when;
++ int force_state_changed = 0;
++
++ if (when_rounded.beats != 1) {
++ when_rounded.beats = 1;
++ when_rounded.bars++;
++ force_state_changed = 1;
++ }
++
++ /* new tempo *always* start on a beat. */
++
++ when_rounded.ticks = 0;
++
++ if ((move_metric_section (tempo, when_rounded) == 0) || force_state_changed) {
+ StateChanged (Change (0));
+ }
+ }
+@@ -307,7 +321,21 @@
+ void
+ TempoMap::move_meter (MeterSection& meter, const BBT_Time& when)
+ {
+- if (move_metric_section (meter, when) == 0) {
++ /* a new meter always starts a new bar on the first beat */
++ BBT_Time when_rounded = when;
++ int force_state_changed = 0;
++
++ if (when_rounded.beats != 1) {
++ when_rounded.beats = 1;
++ when_rounded.bars++;
++ force_state_changed = 1;
++ }
++
++ /* new meters *always* start on a beat. */
++
++ when_rounded.ticks = 0;
++
++ if ((move_metric_section (meter, when_rounded) == 0) || force_state_changed) {
+ StateChanged (Change (0));
+ }
+ }
+--- a/libs/gtkmm2ext/barcontroller.cc
++++ b/libs/gtkmm2ext/barcontroller.cc
+@@ -146,7 +146,6 @@
+
+ stringstream stream;
+ string str;
+- size_t found;
+
+ char buf[128];
+
+--- a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
++++ b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
+@@ -51,6 +51,7 @@
+
+ class TextViewer;
+
++extern BaseUI::RequestType NullRequest;
+ extern BaseUI::RequestType ErrorMessage;
+ extern BaseUI::RequestType Quit;
+ extern BaseUI::RequestType CallSlot;
+@@ -77,6 +78,10 @@
+ void *arg;
+ const char *msg2;
+ sigc::slot<void> slot;
++
++ UIRequest () {
++ type = NullRequest;
++ }
+
+ ~UIRequest () {
+ if (type == ErrorMessage && msg) {
+--- a/libs/gtkmm2ext/gtk_ui.cc
++++ b/libs/gtkmm2ext/gtk_ui.cc
+@@ -52,6 +52,7 @@
+ pthread_t UI::gui_thread;
+ UI *UI::theGtkUI = 0;
+
++BaseUI::RequestType Gtkmm2ext::NullRequest = BaseUI::new_request_type();
+ BaseUI::RequestType Gtkmm2ext::ErrorMessage = BaseUI::new_request_type();
+ BaseUI::RequestType Gtkmm2ext::Quit = BaseUI::new_request_type();
+ BaseUI::RequestType Gtkmm2ext::TouchDisplay = BaseUI::new_request_type();
+--- a/libs/pbd/enumwriter.cc
++++ b/libs/pbd/enumwriter.cc
+@@ -174,6 +174,98 @@
+ return string();
+ }
+
++string
++EnumWriter::validate_string (EnumRegistration& er, const string& str)
++{
++ int val;
++
++ if (er.values.empty()) {
++ return str;
++ }
++
++ if (er.bitwise) {
++ /* Legal values consist of OR-ed masks of zero or more values defined an enum.
++ Since we only ever check the legal bits, any value is acceptable,
++ including zero.
++ */
++ return str;
++ }
++
++ val = atoi (str.c_str());
++
++ /* not bitwise: Legal values consist of discrete values defined by an enum */
++
++ for (vector<int>::iterator i = er.values.begin(); i != er.values.end(); ++i) {
++ if (*i == val) {
++ return str; /* string is a legal representation of a enumerated single value */
++ }
++ }
++
++ string enum_name = _("unknown enumeration");
++
++ for (Registry::iterator x = registry.begin(); x != registry.end(); ++x) {
++ if (&er == &(*x).second) {
++ enum_name = (*x).first;
++ }
++ }
++
++ warning << string_compose (_("Illegal value loaded for %1 (%2) - %3 used instead"),
++ enum_name, val, er.names.front())
++ << endmsg;
++
++ stringstream ss;
++ ss << er.values.front();
++
++ return ss.str();
++}
++
++string
++EnumWriter::typed_validate (const string& type, const string& value_str)
++{
++ for (Registry::iterator x = registry.begin(); x != registry.end(); ++x) {
++ if (x->first == type) {
++ return validate_string (x->second, value_str);
++ }
++ }
++
++ /* not a known enum */
++
++ return value_str;
++}
++
++int
++EnumWriter::validate (EnumRegistration& er, int val)
++{
++ if (er.values.empty()) {
++ return val;
++ }
++
++ if (er.bitwise) {
++ return val;
++ }
++
++ vector<int>::iterator i;
++ string enum_name = _("unknown enumeration");
++
++ for (Registry::iterator x = registry.begin(); x != registry.end(); ++x) {
++ if (&er == &(*x).second) {
++ enum_name = (*x).first;
++ }
++ }
++
++
++ for (i = er.values.begin(); i != er.values.end(); ++i) {
++ if (*i == val) {
++ return val;
++ }
++ }
++
++ warning << string_compose (_("Illegal value loaded for %1 (%2) - %3 used instead"),
++ enum_name, val, er.names.front())
++ << endmsg;
++ return er.values.front();
++}
++
+ int
+ EnumWriter::read_bits (EnumRegistration& er, string str)
+ {
+@@ -186,14 +278,16 @@
+ /* catch old-style hex numerics */
+
+ if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
+- return strtol (str.c_str(), (char **) 0, 16);
++ int val = strtol (str.c_str(), (char **) 0, 16);
++ return validate (er, val);
+ }
+
+ /* catch old style dec numerics */
+
+ if (strspn (str.c_str(), "0123456789") == str.length()) {
+- return strtol (str.c_str(), (char **) 0, 10);
+- }
++ int val = strtol (str.c_str(), (char **) 0, 10);
++ return validate (er, val);
++ }
+
+ do {
+
+@@ -231,14 +325,16 @@
+ /* catch old-style hex numerics */
+
+ if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
+- return strtol (str.c_str(), (char **) 0, 16);
++ int val = strtol (str.c_str(), (char **) 0, 16);
++ return validate (er, val);
+ }
+
+ /* catch old style dec numerics */
+
+ if (strspn (str.c_str(), "0123456789") == str.length()) {
+- return strtol (str.c_str(), (char **) 0, 10);
+- }
++ int val = strtol (str.c_str(), (char **) 0, 10);
++ return validate (er, val);
++ }
+
+ for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
+ if (str == (*s) || nocase_cmp (str, *s) == 0) {
+--- /dev/null
++++ b/libs/pbd/epa.cc
+@@ -0,0 +1,130 @@
++/*
++ Copyright (C) 2010 Paul Davis
++
++ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++*/
++
++#include <cstdlib>
++#include <iostream>
++
++#include "pbd/epa.h"
++#include "pbd/strsplit.h"
++
++#ifdef __APPLE__
++#include <crt_externs.h>
++#define environ (*_NSGetEnviron())
++#else
++extern char** environ;
++#endif
++
++using namespace PBD;
++using namespace std;
++
++EnvironmentalProtectionAgency* EnvironmentalProtectionAgency::_global_epa = 0;
++
++EnvironmentalProtectionAgency::EnvironmentalProtectionAgency (bool arm, const std::string& envname)
++ : _armed (arm)
++ , _envname (envname)
++{
++ if (_armed) {
++ save ();
++ }
++}
++
++EnvironmentalProtectionAgency::~EnvironmentalProtectionAgency()
++{
++ if (_armed) {
++ restore ();
++ }
++}
++
++void
++EnvironmentalProtectionAgency::arm ()
++{
++ _armed = true;
++}
++
++void
++EnvironmentalProtectionAgency::save ()
++{
++ /* do this to avoid lots of calls to _NSGetEnviron() on OS X */
++
++ char** the_environ = environ;
++
++ e.clear ();
++
++ if (!_envname.empty()) {
++
++ /* fetch environment from named environment variable, rather than "environ"
++ */
++
++ const char* estr = getenv (_envname.c_str());
++
++ if (!estr) {
++ return;
++ }
++
++ /* parse line by line, and save into "e"
++ */
++
++ vector<string> lines;
++ split (estr, lines, '\n');
++
++ for (vector<string>::iterator i = lines.begin(); i != lines.end(); ++i) {
++
++ string estring = *i;
++ string::size_type equal = estring.find_first_of ('=');
++
++ if (equal == string::npos) {
++ /* say what? an environ value without = ? */
++ continue;
++ }
++
++ string before = estring.substr (0, equal);
++ string after = estring.substr (equal+1);
++
++ e.insert (pair<string,string>(before,after));
++ }
++
++ } else {
++
++ /* fetch environment from "environ"
++ */
++
++ for (size_t i = 0; the_environ[i]; ++i) {
++
++ string estring = the_environ[i];
++ string::size_type equal = estring.find_first_of ('=');
++
++ if (equal == string::npos) {
++ /* say what? an environ value without = ? */
++ continue;
++ }
++
++ string before = estring.substr (0, equal);
++ string after = estring.substr (equal+1);
++
++ e.insert (pair<string,string>(before,after));
++ }
++ }
++}
++void
++EnvironmentalProtectionAgency::restore () const
++{
++ for (map<string,string>::const_iterator i = e.begin(); i != e.end(); ++i) {
++ setenv (i->first.c_str(), i->second.c_str(), 1);
++ }
++}
+--- a/libs/pbd/pbd/abstract_ui.cc
++++ b/libs/pbd/pbd/abstract_ui.cc
+@@ -1,4 +1,5 @@
+ #include <unistd.h>
++#include <cstdlib>
+
+ #include <pbd/abstract_ui.h>
+ #include <pbd/pthread_utils.h>
+@@ -8,11 +9,22 @@
+
+ using namespace std;
+
++template<typename RequestBuffer> void
++cleanup_request_buffer (void* ptr)
++{
++ RequestBuffer* rb = (RequestBuffer*) ptr;
++
++ {
++ Glib::Mutex::Lock lm (rb->ui.request_buffer_map_lock);
++ rb->dead = true;
++ }
++}
++
+ template <typename RequestObject>
+ AbstractUI<RequestObject>::AbstractUI (string name, bool with_signal_pipes)
+ : BaseUI (name, with_signal_pipes)
+ {
+- if (pthread_key_create (&thread_request_buffer_key, 0)) {
++ if (pthread_key_create (&thread_request_buffer_key, cleanup_request_buffer<RequestBuffer>)) {
+ cerr << _("cannot create thread request buffer key") << endl;
+ throw failed_constructor();
+ }
+@@ -30,10 +42,24 @@
+ template <typename RequestObject> void
+ AbstractUI<RequestObject>::register_thread_with_request_count (pthread_t thread_id, string thread_name, uint32_t num_requests)
+ {
+- RequestBuffer* b = new RequestBuffer (num_requests);
++ RequestBuffer* rbuf = static_cast<RequestBuffer*>(pthread_getspecific (thread_request_buffer_key));
+
++ /* we require that the thread being registered is the caller */
++
++ if (thread_id != pthread_self()) {
++ cerr << "thread attempts to register some other thread with the UI named " << name() << endl;
++ abort ();
++ }
++
++ if (rbuf) {
++ /* this thread is already registered with this AbstractUI */
++ return;
++ }
++
++ RequestBuffer* b = new RequestBuffer (num_requests, *this);
++
+ {
+- Glib::Mutex::Lock lm (request_buffer_map_lock);
++ Glib::Mutex::Lock lm (request_buffer_map_lock);
+ request_buffers[thread_id] = b;
+ }
+
+@@ -93,33 +119,42 @@
+
+ request_buffer_map_lock.lock ();
+
+- for (i = request_buffers.begin(); i != request_buffers.end(); ++i) {
++ for (i = request_buffers.begin(); i != request_buffers.end(); ) {
+
+ RequestBufferVector vec;
+
+- while (true) {
+-
+- /* we must process requests 1 by 1 because
+- the request may run a recursive main
+- event loop that will itself call
+- handle_ui_requests. when we return
+- from the request handler, we cannot
+- expect that the state of queued requests
+- is even remotely consistent with
+- the condition before we called it.
+- */
+-
+- i->second->get_read_vector (&vec);
+-
+- if (vec.len[0] == 0) {
+- break;
+- } else {
+- request_buffer_map_lock.unlock ();
+- do_request (vec.buf[0]);
+- request_buffer_map_lock.lock ();
+- i->second->increment_read_ptr (1);
+- }
+- }
++ if ((*i).second->dead) {
++ delete (*i).second;
++ RequestBufferMapIterator tmp = i;
++ ++tmp;
++ request_buffers.erase (i);
++ i = tmp;
++ } else {
++ while (true) {
++
++ /* we must process requests 1 by 1 because
++ the request may run a recursive main
++ event loop that will itself call
++ handle_ui_requests. when we return
++ from the request handler, we cannot
++ expect that the state of queued requests
++ is even remotely consistent with
++ the condition before we called it.
++ */
++
++ i->second->get_read_vector (&vec);
++
++ if (vec.len[0] == 0) {
++ break;
++ } else {
++ request_buffer_map_lock.unlock ();
++ do_request (vec.buf[0]);
++ request_buffer_map_lock.lock ();
++ i->second->increment_read_ptr (1);
++ }
++ }
++ ++i;
++ }
+ }
+
+ request_buffer_map_lock.unlock ();
+--- a/libs/pbd/pbd/abstract_ui.h
++++ b/libs/pbd/pbd/abstract_ui.h
+@@ -58,12 +58,21 @@
+ void register_thread_with_request_count (pthread_t, std::string, uint32_t num_requests);
+ void unregister_thread (pthread_t);
+
++ Glib::Mutex request_buffer_map_lock;
++
+ protected:
+- typedef RingBufferNPT<RequestObject> RequestBuffer;
++ struct RequestBuffer : public RingBufferNPT<RequestObject> {
++ bool dead;
++ AbstractUI<RequestObject>& ui;
++ RequestBuffer (uint32_t size, AbstractUI<RequestObject>& uir)
++ : RingBufferNPT<RequestObject> (size)
++ , dead (false)
++ , ui (uir) {}
++ };
++
+ typedef typename RequestBuffer::rw_vector RequestBufferVector;
+ typedef typename std::map<pthread_t,RequestBuffer*>::iterator RequestBufferMapIterator;
+
+- Glib::Mutex request_buffer_map_lock;
+ typedef std::map<pthread_t,RequestBuffer*> RequestBufferMap;
+ RequestBufferMap request_buffers;
+ pthread_key_t thread_request_buffer_key;
+--- a/libs/pbd/pbd/enumwriter.h
++++ b/libs/pbd/pbd/enumwriter.h
+@@ -18,6 +18,9 @@
+ $Id$
+ */
+
++#ifndef __pbd_enumwriter_h__
++#define __pbd_enumwriter_h__
++
+ #include <map>
+ #include <string>
+ #include <vector>
+@@ -45,6 +48,7 @@
+ int read (std::string type, std::string value);
+
+ void add_to_hack_table (std::string str, std::string hacked_str);
++ std::string typed_validate (const std::string& type, const std::string&);
+
+ private:
+ struct EnumRegistration {
+@@ -68,10 +72,16 @@
+
+ static EnumWriter* _instance;
+ static std::map<std::string,std::string> hack_table;
++
++ int validate (EnumRegistration& er, int value);
++
++ std::string validate_string (EnumRegistration& er, const std::string&);
+ };
+
+ }
+
++#define enum_validate(v,str) PBD::EnumWriter::instance().typed_validate (typeid(v).name(),str)
+ #define enum_2_string(e) (PBD::EnumWriter::instance().write (typeid(e).name(), e))
+ #define string_2_enum(str,e) (PBD::EnumWriter::instance().read (typeid(e).name(), (str)))
+
++#endif /* __pbd_enumwriter_h__ */
+--- /dev/null
++++ b/libs/pbd/pbd/epa.h
+@@ -0,0 +1,49 @@
++/*
++ Copyright (C) 2010 Paul Davis
++
++ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++*/
++
++#ifndef __libpbd_epa_h__
++#define __libpbd_epa_h__
++
++#include <map>
++#include <string>
++
++namespace PBD {
++
++class EnvironmentalProtectionAgency {
++ public:
++ EnvironmentalProtectionAgency (bool arm = true, const std::string& envname = std::string());
++ ~EnvironmentalProtectionAgency ();
++
++ void arm ();
++ void save ();
++ void restore () const;
++
++ static EnvironmentalProtectionAgency* get_global_epa () { return _global_epa; }
++ static void set_global_epa (EnvironmentalProtectionAgency* epa) { _global_epa = epa; }
++
++ private:
++ bool _armed;
++ std::string _envname;
++ std::map<std::string,std::string> e;
++ static EnvironmentalProtectionAgency* _global_epa;
++};
++
++}
++
++#endif /* __libpbd_epa_h__ */
+--- a/libs/pbd/SConscript
++++ b/libs/pbd/SConscript
+@@ -26,6 +26,7 @@
+ controllable.cc
+ enumwriter.cc
+ dmalloc.cc
++epa.cc
+ error.cc
+ fpu.cc
+ id.cc
+--- a/libs/pbd/undo.cc
++++ b/libs/pbd/undo.cc
+@@ -40,6 +40,8 @@
+ {
+ _name = rhs._name;
+ _clearing = false;
++ _timestamp = rhs._timestamp;
++
+ clear ();
+ actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end());
+ }
+--- a/libs/surfaces/mackie/mackie_control_protocol.cc
++++ b/libs/surfaces/mackie/mackie_control_protocol.cc
+@@ -622,9 +622,15 @@
+ cout << "MIDI::Port::ALSA_Sequencer " << MIDI::Port::ALSA_Sequencer << endl;
+ cout << "MIDI::Port::Unknown " << MIDI::Port::Unknown << endl;
+ #endif
+- if ( string( midi_port.device() ) == string( "ardour" ) && midi_port.type() == MIDI::Port::ALSA_Sequencer )
++ string pname (PROGRAM_NAME);
++ std::transform(pname.begin(), pname.end(), pname.begin(), ::tolower);
++
++ if ( string( midi_port.device() ) == pname && midi_port.type() == MIDI::Port::ALSA_Sequencer )
+ {
+- throw MackieControlException( "The Mackie MCU driver will not use a port with device=ardour" );
++ ostringstream s;
++ s << "The Mackie MCU driver will not use a port with device=";
++ s << pname;
++ throw MackieControlException( s.str());
+ }
+ else if ( midi_port.type() == MIDI::Port::ALSA_Sequencer )
+ {
+--- a/libs/surfaces/mackie/mackie_port.cc
++++ b/libs/surfaces/mackie/mackie_port.cc
+@@ -488,6 +488,12 @@
+ state.sign = ( raw_bytes[2] & 0x40 ) == 0 ? 1 : -1;
+ // bytes[2] & 0b00111111 (0x3f) gives delta
+ state.ticks = ( raw_bytes[2] & 0x3f);
++ if (state.ticks == 0) {
++ /* euphonix and perhaps other devices send zero
++ when they mean 1, we think.
++ */
++ state.ticks = 1;
++ }
+ state.delta = float( state.ticks ) / float( 0x3f );
+
+ /*
+--- a/SConstruct
++++ b/SConstruct
+@@ -545,6 +545,14 @@
+ else:
+ print 'LV2 support is not enabled (SLV2 not found or older than 0.6.0)'
+ env['LV2'] = 0
++
++ if conf.CheckPKGVersion('rasqal', '0.9.14'):
++ libraries['rasqal'] = LibraryInfo()
++ libraries['rasqal'].ParseConfig('pkg-config --cflags --libs rasqal')
++ else:
++ print 'LV2 support is not enabled (Rasqal, required by SLV2, not found)'
++ env['LV2'] = 0
++
+ conf.Finish()
+ else:
+ print 'LV2 support is not enabled. Build with \'scons LV2=1\' to enable.'
+@@ -1027,6 +1035,9 @@
+ print "It appears you don't have the required MIDI libraries installed. For Linux this means you are missing the development package for ALSA libraries."
+ sys.exit (1)
+
++pname = env['PROGRAM_NAME']
++subst_dict['%MIDI_DEVICE_NAME%'] = pname.lower()
++
+ env = conf.Finish()
+
+ if env['GTKOSX']:
+@@ -1226,6 +1237,15 @@
+ if env['RUBBERBAND']:
+ timefx_subdirs += ['libs/rubberband']
+
++#
++# Tools
++#
++if env['IS_OSX'] == 0 :
++ tools_subdirs = [ 'tools/sanity_check' ]
++else:
++ tools_subdirs = [ ]
++
++
+ opts.Save('scache.conf', env)
+ Help(opts.GenerateHelpText(env))
+
+@@ -1403,7 +1423,7 @@
+ for subdir in coredirs:
+ SConscript (subdir + '/SConscript')
+
+-for sublistdir in [ subdirs, timefx_subdirs, gtk_subdirs, surface_subdirs ]:
++for sublistdir in [ subdirs, timefx_subdirs, gtk_subdirs, surface_subdirs, tools_subdirs ]:
+ for subdir in sublistdir:
+ SConscript (subdir + '/SConscript')
+
+--- /dev/null
++++ b/tools/linux_packaging/ardour.sh.in
+@@ -0,0 +1,40 @@
++#!/bin/sh
++
++#LD_LIBRARY_PATH needs to be set (empty) so that epa can swap between the original and the bundled version
++export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
++
++export PREBUNDLE_ENV="$(env)"
++
++BIN_DIR=$(dirname $(readlink -f $0))
++INSTALL_DIR=$(dirname $BIN_DIR)
++LIB_DIR=$INSTALL_DIR/lib
++ETC_DIR=$INSTALL_DIR/etc
++USER_ARDOUR_DIR=$HOME/.ardour2
++
++if [ ! -d $USER_ARDOUR_DIR ] ; then
++ mkdir -p $USER_ARDOUR_DIR || exit 1
++fi
++
++# this triggers code in main() that will reset runtime environment variables
++# to point to directories inside the ardour package
++
++export ARDOUR_BUNDLED=true
++
++# this is edited by the build script to include relevant environment variables
++
++%ENV%
++
++export GTK_PATH=$INSTALL_DIR${GTK_PATH:+:$GTK_PATH}
++export GTK_MODULES="" # Disable extra modules from being loaded by gtk (example, libcanberra-gtk-module.so)
++export LD_LIBRARY_PATH=$INSTALL_DIR/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
++
++# create install-location-dependent config files for Pango and GDK image loaders
++# We have to do this every time because its possible that BIN_DIR has changed
++
++sed "s?@ROOTDIR@/modules?$LIB_DIR/modules?" < $ETC_DIR/pango.modules.in > $USER_ARDOUR_DIR/pango.modules
++sed "s?@ROOTDIR@/loaders?$LIB_DIR/loaders?" < $ETC_DIR/gdk-pixbuf.loaders.in > $USER_ARDOUR_DIR/gdk-pixbuf.loaders
++
++exec $INSTALL_DIR/bin/ardour-%VER% "$@"
++
++
++
+--- /dev/null
++++ b/tools/linux_packaging/build
+@@ -0,0 +1,619 @@
++#!/bin/bash
++
++#
++
++. ./buildenv
++
++# script for pulling together a Linux app bundle.
++#
++# This will create a bundle for a single architecture.
++# Execute this scirpt on both x86 and x86_64 and then use
++# package to merge the 2 bundles into a final package with the
++# installer.
++
++SAE=
++MIXBUS=
++INTERNAL_JACK=1
++WITH_LADSPA=0
++STRIP=1
++PRINT_SYSDEPS=
++WITH_NLS=
++EXTERNAL_JACK=
++VENDOR=Ardour ;
++
++if [ $# -eq 0 ] ; then
++ echo ""
++ echo "ERROR - Please specify build type"
++ echo " --public"
++ echo " --sae"
++ echo ""
++ exit 1
++fi
++
++while [ $# -gt 0 ] ; do
++ echo "arg = $1"
++ case $1 in
++
++ #
++ # top level build targets
++ #
++
++ --sae)
++ WITH_NLS= ;
++ SAE=1 ;
++ INTERNAL_JACK=1;
++ WITH_LADSPA=1;
++ STRIP=1;
++ APPNAME=Ardour ;
++ shift ;;
++ --mixbus)
++ MIXBUS=1;
++ WITH_NLS=1 ;
++ SAE= ;
++ INTERNAL_JACK=;
++ WITH_LADSPA=;
++ STRIP=1;
++ APPNAME=Mixbus ;
++ VENDOR=Harrison ;
++ shift ;;
++ --public)
++ WITH_NLS=1 ;
++ SAE= ;
++ INTERNAL_JACK=;
++ WITH_LADSPA=;
++ STRIP=1;
++ APPNAME=Ardour ;
++ shift ;;
++ --allinone)
++ SAE= ;
++ WITH_NLS= ;
++ INTERNAL_JACK=1;
++ WITH_LADSPA=1;
++ STRIP=1;
++ shift ;;
++ --test) SAE= ; INTERNAL_JACK=; WITH_LADSPA=; STRIP= ; shift ;;
++
++ #
++ # specific build flags
++ #
++
++ --nojack) INTERNAL_JACK= ; shift ;;
++ --noladspa) WITH_LADSPA= ; shift ;;
++ --nostrip) STRIP= ; shift ;;
++ --sysdeps) PRINT_SYSDEPS=1; shift ;;
++ --nls) WITH_NLS=1 ; shift ;;
++ --external_jack) EXTERNAL_JACK=$2; shift ; shift ;;
++
++ *)
++ #catch all for unknown arguments
++ echo ""
++ echo "!!! ERROR !!! - Unknown argument $1"
++ echo ""
++ exit 1
++ ;;
++ esac
++done
++
++if [ x$EXTERNAL_JACK != x -a x$INTERNAL_JACK != x ] ; then
++ echo "It makes no sense to package JACK internally and externally. Please pick one."
++fi
++
++release_version=`grep -m 1 '^ardour_version' ../../SConstruct | cut -d' ' -f 3 | sed "s/'//g"`
++svn_version=`grep -m 1 'svn_revision =' ../../libs/ardour/svn_revision.cc | cut -d' ' -f 6 | sed 's/[";]//g'`
++echo "Version is $release_version / $svn_version"
++info_string="$release_version/$svn_version built on `hostname` by `whoami` on `date`"
++echo "Info string is $info_string"
++
++# Figure out our CPU type
++case `uname -m` in
++ i[3456789]86|x86|i86pc)
++ echo "Architecture is x86"
++ ARCH='x86'
++ ARCH_BITS='32-bit'
++ ;;
++ x86_64|amd64|AMD64)
++ echo "Architecture is x86_64"
++ ARCH='x86_64'
++ ARCH_BITS='64-bit'
++ ;;
++ *)
++ echo ""
++ echo "ERROR - Unknown architecture `uname -m`"
++ echo ""
++ exit 1
++ ;;
++esac
++
++# setup directory structure
++
++APPDIR=${APPNAME}_${ARCH}-${release_version}_${svn_version}
++APPBIN=$APPDIR/bin
++APPLIB=$APPDIR/lib
++Libraries=$APPLIB
++Etc=$APPDIR/etc
++Shared=$APPDIR/share
++Plugins=$APPLIB/plugins
++Surfaces=$APPLIB/surfaces
++Panners=$APPLIB/panners
++Locale=$Shared/locale
++Modules=$Libraries/modules
++Loaders=$Libraries/loaders
++
++
++if [ x$PRINT_SYSDEPS != x ] ; then
++#
++# print system dependencies
++#
++
++ for file in $APPBIN/* $Libraries/* $Modules/* $Plugins/*.so ; do
++ if ! file $file | grep -qs Mach-O ; then
++ continue
++ fi
++ otool -L $file | awk '{print $1}' | egrep -v "(^@executable_path|^Ardour[0-9][.0-9]*.app)"
++ done | sort | uniq
++ exit 0
++fi
++
++echo "Removing old $APPDIR tree ..."
++rm -rf $APPDIR/
++
++echo "Building new app directory structure ..."
++
++# only bother to make the longest paths
++
++mkdir -p $APPDIR
++mkdir -p $APPBIN
++mkdir -p $APPLIB
++mkdir -p $Etc
++mkdir -p $Plugins
++mkdir -p $Modules
++mkdir -p $Loaders
++mkdir -p $Shared
++mkdir -p $Locale
++mkdir -p $Surfaces
++mkdir -p $Panners
++mkdir -p $Shared/templates
++mkdir -p $Shared/doc
++
++# maybe set variables
++ENVIRONMENT=environment
++rm -f $ENVIRONMENT
++touch $ENVIRONMENT
++
++if test x$SAE != x ; then
++ echo "export ARDOUR_SAE=true" >> $ENVIRONMENT
++ #
++ # current default for SAE version is German keyboard layout without a keypad
++ #
++ echo export ARDOUR_KEYBOARD_LAYOUT=de-nokeypad >> $ENVIRONMENT
++ echo export ARDOUR_UI_CONF=ardour2_ui_sae.conf >> $ENVIRONMENT
++ echo export ARDOUR2_UI_RC=ardour2_ui_dark_sae.rc >> $ENVIRONMENT
++elif test x$MIXBUS != x ; then
++ echo export ARDOUR_MIXBUS=true >> $ENVIRONMENT
++ #
++ # current default for MIXBUS version is US keyboard layout without a keypad
++ #
++ echo export ARDOUR_KEYBOARD_LAYOUT=us-nokeypad >> $ENVIRONMENT
++ echo export ARDOUR_UI_CONF=ardour2_ui.conf >> $ENVIRONMENT
++ echo export ARDOUR2_UI_RC=ardour2_ui_dark.rc >> $ENVIRONMENT
++fi
++
++#
++# if we're not going to bundle JACK, make sure we can find
++# jack in the places where it might be
++#
++
++echo export 'PATH=/usr/local/bin:/opt/bin:$PATH' >> $ENVIRONMENT
++
++# create startup helper script
++
++sed -e "/^%ENV%/r $ENVIRONMENT" -e '/^%ENV%/d' -e 's/%VER%/'"${release_version}"'/' < ardour.sh.in > $APPBIN/ardour2
++rm $ENVIRONMENT && chmod 775 $APPBIN/ardour2
++MAIN_EXECUTABLE=ardour-$release_version
++
++echo "Copying ardour executable ...."
++cp ../../gtk2_ardour/$MAIN_EXECUTABLE $APPBIN
++if test x$STRIP != x ; then
++ strip $APPBIN/$MAIN_EXECUTABLE
++fi
++
++# copy locale files
++if test x$WITH_NLS != x ; then
++ echo "NLS support ..."
++ echo "I hope you remembered to run scons msgupdate!"
++ LINGUAS=
++ files=`find ../../gtk2_ardour/ -name "*.mo"`
++
++ if [ -z "$files" ]; then
++ echo ""
++ echo "!!!! WARNING !!!! - Did not find any .mo files in ../../gtk2_ardour"
++ echo ""
++ fi
++
++ for file in $files
++ do
++ echo $file
++ lang=`basename $file | sed 's/\.mo//'`
++ mkdir -p $Locale/$lang/LC_MESSAGES
++ cp $file $Locale/$lang/LC_MESSAGES/gtk2_ardour.mo
++ LINGUAS="$LINGUAS $lang"
++ done
++
++ files=`find ../../libs/ardour/ -name "*.mo"`
++
++ if [ -z "$files" ]; then
++ echo ""
++ echo "!!!! WARNING !!!! - Did not find any .mo files in ../../libs/ardour"
++ echo ""
++ fi
++
++ for file in $files
++ do
++ echo $file
++ lang=`basename $file | sed 's/\.mo//'`
++ mkdir -p $Locale/$lang/LC_MESSAGES
++ cp $file $Locale/$lang/LC_MESSAGES/libardour.mo
++ done
++
++ GTK_MESSAGES="atk10.mo gdk-pixbuf.mo gtk20-properties.mo gtk20.mo atk10.mo glib20.mo"
++ LOCALEROOT=/usr/share/locale
++
++ for l in $LINGUAS ; do
++ echo "Copying GTK i18n files for $l..."
++ for MO in $GTK_MESSAGES ; do
++ if [ -f $LOCALEROOT/$l/LC_MESSAGES/$MO ] ; then
++ cp $LOCALEROOT/$l/LC_MESSAGES/$MO $Locale/$l/LC_MESSAGES
++ else
++ # try with just the language spec
++ just_lang=`echo $l | sed 's/_[A-Z][A-Z]$//'`
++ if [ -f $LOCALEROOT/$just_lang/LC_MESSAGES/$MO ] ; then
++ cp $LOCALEROOT/$just_lang/LC_MESSAGES/$MO $Locale/$just_lang/LC_MESSAGES
++ fi
++ fi
++ done
++ done
++else
++ echo "Skipping NLS support"
++fi
++
++### Find gtk ###
++GTKROOT=`pkg-config --libs-only-L gtk+-2.0 | sed -e "s/-L//" -e "s/[[:space:]]//g"`
++if [ ! -z "$GTKROOT" ]; then
++ echo "Found GTKROOT using pkg-config"
++elif [ -d /usr/lib/gtk-2.0 ]; then
++ GTKROOT="/usr/lib"
++elif [ -d /usr/local/lib/gtk-2.0 ]; then
++ GTKROOT="/usr/local/lib"
++else
++ echo ""
++ echo "!!! ERROR !!! - Unable to locate gtk-2.0 directory. Packager will exit"
++ echo ""
++ exit 1
++fi
++
++echo "GTKROOT is ${GTKROOT}"
++versionDir=`ls ${GTKROOT}/gtk-2.0/ | grep "[0-9]*\.[0-9]*\.[0-9]*"`
++
++num=0
++for name in $versionDir ; do
++ num=$(($num + 1))
++done
++
++if [ $num -eq 1 ]; then
++ GTKLIB=${GTKROOT}/gtk-2.0/$versionDir
++ echo "GTKLIB is ${GTKLIB}"
++else
++ echo ""
++ echo "!!! ERROR !!! - More than one gtk-2.0 version found in ${GTKROOT}/gtk-2.0/ ( $versionDir ). Packager will exit"
++ echo ""
++ exit 1
++fi
++
++
++### Find pango ###
++PANGOROOT=`pkg-config --libs-only-L pango | sed -e "s/-L//" -e "s/[[:space:]]//g"`
++if [ ! -z "$PANGOROOT" ]; then
++ echo "Found PANGOROOT using pkg-config"
++elif [ -d /usr/lib/pango ]; then
++ PANGOROOT="/usr/lib"
++elif [ -d /usr/local/lib/pango ]; then
++ PANGOROOT="/usr/local/lib"
++else
++ echo ""
++ echo "!!! ERROR !!! - Unable to locate pango directory. Packager will exit"
++ echo ""
++ exit 1
++fi
++
++echo "PANGOROOT is ${PANGOROOT}"
++versionDir=`ls ${PANGOROOT}/pango/ | grep "[0-9]*\.[0-9]*\.[0-9]*"`
++
++num=0
++for name in $versionDir ; do
++ num=$(($num + 1))
++done
++
++if [ $num -eq 1 ]; then
++ PANGOLIB=${PANGOROOT}/pango/$versionDir
++ echo "PANGOLIB is ${PANGOLIB}"
++else
++ echo ""
++ echo "!!! ERROR !!! - More than one pango version found in ${PANGOROOT}/pango/ ( $versionDir ). Packager will exit"
++ echo ""
++ exit 1
++fi
++
++
++### Find gdk-pixbuf ###
++GDKPIXBUFROOT=`pkg-config --libs-only-L gdk-pixbuf-2.0 | sed -e "s/-L//" -e "s/[[:space:]]//g"`
++if [ ! -z "$GDKPIXBUFROOT" ]; then
++ echo "Found GDKPIXBUFROOT using pkg-config"
++elif [ -d /usr/lib/gdk-pixbuf-2.0 ]; then
++ GDKPIXBUFROOT="/usr/lib/gdk-pixbuf-2.0"
++elif [ -d /usr/local/lib/gdk-pixbuf-2.0 ]; then
++ GDKPIXBUFROOT="/usr/local/lib/gdk-pixbuf-2.0"
++elif [ -d ${GTKLIB}/loaders ]; then #odd ball case
++ GDKPIXBUFROOT=${GTKROOT}
++ GDKPIXBUFLIB=${GTKLIB}
++else
++ echo ""
++ echo "!!! ERROR !!! - Unable to locate gdk-pixbuf-2.0 directory. Packager will exit"
++ echo ""
++ exit 1
++fi
++
++echo "GDKPIXBUFROOT is ${GDKPIXBUFROOT}"
++
++if [ -z ${GDKPIXBUFLIB} ]; then
++ versionDir=`ls ${GDKPIXBUFROOT}/gdk-pixbuf-2.0/ | grep "[0-9]*\.[0-9]*\.[0-9]*"`
++
++ num=0
++ for name in $versionDir ; do
++ num=$(($num + 1))
++ done
++
++ if [ $num -eq 1 ]; then
++ GDKPIXBUFLIB=${GDKPIXBUFROOT}/gdk-pixbuf-2.0/$versionDir
++ echo "GDKPIXBUFLIB is ${GDKPIXBUFLIB}"
++ else
++ echo ""
++ echo "!!! ERROR !!! - More than one gdk-pixbuf-2.0 version found in ${GDKPIXBUFROOT}/pango/ ( $versionDir ). Packager will exit"
++ echo ""
++ exit 1
++ fi
++fi
++
++
++
++echo "Copying all Pango modules ..."
++cp -R $PANGOLIB/modules/*.so $Modules
++
++echo "Copying all GDK Pixbuf loaders ..."
++cp -R $GDKPIXBUFLIB/loaders/*.so $Loaders
++
++pango-querymodules | sed "s?$PANGOLIB/?@ROOTDIR@/?" > $Etc/pango.modules.in
++gdk-pixbuf-query-loaders | sed "s?$GDKPIXBUFLIB/?@ROOTDIR@/?" > $Etc/gdk-pixbuf.loaders.in
++
++# We sort of rely on clearlooks, so include a version
++# this one is special - we will set GTK_PATH to $Libraries/clearlooks
++
++if [ ! -e ${GTKLIB}/engines/libclearlooks.so ]; then
++ echo ""
++ echo "!!! ERROR !!! - not able to locate libclearlooks.so"
++ echo ""
++ echo "Packager with exit"
++ exit 1
++fi
++
++echo "Copying clearlooks ..."
++cp ${GTKLIB}/engines/libclearlooks.so $Libraries
++mkdir -p $Libraries/clearlooks/engines
++(cd $Libraries/clearlooks/engines && ln -s ../../libclearlooks* libclearlooks.so )
++
++# LADSPA
++if test x$WITH_LADSPA != x ; then
++ if test x$SAE != x ; then
++ plugdir=sae_ladspa
++ elif test x$MIXBUS != x ; then
++ plugdir=mixbus_ladspa
++ else
++ plugdir=ladspa
++ fi
++ echo "Copying `ls $plugdir | wc -l` plugins ..."
++ if [ -d $plugdir ] ; then
++ cp -r $plugdir/* $Plugins
++ fi
++fi
++
++# XXX STILL NEED TO DO PANNERS FOR TRUNK
++cp ../../libs/surfaces/*/libardour_*.so* $Surfaces
++# hack ... move libardour_cp back into Libraries
++mv $Surfaces/libardour_cp.so* $Libraries
++
++# VAMP plugins that we use
++cp ../../libs/vamp-plugins/libardourvampplugins.so* $Libraries
++
++OURLIBDIR=../../libs
++OURLIBS=$OURLIBDIR/vamp-sdk:$OURLIBDIR/surfaces/control_protocol:$OURLIBDIR/ardour:$OURLIBDIR/midi++2:$OURLIBDIR/pbd:$OURLIBDIR/rubberband:$OURLIBDIR/soundtouch:$OURLIBDIR/gtkmm2ext:$OURLIBDIR/sigc++2:$OURLIBDIR/glibmm2:$OURLIBDIR/gtkmm2/atk:$OURLIBDIR/gtkmm2/pango:$OURLIBDIR/gtkmm2/gdk:$OURLIBDIR/gtkmm2/gtk:$OURLIBDIR/libgnomecanvasmm:$OURLIBDIR/libsndfile
++
++echo $OURLIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
++
++checkedIdx=0
++
++while [ true ] ; do
++ missing=false
++ filelist=`find $APPLIB/ -type f`
++ filelist="$APPBIN/$MAIN_EXECUTABLE $filelist"
++
++ for file in $filelist ; do
++ if ! file $file | grep -qs ELF ; then
++ continue
++ fi
++
++ # speed this up a bit by not checking things multiple times.
++ for i in "${depCheckedList[@]}"; do
++ if [ $i == $file ]; then
++ continue 2
++ fi
++ done
++ depCheckedList[$checkIdx]=$file
++ checkIdx=$(($checkIdx + 1))
++
++ # do not include libjack
++ deps=`LD_LIBRARY_PATH=$OURLIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} ldd $file | awk '{print $3}'`
++
++ # LD_LIBRARY_PATH=$OURLIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} ldd $file | egrep "(/opt/|/local/|libs/|/usr/lib|/gtk)" | grep -v 'libjack\.'
++ echo -n "."
++ for dep in $deps ; do
++ if test "not" = ${dep}; then
++ echo ""
++ echo "!!! ERROR !!! - Missing dependant library for $file."
++ echo ""
++ (LD_LIBRARY_PATH=$OURLIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} ldd $file)
++ echo ""
++ echo "!!! ERROR !!! - See Above"
++ exit 1
++ fi
++
++ # don't use anything mapped at a specific address
++ if echo $dep | grep -qs '0x' ; then continue; fi
++ # don't include /lib
++ if echo $dep | grep -qs "^/lib/" ; then continue; fi
++ # don't include jack
++ if echo $dep | grep -qs libjack ; then continue; fi
++ # don't include any X Window libraries
++ if echo $dep | grep -qs libX ; then continue; fi
++ if echo $dep | grep -qs libxcb ; then continue; fi
++ # don't include libc
++ if echo $dep | grep -qs 'libc\.' ; then continue; fi
++ # don't include libstdc++
++ if echo $dep | grep -qs libstdc++ ; then continue; fi
++
++ base=`basename $dep`
++ if ! test -f $Libraries/$base; then
++ parent=$(basename ${file})
++ if echo $dep | grep -sq '^libs' ; then
++ echo "Copying dependant lib ../../$dep (required by ${parent})"
++ cp ../../$dep $Libraries
++ else
++ echo "Copying dependant lib $dep (required by ${parent})"
++ cp $dep $Libraries
++ fi
++ missing=true
++ fi
++ done
++ done
++ if test x$missing = xfalse ; then
++ # everything has been found
++ break
++ fi
++done
++echo
++
++# strip libraries
++if test x$STRIP != x ; then
++ echo Stripping libraries
++ find $APPLIB/ -name "*.so*" | xargs strip
++fi
++
++find $APPLIB/ -name "*.so*" | xargs chmod a+rx
++
++echo "Copying other stuff to $APPDIR ..."
++
++cp ../../gtk2_ardour/ergonomic-us.bindings $Etc
++cp ../../gtk2_ardour/mnemonic-us.bindings $Etc
++cp ../../gtk2_ardour/SAE-de-keypad.bindings $Etc
++cp ../../gtk2_ardour/SAE-de-nokeypad.bindings $Etc
++cp ../../gtk2_ardour/SAE-us-keypad.bindings $Etc
++cp ../../gtk2_ardour/SAE-us-nokeypad.bindings $Etc
++cp ../../gtk2_ardour/ardour.menus $Etc
++cp ../../gtk2_ardour/ardour-sae.menus $Etc
++if test x$SAE != x ; then
++ cp ../../ardour_system_sae.rc $Etc/ardour_system.rc
++ echo cp ../../ardour_system_sae.rc $Etc/ardour_system.rc
++ cp ../../instant.xml.sae $Etc/instant.xml
++ echo cp ../../instant.xml.sae $Etc/instant.xml
++else
++ cp ../../ardour_system.rc $Etc/ardour_system.rc
++ echo cp ../../ardour_system.rc $Etc/ardour_system.rc
++ cp ../../instant.xml $Etc/instant.xml
++ echo cp ../../instant.xml $Etc/instant.xml
++fi
++cp ../../gtk2_ardour/ardour2_ui_sae.conf $Etc
++cp ../../gtk2_ardour/ardour2_ui_default.conf $Etc
++cp ../../gtk2_ardour/ardour2_ui_default.conf $Etc/ardour2_ui.conf
++cp ../../gtk2_ardour/ardour2_ui_light.rc $Etc
++cp ../../gtk2_ardour/ardour2_ui_dark.rc $Etc
++cp ../../gtk2_ardour/ardour2_ui_light_sae.rc $Etc
++cp ../../gtk2_ardour/ardour2_ui_dark_sae.rc $Etc
++
++cp -r ../../gtk2_ardour/icons $Etc
++cp -r ../../gtk2_ardour/pixmaps $Etc
++
++#
++# put sooper sekrit ingredients here and they will be copied
++#
++
++if [ -d specialSauce ] ; then
++ cp -r specialSauce $Etc
++fi
++
++# share stuff
++
++cp -R ../../gtk2_ardour/splash.png $Shared
++cp ../../templates/*.template $Shared/templates/
++
++# go through and recursively remove any .svn dirs in the bundle
++for svndir in `find $APPDIR -name .svn -type d`; do
++ rm -rf $svndir
++done
++
++#
++# Add any documentation to the top level of the package
++#
++
++if [ x$SAE != x ] ; then
++
++ # SAE packaging
++
++ echo "Adding SAE documentation"
++ cp HowToInstallArdourSAE.pdf "$Shared/doc/How To Install Ardour SAE.pdf"
++ cp SAE-de-keypad.pdf "$Shared/doc/Ardour SAE Shortcuts (keypad).pdf"
++ cp SAE-de-nokeypad.pdf "$Shared/doc/Ardour SAE Shortcuts.pdf"
++
++elif [ x$MIXBUS != x ] ; then
++
++ # Mixbus packaging
++
++ echo "Adding Mixbus documentation"
++ cp MixBus_Install_QuickStart.pdf "$Shared/doc/Mixbus Install & Quick Start Guide.pdf"
++
++ if [ -x $EXTERNAL_JACK != x ] ; then
++ cp $EXTERNAL_JACK $PRODUCT_PKG_DIR
++ fi
++fi
++
++#
++# Add the uninstaller
++#
++APP_VER_NAME=${APPNAME}-${release_version}_${svn_version}
++sed -e "s/%REPLACE_PGM%/${APPNAME}/" -e "s/%REPLACE_VENDOR%/${VENDOR}/" -e "s/%REPLACE_VERSION%/${release_version}/" -e "s/%REPLACE_BUILD%/${svn_version}/" < uninstall.sh.in > $APPBIN/${APP_VER_NAME}.uninstall.sh
++chmod a+x $APPBIN/${APP_VER_NAME}.uninstall.sh
++
++#Sanity Check file
++if [ -e ../sanity_check/sanityCheck ]; then
++ cp ../sanity_check/sanityCheck $APPBIN
++else
++ echo "!!!ERROR !!! sanityCheck program is missing. packager will exit without being complete"
++ exit 1
++fi
++
++echo "Building tarball ..."
++
++rm -f $APPDIR.tar.bz2
++tar -cjf $APPDIR.tar.bz2 $APPDIR
++
++rm -rf $APPDIR/
++
++echo "Done."
++
+--- /dev/null
++++ b/tools/linux_packaging/buildenv
+@@ -0,0 +1,8 @@
++GTK_PREFIX_DIR=/gtk/will/search/here
++
++if ! echo $LD_LIBRARY_PATH | grep -qs $GTK_PREFIX_DIR ; then
++ LD_LIBRARY_PATH=${GTK_PREFIX_DIR}/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
++ PATH=${GTK_PREFIX_DIR}/bin:$PATH
++ PKG_CONFIG_PATH=${GTK_PREFIX_DIR}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}
++fi
++
+--- /dev/null
++++ b/tools/linux_packaging/install.sh
+@@ -0,0 +1,25 @@
++#!/bin/sh
++
++# Make sure we have a terminal for the user to see and then run
++# the real install script.
++
++# Some systems don't correctly set the PWD when a script is double-clicked,
++# so go ahead and figure out our path and make sure we are in that directory.
++
++SAVED_PWD=$PWD
++PKG_PATH=$(dirname $(readlink -f $0))
++cd ${PKG_PATH}
++
++if [ -z "$TERM" ] || [ "$TERM" = "dumb" ]; then
++ if which xterm > /dev/null; then
++ exec xterm -e ${PKG_PATH}/.stage2.run
++ elif which gnome-terminal > /dev/null; then
++ exec gnome-terminal -e ${PKG_PATH}/.stage2.run
++ elif which konsole > /dev/null; then
++ exec konsole -e ${PKG_PATH}/.stage2.run
++ fi
++else
++ ${PKG_PATH}/.stage2.run
++fi
++
++cd ${SAVED_PWD}
+--- /dev/null
++++ b/tools/linux_packaging/package
+@@ -0,0 +1,90 @@
++#!/bin/bash
++
++# package
++
++# This will collect up the x86 and x86_64 bundles created by build
++# and package them together with an installer script.
++
++
++if [ $# -eq 0 ] ; then
++ echo ""
++ echo "ERROR - Please specify build type"
++ echo " --public"
++ echo " --sae"
++ echo ""
++ exit 1
++fi
++
++while [ $# -gt 0 ] ; do
++ echo "arg = $1"
++ case $1 in
++
++ #
++ # top level build targets
++ #
++
++ --sae)
++ APPNAME=Ardour ;
++ shift ;;
++ --mixbus)
++ APPNAME=Mixbus ;
++ shift ;;
++ --public)
++ APPNAME=Ardour ;
++ shift ;;
++
++ *)
++ #catch all for unknown arguments
++ echo ""
++ echo "!!! ERROR !!! - Unknown argument $1"
++ echo ""
++ exit 1
++ ;;
++ esac
++done
++
++
++release_version=`grep -m 1 '^ardour_version' ../../SConstruct | cut -d' ' -f 3 | sed "s/'//g"`
++svn_version=`grep -m 1 'svn_revision =' ../../libs/ardour/svn_revision.cc | cut -d' ' -f 6 | sed 's/[";]//g'`
++
++X86_BUILD="${APPNAME}_x86-${release_version}_${svn_version}.tar.bz2"
++X86_64_BUILD="${APPNAME}_x86_64-${release_version}_${svn_version}.tar.bz2"
++PACKAGE="${APPNAME}-${release_version}_${svn_version}"
++
++if [ ! -e ${X86_BUILD} ]; then
++ echo ""
++ echo "!!! ERROR !!! - Can't locate x86 build file ${X86_BUILD}"
++ echo ""
++ exit 1
++fi
++
++if [ ! -e ${X86_64_BUILD} ]; then
++ echo ""
++ echo "!!! ERROR !!! - Can't locate x86_64 build file ${X86_64_BUILD}"
++ echo ""
++ exit 1
++fi
++
++echo "Cleaning up any old package files for this build"
++#Get rid of any old packages of this same name.
++rm -f ${PACKAGE}.tar.bz2
++rm -rf ${PACKAGE}
++
++
++echo "Creating new package dir..."
++mkdir ${PACKAGE}
++mv ${X86_BUILD} ${PACKAGE}
++mv ${X86_64_BUILD} ${PACKAGE}
++cp install.sh ${PACKAGE}
++cp stage2.run ${PACKAGE}/.stage2.run
++cp README ${PACKAGE}
++
++echo "Creating tarball..."
++tar -czf ${PACKAGE}.tar.gz ${PACKAGE}
++
++echo "Clean up"
++rm -rf ${PACKAGE}
++
++echo ""
++echo "Done"
++echo ""
+--- /dev/null
++++ b/tools/linux_packaging/README
+@@ -0,0 +1,35 @@
++* Installing Ardour:
++
++On most distributions, you can double-click the file "install.sh".
++
++Alternatively, you can use a Terminal to run the installer. Navigate
++to the folder and run:
++
++ ./install.sh
++
++The installer will ask for your root password, and copy the contents of
++the appropriate bundle (32-bit or 64-bit) to your /opt folder.
++
++
++* Links and Menu entries:
++
++In addition to installing the program, the installer will create:
++1) A desktop link to launch the Ardour application
++2) A menu entry in Gnome/KDE
++3) An uninstall script in the /opt folder.
++
++
++* Uninstaller:
++
++To uninstall Ardour, run the uninstaller script in the /opt folder
++(as root). This will remove the app, desktop links, menu links, and
++the uninstaller itself.
++
++
++* Manual Installation:
++
++If you would prefer to install Ardour in a custom location, then you
++may simply unzip the appropriate package (32bit or 64bit) to your
++preferred location and run the Ardour application from the "bin"
++folder inside.
++
+--- /dev/null
++++ b/tools/linux_packaging/stage2.run
+@@ -0,0 +1,525 @@
++#!/bin/sh
++
++####################################
++#
++# stage2.run
++# Ardour/Mixbus bundle installer
++# Todd Naugle
++#
++###################################
++
++
++
++PGM_NAME="Ardour"
++PGM_VENDOR="Ardour"
++PGM_EXEC_FILE="ardour2"
++
++INSTALL_DEST_BASE="/opt"
++
++PGM_NAME_LOWER=$(echo $PGM_NAME | tr '[:upper:]' '[:lower:]')
++
++#### Global Variables ####
++HAS_XDG="T"
++
++########################
++# Function Definitions
++########################
++
++VaildateYesNoQuestion ()
++{
++ # $1 = Question Text
++
++ local INPUT_OK="n"
++ local USER_INPUT=""
++
++ until test "y" = $INPUT_OK;
++ do
++ echo ""
++ read -p "$1 [y/n]: " USER_INPUT
++ echo ""
++
++ if [ ! -z $USER_INPUT ];
++ then
++ if [ "Y" = $USER_INPUT -o "y" = $USER_INPUT -o "n" = $USER_INPUT -o "N" = $USER_INPUT ];
++ then
++ INPUT_OK="y"
++ fi
++ fi
++ done
++
++ echo $USER_INPUT | tr '[:upper:]' '[:lower:]'
++
++}
++
++SystemInstall ()
++{
++
++ # Determine which software install app to use and then install requested package
++ # $1 = Package Name
++
++ if which yum > /dev/null;
++ then
++ sudo yum -y install $1
++ rtrn=$?
++
++ if [ $rtrn -ne 0 ];
++ then
++ echo ""
++ echo "!!! ERROR !!! yum install failed for an unknown reason."
++ echo "Please install package $1 after this installer completes."
++ echo ""
++ fi
++
++ elif which apt-get > /dev/null;
++ then
++ sudo apt-get -y install $1
++ rtrn=$?
++
++ if [ $rtrn -ne 0 ];
++ then
++ echo ""
++ echo "!!! ERROR !!! apt-get install failed for an unknown reason."
++ echo "Please install package $1 after this installer completes."
++ echo ""
++ fi
++
++ else
++ echo ""
++ echo "!!! ERROR !!! - Not able to detect which software install tool to use (yum or apt-get)."
++ echo "Please install package $1 using the system software install tool."
++ echo ""
++ rtrn=1
++ fi
++
++ return $rtrn
++
++}
++
++########################################################################
++# Main
++########################################################################
++
++# If you double click a script, some systems don't get the PWD correct.
++# Force it to be correct
++PKG_PATH=$(dirname $(readlink -f $0))
++cd ${PKG_PATH}
++
++echo ""
++echo "Welcome to the ${PGM_NAME} installer"
++echo ""
++
++##############
++# Check sudo
++##############
++
++if ! sudo date;
++then
++ echo ""
++ echo "!!! ERROR !!!"
++ echo ""
++ echo "Either you don't know the root password or the user is not allowed to sudo"
++ echo "Please correct this and run the installer again (hint: use visudo to edit sudoers file)"
++ echo ""
++ read -p "Press ENTER to exit installer:" BLAH
++ exit 1
++fi
++
++############################
++# Determine processor type
++############################
++
++case `uname -m` in
++ i[3456789]86|x86|i86pc)
++ echo "Architecture is x86"
++ ARCH='x86'
++ ;;
++ x86_64|amd64|AMD64)
++ echo "Architecture is x86_64"
++ ARCH='x86_64'
++ ;;
++ *)
++ echo ""
++ echo "!!! ERROR !!! - Unknown architecture `uname -m`"
++ echo ""
++ read -p "Press ENTER to exit installer:" BLAH
++ exit 1
++ ;;
++esac
++
++# untar the correct bundle for us to install
++echo "Unpacking bundle for $ARCH"
++tar -xjf ${PGM_NAME}_${ARCH}-*.tar.bz2
++BUNDLE_DIR=$(basename `find -maxdepth 1 -type d -name "${PGM_NAME}_${ARCH}-*"`)
++
++
++#######################
++# Check for xdg utils
++#######################
++
++XDG_MENU_VER=$(xdg-desktop-menu --version 2> /dev/null)
++if [ -z "$XDG_MENU_VER" ];
++then
++ echo "System does not have xdg-desktop-menu installed"
++ HAS_XDG="F"
++fi
++
++XDG_ICON_VER=$(xdg-icon-resource --version 2> /dev/null)
++if [ -z "$XDG_ICON_VER" ];
++then
++ echo "System does not have xdg-icon-resource installed"
++ HAS_XDG="F"
++fi
++
++#################################################
++# Check if system libs are OK (libc, etc)
++#################################################
++
++echo ""
++echo "Checking system libs to see if they are compatible with ${PGM_NAME}."
++echo ""
++
++LIB_ERROR="F"
++LD_PATH=`pwd`/${BUNDLE_DIR}/lib
++
++# check the main App
++LDD_RESULT=$(LD_LIBRARY_PATH=${LD_PATH} ldd ${BUNDLE_DIR}/bin/${PGM_NAME_LOWER}-* 2>&1 > /dev/null)
++
++if [ -n "$LDD_RESULT" ];
++then
++ echo "$LDD_RESULT"
++ LIB_ERROR="T"
++fi
++
++# check the libs
++LIB_FILES=$(find ${BUNDLE_DIR}/lib -name "*.so")
++
++for path in $LIB_FILES
++do
++ LDD_RESULT=$(LD_LIBRARY_PATH=${LD_PATH} ldd $path 2>&1 > /dev/null)
++ if [ -n "$LDD_RESULT" ];
++ then
++ echo "$LDD_RESULT"
++ LIB_ERROR="T"
++ fi
++done
++
++if test "T" = $LIB_ERROR;
++then
++ echo ""
++ echo "!!! ERROR !!! - Missing library detected!"
++ echo "This system does not have the correct libs to run ${PGM_NAME}."
++ echo "Installation will not complete. Please use a compatible distro."
++ echo ""
++ read -p "Press ENTER to exit installer:" BLAH
++ exit 1
++fi
++
++################################
++# Setup derived variables
++################################
++PGM_VERSION=$(echo ${BUNDLE_DIR} | awk 'BEGIN { FS = "-" } ; { print $2 }' | awk 'BEGIN { FS = "_"} ; { print $1}')
++PGM_BUILD=$(echo ${BUNDLE_DIR} | awk 'BEGIN { FS = "-" } ; { print $2 }' | awk 'BEGIN { FS = "_"} ; { print $2}')
++PGM_FULL_NAME="${PGM_NAME}-${PGM_VERSION}_${PGM_BUILD}"
++
++ICON_NAME="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}" #no dash since it seperates vendor from program
++MENU_FILE="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}.desktop" #no dash since it seperates vendor from program
++DESKTOP_LINK_FILE="${PGM_NAME}_${PGM_VERSION}.desktop"
++
++PGM_EXEC_PATH="${INSTALL_DEST_BASE}/${PGM_FULL_NAME}/bin/${PGM_EXEC_FILE}"
++ICON_PATH="${INSTALL_DEST_BASE}/${PGM_FULL_NAME}/etc/icons"
++MENU_FILE_PATH="${INSTALL_DEST_BASE}/${PGM_FULL_NAME}/share"
++
++
++
++################################
++# Install bundle and Menu/Link
++################################
++
++if [ ! -d ${INSTALL_DEST_BASE} ];
++then
++ echo ""
++ echo "!!! ERROR !!! - Installation location ${INSTALL_DEST_BASE} does not exist!"
++ echo "Installation will not complete."
++ echo ""
++ read -p "Press ENTER to exit installer:" BLAH
++ exit 1
++fi
++
++# uninstall any older versions
++UNINSTALLERS=$(find ${INSTALL_DEST_BASE} -maxdepth 1 -type f -name "${PGM_NAME}*.uninstall.sh")
++if [ ! -z "$UNINSTALLERS" ];
++then
++ for i in $UNINSTALLERS; do
++ echo ""
++ echo "Found existing ${PGM_NAME} installation."
++
++ ANSWER=$(VaildateYesNoQuestion "Do you want to run the uninstaller ${i} ?")
++
++ if test "y" = $ANSWER;
++ then
++ echo ""
++ echo "Running uninstaller $i"
++
++ ${i}
++ sudo rm -f ${i}
++ fi
++ done
++fi
++
++
++# install
++
++echo ""
++echo "Installing ${PGM_NAME} ${PGM_VERSION} built from ${PGM_BUILD} in ${INSTALL_DEST_BASE}"
++echo ""
++
++# Copy the new version in the install directory
++sudo mkdir ${INSTALL_DEST_BASE}/${PGM_FULL_NAME}
++sudo cp -Rf ${BUNDLE_DIR}/* ${INSTALL_DEST_BASE}/${PGM_FULL_NAME}/
++
++# write the desktop/menu file
++echo "[Desktop Entry]" > /tmp/${MENU_FILE}
++echo "Encoding=UTF-8" >> /tmp/${MENU_FILE}
++echo "Version=1.0" >> /tmp/${MENU_FILE}
++echo "Type=Application" >> /tmp/${MENU_FILE}
++echo "Terminal=false" >> /tmp/${MENU_FILE}
++echo "Exec=${PGM_EXEC_PATH}" >> /tmp/${MENU_FILE}
++echo "Name=${PGM_NAME}-${PGM_VERSION}" >> /tmp/${MENU_FILE}
++echo "Icon=${ICON_NAME}" >> /tmp/${MENU_FILE}
++echo "Comment=Digital Audio Workstation" >> /tmp/${MENU_FILE}
++echo "Categories=AudioVideo;AudioEditing;Audio;Recorder;" >> /tmp/${MENU_FILE}
++
++chmod ugo+rx /tmp/${MENU_FILE}
++sudo mv /tmp/${MENU_FILE} ${MENU_FILE_PATH}/.
++
++# install the Menu, Link, and Icon(s)
++if [ "T" = ${HAS_XDG} ];
++then
++ echo "Adding ${PGM_NAME} to the applications menu"
++ sudo xdg-icon-resource install --context apps --size 16 ${ICON_PATH}/${PGM_NAME_LOWER}_icon_16px.png ${ICON_NAME}
++ sudo xdg-icon-resource install --context apps --size 22 ${ICON_PATH}/${PGM_NAME_LOWER}_icon_22px.png ${ICON_NAME}
++ sudo xdg-icon-resource install --context apps --size 32 ${ICON_PATH}/${PGM_NAME_LOWER}_icon_32px.png ${ICON_NAME}
++ sudo xdg-icon-resource install --context apps --size 48 ${ICON_PATH}/${PGM_NAME_LOWER}_icon_48px.png ${ICON_NAME}
++
++ if [ -e ${ICON_PATH}/${PGM_NAME_LOWER}_icon.svg -a -d /usr/share/icons/hicolor/scalable/apps ];
++ then
++ sudo cp -f ${ICON_PATH}/${PGM_NAME_LOWER}_icon.svg /usr/share/icons/hicolor/scalable/apps/${ICON_NAME}.svg
++ fi
++
++ sudo xdg-desktop-menu install ${MENU_FILE_PATH}/${MENU_FILE}
++ sudo xdg-desktop-menu forceupdate --mode system # Some systems need an extra kick
++
++ echo ""
++ echo "Creating a desktop link for ${PGM_NAME}"
++ cp ${MENU_FILE_PATH}/${MENU_FILE} ~/Desktop/${DESKTOP_LINK_FILE}
++ chmod ugo+rx ~/Desktop/${DESKTOP_LINK_FILE}
++else
++ echo ""
++ echo "Creating a desktop link for ${PGM_NAME}"
++ cp ${MENU_FILE_PATH}/${MENU_FILE} ~/Desktop/${DESKTOP_LINK_FILE}
++ chmod ugo+rx ~/Desktop/${DESKTOP_LINK_FILE}
++fi
++
++echo ""
++echo "Copying uninstall script to ${INSTALL_DEST_BASE}"
++echo ""
++
++sudo cp -f ${BUNDLE_DIR}/bin/*.uninstall.sh ${INSTALL_DEST_BASE}/.
++
++###########################
++# Check Jack and qjackctl
++###########################
++
++echo ""
++echo "Checking to see if Jack is installed"
++echo ""
++
++if ! which jackd > /dev/null;
++then
++ echo ""
++ echo "The program Jack is missing from this system. Jack is a required component of $PGM_NAME."
++ echo ""
++
++ ANSWER=$(VaildateYesNoQuestion "Install jack using system software repository?")
++
++ if test "y" = $ANSWER;
++ then
++ echo "Attempting to install Jack"
++ SystemInstall "jackd"
++
++ if [ $? -ne 0 ];
++ then
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++ fi
++ fi
++else
++ echo "Jack OK"
++fi
++
++
++if ! which qjackctl > /dev/null;
++then
++ echo ""
++ echo "The program QjackCtl is missing from this system."
++ echo "QjackCtl is an extremely useful tool for any system that runs JACK applications like $PGM_NAME."
++ echo "We recommend that you install it."
++ echo ""
++
++ ANSWER=$(VaildateYesNoQuestion "Install QjackCtl using system software repository?")
++
++ if test "y" = $ANSWER;
++ then
++ echo "Attempting to install QjackCtl"
++ SystemInstall "qjackctl"
++
++ if [ $? -ne 0 ];
++ then
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++ fi
++ fi
++fi
++
++
++########################
++# Run Sanity Check
++########################
++
++USER_GROUP_ADJUSTED="f"
++
++if ! ./${BUNDLE_DIR}/bin/sanityCheck -a > /dev/null;
++then
++ echo ""
++ echo "System failed the quick sanity check... Looking for the cause"
++
++ if ! ./${BUNDLE_DIR}/bin/sanityCheck -rt > /dev/null;
++ then
++ echo ""
++ echo "System does not allow realtime for the current user... Looking for a solution"
++
++ if ./${BUNDLE_DIR}/bin/sanityCheck -hasaudiogroup > /dev/null;
++ then
++ if ./${BUNDLE_DIR}/bin/sanityCheck -memberaudiogroup > /dev/null 2>&1;
++ then
++ ## This is an odd case. We have an audio group and are a member.
++ echo ""
++ echo "!!! WARNING !!! - The current user can not execute realtime processes."
++ echo "This will adversely affect audio latency."
++ echo "This system has an audio group and the user is a member. If jack was"
++ echo "just installed, a simple log out/in may fix this."
++ echo ""
++ echo "For best results, please correct this on your system."
++ echo "(Hint: check /etc/security/limits.conf or /etc/security/limits.d/)"
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++ else
++ # Not a member of an audio group. Try to fix it.
++
++ if ./${BUNDLE_DIR}/bin/sanityCheck -hasgroup audio > /dev/null && find /etc/security -type f -name "*.conf" | xargs grep -q "^@audio.*rtprio";
++ then
++ # add user to audio group
++ echo ""
++ echo "Adding user `whoami` to the audio group."
++ echo "This should allow you to run realtime tasks. Please re-login for this change to take affect."
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++
++ user=`whoami`
++ if sudo usermod -a -G audio $user;
++ then
++ USER_GROUP_ADJUSTED="t"
++ else
++ echo ""
++ echo "!!! ERROR !!! - Not able to add user to the audio group (usermod failed)!"
++ echo ""
++ echo "Please add yourself to the audio group and re-login"
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++ fi
++
++ elif ./${BUNDLE_DIR}/bin/sanityCheck -hasgroup jackuser > /dev/null && find /etc/security -type f -name "*.conf" | xargs grep -q "^@jackuser.*rtprio";
++ then
++ # add user to jackuser group
++ echo ""
++ echo "Adding user `whoami` to the jackuser group."
++ echo "This should allow you to run realtime tasks. Please re-login for this change to take affect."
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++
++ user=`whoami`
++ if sudo usermod -a -G jackuser $user;
++ then
++ USER_GROUP_ADJUSTED="t"
++ else
++ echo ""
++ echo "!!! ERROR !!! - Not able to add user to the jackuser group."
++ echo ""
++ echo "Please add yourself to the audio group and re-login"
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++ fi
++
++
++ fi
++ fi
++ else
++ # No audio group found on this system!
++ echo ""
++ echo "!!! WARNING !!! - The system does not seem to have an audio group (audio or jackuser)."
++ echo ""
++ echo "We will not attempt to fix this. Please configure your system to allow"
++ echo "non-root users to execute realtime tasks."
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++ fi
++ fi
++
++ if ! ./${BUNDLE_DIR}/bin/sanityCheck -freqscaling > /dev/null;
++ then
++ echo ""
++ echo "!!! WARNING !!! - Your system seems to use frequency scaling."
++ echo "This can have a serious impact on audio latency. You have two choices:"
++ echo "(1) turn it off, e.g. by chosing the 'performance' governor."
++ echo "(2) Use the HPET clocksource by passing \"-c h\" to JACK"
++ echo "(this second option only works on relatively recent computers)"
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++ fi
++
++ if [ "f" = $USER_GROUP_ADJUSTED ];
++ then
++ if ! ./${BUNDLE_DIR}/bin/sanityCheck -memlock > /dev/null;
++ then
++ echo ""
++ echo "!!! WARNING !!! - You are not allowed to lock memory."
++ echo ""
++ echo "We will not attempt to fix this. Please configure your system to allow"
++ echo "non-root users to execute lock memory."
++ echo ""
++ read -p "Press ENTER to continue:" BLAH
++ fi
++ fi
++fi
++
++
++########################
++# Install Complete
++########################
++
++echo ""
++echo "Cleaning up"
++rm -rf ${BUNDLE_DIR}/
++
++echo ""
++echo "!!! Install Complete !!!"
++
++if [ "t" = $USER_GROUP_ADJUSTED ];
++then
++ echo "You will need to logout and then login again for all changes to be complete"
++fi
++
++echo ""
++read -p "Press ENTER to exit installer:" BLAH
++
++
+--- /dev/null
++++ b/tools/linux_packaging/uninstall.sh.in
+@@ -0,0 +1,84 @@
++#!/bin/sh
++
++######################################
++#
++# Ardour/Mixbus bundle uninstaller
++# Todd Naugle
++#
++#####################################
++
++
++PGM_NAME="%REPLACE_PGM%"
++PGM_VENDOR="%REPLACE_VENDOR%"
++PGM_VERSION="%REPLACE_VERSION%"
++PGM_BUILD="%REPLACE_BUILD%"
++
++INSTALL_DEST_BASE=/opt
++
++
++#### Derived Variables ####
++PGM_PATH=${INSTALL_DEST_BASE}/${PGM_NAME}-${PGM_VERSION}_${PGM_BUILD}
++
++ICON_NAME="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}" #no dash between name and version since seperates vendor from program
++MENU_FILE="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}.desktop" #no dash between name and version since seperates vendor from program
++DESKTOP_LINK_FILE="${PGM_NAME}_${PGM_VERSION}.desktop"
++MENU_FILE_PATH="${PGM_PATH}/share/${MENU_FILE}"
++
++
++#######################
++# Check for xdg utils
++#######################
++HAS_XDG="T"
++
++XDG_MENU_VER=$(xdg-desktop-menu --version 2> /dev/null)
++if [ -z "$XDG_MENU_VER" ];
++then
++ echo "System does not have xdg-desktop-menu installed"
++ HAS_XDG="F"
++fi
++
++XDG_ICON_VER=$(xdg-icon-resource --version 2> /dev/null)
++if [ -z "$XDG_ICON_VER" ];
++then
++ echo "System does not have xdg-icon-resource installed"
++ HAS_XDG="F"
++fi
++
++
++#############
++# Uninstall
++#############
++
++if [ -d ${PGM_PATH} ];
++then
++ echo ""
++ echo "Removing existing ${PGM_NAME} installation at ${PGM_PATH}"
++ echo ""
++
++ if [ "T" = ${HAS_XDG} ];
++ then
++ sudo xdg-desktop-menu uninstall ${MENU_FILE_PATH}
++ sudo xdg-icon-resource uninstall --size 16 ${ICON_NAME}
++ sudo xdg-icon-resource uninstall --size 22 ${ICON_NAME}
++ sudo xdg-icon-resource uninstall --size 32 ${ICON_NAME}
++ sudo xdg-icon-resource uninstall --size 48 ${ICON_NAME}
++
++ if [ -e /usr/share/icons/hicolor/scalable/apps/${ICON_NAME}.svg ];
++ then
++ sudo rm -f /usr/share/icons/hicolor/scalable/apps/${ICON_NAME}.svg
++ fi
++ fi
++
++ if [ -e ~/Desktop/${DESKTOP_LINK_FILE} ];
++ then
++ sudo rm -f ~/Desktop/${DESKTOP_LINK_FILE}
++ fi
++
++ # delete the old package
++ sudo rm -rf ${PGM_PATH}
++ sudo rm -f $0
++else
++ echo ""
++ echo "!!! FAILURE !!! - install path ${PGM_PATH} does not exist."
++ echo ""
++fi
+--- /dev/null
++++ b/tools/sanity_check/main.cpp
+@@ -0,0 +1,359 @@
++/*
++ *
++ * program: sanityCheck
++ * file: main.c
++ * author: Todd Naugle
++ * date: 11/17/2010
++ *
++ * Desc: Command line version of the sanity check functions found in jack
++*/
++
++#include <algorithm>
++#include <stdio.h>
++#include <string>
++#include <vector>
++
++#include "systemtest.h"
++
++
++using namespace std;
++
++typedef int (*testfuncPtr) ();
++typedef int (*testfuncOpPtr) (string);
++
++typedef struct
++{
++ string switchText; // ie -option
++ string swOptionText; // option arguments for just this swtich.
++ string descriptionText; // Help Text on what this does
++ string failureText; // What to say when this test fails
++ bool hasOption; // Set true if this switch has option paramters
++ testfuncPtr functionPtr; // Function to call
++ testfuncOpPtr opFunctionPtr; // Function with option string to call
++ string optionArg; // Storage used to hold any options passed in by the user
++} testRecord;
++
++static vector<testRecord> gTestSet;
++
++static vector<string> gValidSwitchList;
++static vector<string> gSwitchDescriptionList;
++
++static vector<string> gSwitchesReceived;
++
++int
++ExecuteAll()
++{
++ bool OK = true;
++
++ OK &= system_user_can_rtprio();
++
++ if (system_has_frequencyscaling()) {
++ OK &= !system_uses_frequencyscaling();
++ }
++
++ OK &= !(system_memlock_amount() == 0);
++
++ return OK;
++}
++
++int
++HasGroup(string name)
++{
++ return system_has_group(name.c_str());
++}
++
++int
++IsMemberOfGroup(string name)
++{
++ return system_user_in_group(name.c_str());
++}
++
++int
++CheckFreqScaling()
++{
++ bool OK = true;
++
++ if (system_has_frequencyscaling()) {
++ OK &= !system_uses_frequencyscaling();
++ }
++
++ return OK;
++}
++
++int
++CheckMemoryLocking()
++{
++ return !(system_memlock_amount() == 0);
++}
++
++int
++PrintUsage()
++{
++ printf("\n");
++ printf(" sanityCheck - A program to verify proper system settings for use with audio applications (Ardour/Jack/Mixbus).\n");
++ printf("\n");
++ printf(" Usage: sanityCheck [OPTIONS]\n");
++ printf("\n");
++ printf(" Options are as follows:\n");
++ printf("\n");
++ printf("\n");
++
++ vector<testRecord>::iterator itr;
++
++ for (itr = gTestSet.begin(); itr != gTestSet.end(); ++itr) {
++ printf("%20s %s :\t%s\n", (*itr).switchText.c_str(), (*itr).swOptionText.c_str(), (*itr).descriptionText.c_str());
++ }
++
++ printf("\n");
++
++ return true;
++}
++
++void
++DefineSwitches()
++{
++ testRecord rec;
++
++ // Global switches
++ rec.switchText = "-a";
++ rec.swOptionText = "";
++ rec.descriptionText = "Checks for a working RT system. Same as -rt -freqscaling -memlock";
++ rec.failureText = "";
++ rec.hasOption = false;
++ rec.functionPtr = &ExecuteAll;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ rec.switchText = "-h";
++ rec.swOptionText = "";
++ rec.descriptionText = "Print usage";
++ rec.failureText = "";
++ rec.hasOption = false;
++ rec.functionPtr = &PrintUsage;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ // Switches for various tests that can be performed.
++ rec.switchText = "-rt";
++ rec.swOptionText = "";
++ rec.descriptionText = "Verfiy that the user can run tasks with realtime priority";
++ rec.failureText = "";
++ rec.hasOption = false;
++ rec.functionPtr = &system_user_can_rtprio;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ rec.switchText = "-hasrtlimits";
++ rec.swOptionText = "";
++ rec.descriptionText = "Verfiy the system has a limits.conf and the audio group can use realtime";
++ rec.failureText = "";
++ rec.hasOption = false;
++ rec.functionPtr = &system_has_rtprio_limits_conf;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ rec.switchText = "-hasgroup";
++ rec.swOptionText = "<groupname>";
++ rec.descriptionText = "Verfiy that the system has a group named <groupname>";
++ rec.failureText = "";
++ rec.hasOption = true;
++ rec.opFunctionPtr = &HasGroup;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ rec.switchText = "-hasaudiogroup";
++ rec.swOptionText = "";
++ rec.descriptionText = "Verfiy that the system has an audio group (audio or jackuser) defined";
++ rec.failureText = "";
++ rec.hasOption = false;
++ rec.functionPtr = &system_has_audiogroup;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ rec.switchText = "-memberofgroup";
++ rec.swOptionText = "<groupname>";
++ rec.descriptionText = "Verfiy that the user is a member of the group named <groupname>";
++ rec.failureText = "";
++ rec.hasOption = true;
++ rec.opFunctionPtr = &IsMemberOfGroup;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ rec.switchText = "-memberaudiogroup";
++ rec.swOptionText = "";
++ rec.descriptionText = "Verfiy that the user is a member of the audio group (audio or jackuser)";
++ rec.failureText = "";
++ rec.hasOption = false;
++ rec.functionPtr = &system_user_in_audiogroup;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ rec.switchText = "-freqscaling";
++ rec.swOptionText = "";
++ rec.descriptionText = "Check to see if frequency scaling is being used by the CPU";
++ rec.failureText = "";
++ rec.hasOption = false;
++ rec.functionPtr = &CheckFreqScaling;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++ rec.switchText = "-memlock";
++ rec.swOptionText = "";
++ rec.descriptionText = "Check to see if the user is able to lock memory";
++ rec.failureText = "";
++ rec.hasOption = false;
++ rec.functionPtr = &CheckMemoryLocking;
++ rec.optionArg = "";
++ gTestSet.push_back(rec);
++
++}
++
++bool
++ParseSwitches(
++ int argc,
++ char **argv)
++{
++ string tmp;
++ vector<testRecord>::iterator itr;
++ bool OK = true;
++ int i;
++
++ if (argc == 1) {
++ gSwitchesReceived.push_back("-a");
++ }
++ else {
++ for (i = 1; i < argc && OK == true; i++) {
++ tmp = argv[i];
++
++ for (itr = gTestSet.begin(); itr != gTestSet.end(); ++itr) {
++ if (tmp == (*itr).switchText) {
++ if ((*itr).hasOption == true) {
++ if (++i < argc) {
++ string op = argv[i];
++ if (op[0] == '-') {
++ // reqiured option for this switch is missing
++ --i;
++ OK = false;
++ break;
++ }
++ (*itr).optionArg = op;
++ break;
++ }
++ else {
++ // reqiured option for this switch is missing
++ --i;
++ OK = false;
++ break;
++ }
++ }
++ break;
++ }
++ }
++
++ if (OK && itr != gTestSet.end()) {
++ // Known option switch found
++ gSwitchesReceived.push_back(tmp);
++ }
++ else {
++ // Unknown option
++ OK = false;
++ }
++ }
++ }
++
++ if (OK) {
++ // All switches are at least valid, now check to make sure they are all valid to
++ // be used together.
++
++ if (gSwitchesReceived.size() > 1) {
++ // make sure help is not mixed with other options
++ vector<string>::iterator swItr;
++ tmp = "-h";
++
++ swItr = find(gSwitchesReceived.begin(), gSwitchesReceived.end(), tmp);
++
++ if (swItr != gSwitchesReceived.end()) {
++ gSwitchesReceived.clear();
++ gSwitchesReceived.push_back("-h");
++ }
++
++ // make sure -a is only used by itself
++ tmp = "-a";
++ swItr = find(gSwitchesReceived.begin(), gSwitchesReceived.end(), tmp);
++
++ if (swItr != gSwitchesReceived.end()) {
++ gSwitchesReceived.clear();
++ gSwitchesReceived.push_back("-a");
++ }
++ }
++
++ return true;
++ }
++ else {
++ fprintf(stderr, "\n");
++ fprintf(stderr, "ERROR - Invalid Option: %s\n", (const char *) argv[--i]);
++ fprintf(stderr, "Check syntax\n");
++ PrintUsage();
++ return false;
++ }
++}
++
++bool
++Execute()
++{
++ bool OK = true;
++ vector<string>::iterator itr;
++ vector<testRecord>::iterator testItr;
++
++ for (itr = gSwitchesReceived.begin(); itr != gSwitchesReceived.end(); ++itr) {
++ for (testItr = gTestSet.begin(); testItr != gTestSet.end(); ++testItr) {
++ if ((*itr) == (*testItr).switchText) {
++ break;
++ }
++ }
++
++ bool result;
++ if ((*testItr).hasOption) {
++ result = ((*testItr).opFunctionPtr((*testItr).optionArg) != 0);
++ }
++ else {
++ result = ((*testItr).functionPtr() != 0);
++ }
++
++ if (result == 0) {
++ // Check for a Failure message and print it if found.
++ if (!(*testItr).failureText.empty()) {
++ printf("\n%s\n", (*testItr).failureText.c_str());
++ }
++ }
++
++ OK &= result;
++ }
++
++ return OK;
++}
++
++int
++main(
++ int argc,
++ char **argv)
++{
++ int status = 0;
++
++ DefineSwitches();
++
++ if (ParseSwitches(argc, argv)) {
++ if (Execute() == false) {
++ printf("\nSanity Check Failed!\n\n");
++ status = -1;
++ }
++ else {
++ printf("\nSanity Check OK!\n\n");
++ }
++ }
++ else {
++ status = -1;
++ }
++
++ return status;
++}
+--- /dev/null
++++ b/tools/sanity_check/SConscript
+@@ -0,0 +1,12 @@
++# -*- python -*-
++
++import os
++import os.path
++import glob
++
++Import('env')
++sanitycheck = env.Clone()
++sc = sanitycheck.Program('sanityCheck', ['main.cpp', 'systemtest.cpp'])
++
++Default(sc)
++
+--- /dev/null
++++ b/tools/sanity_check/systemtest.cpp
+@@ -0,0 +1,333 @@
++/**
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Set of functions to gather system information for the jack setup wizard.
++ *
++ * TODO: Test for rt prio availability
++ *
++ * @author Florian Faber, faber at faberman.de
++ *
++ **/
++
++/** maximum number of groups a user can be a member of **/
++#define MAX_GROUPS 100
++
++#include <fcntl.h>
++
++#include <stdlib.h>
++#include <sys/types.h>
++#include <unistd.h>
++#include <grp.h>
++
++#include <sched.h>
++#include <string.h>
++
++#include <sys/time.h>
++#include <sys/resource.h>
++
++#include <stdio.h>
++#include <errno.h>
++
++#include "systemtest.h"
++
++/**
++ * This function checks for the existence of known frequency scaling mechanisms
++ * in this system by testing for the availability of scaling governors/
++ *
++ * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise.
++ **/
++int system_has_frequencyscaling() {
++ int fd;
++
++ fd = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors", O_RDONLY);
++
++ if (-1==fd) {
++ return 0;
++ }
++
++ (void) close(fd);
++
++ return 1;
++}
++
++
++static int read_string(char* filename, char* buf, size_t buflen) {
++ int fd;
++ ssize_t r=-1;
++
++ memset (buf, 0, buflen);
++
++ fd = open (filename, O_RDONLY);
++ if (-1<fd) {
++ r = read (fd, buf, buflen-1);
++ (void) close(fd);
++
++ if (-1==r) {
++ fprintf(stderr, "Error while reading \"%s\": %s\n", filename, strerror(errno));
++ exit(EXIT_FAILURE);
++ }
++ }
++
++ return (int) r;
++}
++
++
++static int read_int(char* filename, int* value) {
++ char buf[20];
++
++ if (0<read_string(filename, buf, 20)) {
++ return (1==sscanf(buf, "%d", value));
++ }
++
++ return 0;
++}
++
++
++/**
++ * This function determines wether any CPU core uses a variable clock speed if frequency
++ * scaling is available. If the governor for all cores is either "powersave" or
++ * "performance", the CPU frequency can be assumed to be static. This is also the case
++ * if scaling_min_freq and scaling_max_freq are set to the same value.
++ *
++ * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise
++ **/
++int system_uses_frequencyscaling() {
++ int cpu=0, done=0, min, max;
++ char filename[256], buf[256];
++
++ while (!done) {
++ (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu);
++ if (0<read_string(filename, buf, 256)) {
++ if ((0!=strncmp("performance", buf, 11)) &&
++ (0!=strncmp("powersafe", buf, 9))) {
++ // So it's neither the "performance" nor the "powersafe" governor
++ (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
++ if (read_int(filename, &min)) {
++ (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
++ if (read_int(filename, &max)) {
++ if (min!=max) {
++ // wrong governor AND different frequency limits -> scaling
++ return 1;
++ }
++ }
++ }
++ }
++ } else {
++ // couldn't open file -> no more cores
++ done = 1;
++ }
++ cpu++;
++ }
++
++ // couldn't find anything that points to scaling
++ return 0;
++}
++
++
++static gid_t get_group_by_name(const char* name) {
++ struct group* grp;
++ gid_t res = 0;
++
++ while ((0==res) && (NULL != (grp = getgrent()))) {
++ if (0==strcmp(name, grp->gr_name)) {
++ res = grp->gr_gid;
++ }
++ }
++
++ endgrent();
++
++ return res;
++}
++
++/**
++ * Tests wether the owner of this process is in the group 'name'.
++ *
++ * @returns 0 if the owner of this process is not in the group, non-0 otherwise
++ **/
++int system_user_in_group(const char *name) {
++ gid_t* list = (gid_t*) malloc(MAX_GROUPS * sizeof(gid_t));
++ int num_groups, i=0, found=0;
++ unsigned int gid;
++
++ if (NULL==list) {
++ perror("Cannot allocate group list structure");
++ exit(EXIT_FAILURE);
++ }
++
++ gid = get_group_by_name(name);
++ if (0==gid) {
++ fprintf(stderr, "No %s group found\n", name);
++ return 0;
++ }
++
++ num_groups = getgroups(MAX_GROUPS, list);
++
++ while (i<num_groups) {
++ if (list[i]==gid) {
++ found = 1;
++ i = num_groups;
++ }
++
++ i++;
++ }
++
++ free(list);
++
++ return found;
++}
++
++
++/***
++ * Checks for a definition in /etc/security/limits.conf that looks
++ * as if it allows RT scheduling priority.
++ *
++ * @returns 1 if there appears to be such a line
++ **/
++int system_has_rtprio_limits_conf ()
++{
++ const char* limits = "/etc/security/limits.conf";
++ char cmd[100];
++
++ snprintf (cmd, sizeof (cmd), "grep -q 'rtprio *[0-9][0-9]*' %s", limits);
++ if (system (cmd) == 0) {
++ return 1;
++ }
++ return 0;
++}
++
++
++/**
++ * Checks for the existence of the 'audio' group on this system
++ *
++ * @returns 0 if there is no 'audio' group, the group id otherwise
++ **/
++int system_has_audiogroup() {
++ return get_group_by_name("audio") || get_group_by_name ("jackuser");
++}
++
++
++/**
++ * Checks for the existence of 'groupname' on this system
++ *
++ * @returns 0 if there is no group, the group id otherwise
++ **/
++int system_has_group(const char * name) {
++ return get_group_by_name(name);
++}
++
++
++/**
++ * Tests wether the owner of this process is in the 'audio' group.
++ *
++ * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise
++ **/
++int system_user_in_audiogroup() {
++ return system_user_in_group("audio") || system_user_in_group("jackuser");
++}
++
++
++/**
++ * Determines wether the owner of this process can enable rt priority.
++ *
++ * @returns 0 if this process can not be switched to rt prio, non-0 otherwise
++ **/
++int system_user_can_rtprio() {
++ int min_prio;
++ struct sched_param schparam;
++
++ memset(&schparam, 0, sizeof(struct sched_param));
++
++ if (-1 == (min_prio = sched_get_priority_min(SCHED_FIFO))) {
++ perror("sched_get_priority");
++ exit(EXIT_FAILURE);
++ }
++ schparam.sched_priority = min_prio;
++
++ if (0 == sched_setscheduler(0, SCHED_FIFO, &schparam)) {
++ // TODO: restore previous state
++ schparam.sched_priority = 0;
++ if (0 != sched_setscheduler(0, SCHED_OTHER, &schparam)) {
++ perror("sched_setscheduler");
++ exit(EXIT_FAILURE);
++ }
++ return 1;
++ }
++
++ return 0;
++}
++
++
++long long unsigned int system_memlock_amount() {
++ struct rlimit limits;
++
++ if (-1==getrlimit(RLIMIT_MEMLOCK, &limits)) {
++ perror("getrlimit on RLIMIT_MEMLOCK");
++ exit(EXIT_FAILURE);
++ }
++
++ return limits.rlim_max;
++}
++
++
++/**
++ * Checks wether the memlock limit is unlimited
++ *
++ * @returns - 0 if the memlock limit is limited, non-0 otherwise
++ **/
++int system_memlock_is_unlimited() {
++ return ((RLIM_INFINITY==system_memlock_amount())?1:0);
++}
++
++
++long long unsigned int system_available_physical_mem() {
++ char buf[256];
++ long long unsigned int res = 0;
++
++ if (0<read_string((char*)"/proc/meminfo", buf, sizeof (buf))) {
++ if (strncmp (buf, "MemTotal:", 9) == 0) {
++ if (sscanf (buf, "%*s %llu", &res) != 1) {
++ perror ("parse error in /proc/meminfo");
++ }
++ }
++ } else {
++ perror("read from /proc/meminfo");
++ }
++
++ return res*1024;
++}
++
++
++/**
++ * Gets the version of the currently running kernel. The string
++ * returned has to be freed by the caller.
++ *
++ * @returns String with the full version of the kernel
++ **/
++char* system_kernel_version() {
++ return NULL;
++}
++
++
++
++char* system_get_username() {
++ char* res = NULL;
++ char* name = NULL;
++
++ if ((name = getlogin())) {
++ res = strdup(name);
++ }
++
++ return res;
++}
+--- /dev/null
++++ b/tools/sanity_check/systemtest.h
+@@ -0,0 +1,109 @@
++#ifndef __systemtest_h__
++#define __systemtest_h__
++
++/**
++ * GPL, yabbadabba
++ *
++ * Set of functions to gather system information for the jack setup wizard.
++ *
++ * @author Florian Faber, faber at faberman.de
++ *
++ * @version 0.1 (2009-01-15) [FF]
++ * - initial version
++ *
++ **/
++
++
++/**
++ * This function checks for the existence of known frequency scaling mechanisms
++ * in this system.
++ *
++ * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise.
++ **/
++int system_has_frequencyscaling();
++
++
++/**
++ * This function determines wether the CPU has a variable clock speed if frequency
++ * scaling is available.
++ *
++ * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise
++ **/
++int system_uses_frequencyscaling();
++
++/**
++ * Tests wether the owner of this process is in the group 'name'.
++ *
++ * @returns 0 if the owner of this process is not in the group, non-0 otherwise
++ **/
++int system_user_in_group(const char *name);
++
++/***
++ * Checks for a definition in /etc/security/limits.conf that looks
++ * as if it allows RT scheduling priority.
++ *
++ * @returns 1 if there appears to be such a line
++ **/
++int system_has_rtprio_limits_conf ();
++
++/**
++ * Checks for the existence of the 'audio' group on this system
++ *
++ * @returns 0 is there is no 'audio' group, non-0 otherwise
++ **/
++int system_has_audiogroup();
++
++/**
++ * Checks for the existence of a group named 'name' on this system
++ *
++ * @returns 0 if not found, non-0 otherwise
++ **/
++int system_has_group(const char * name);
++
++/**
++ * Tests wether the owner of this process is in the 'audio' group.
++ *
++ * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise
++ **/
++int system_user_in_audiogroup();
++
++
++/**
++ * Determines wether the owner of this process can enable rt priority.
++ *
++ * @returns 0 if this process can not be switched to rt prio, non-0 otherwise
++ **/
++int system_user_can_rtprio();
++
++
++long long unsigned int system_memlock_amount();
++
++
++/**
++ * Checks wether the memlock limit is unlimited
++ *
++ * @returns 0 if the memlock limit is limited, non-0 otherwise
++ **/
++int system_memlock_is_unlimited();
++
++
++long long unsigned int system_available_physical_mem();
++
++
++/**
++ * Gets the version of the currently running kernel
++ *
++ * @returns String with the full version of the kernel
++ **/
++char* system_kernel_version();
++
++
++/**
++ * Returns the username. The caller is in charge of disposal of
++ * the returned name.
++ *
++ * @returns Pointer to a username or NULL
++ **/
++char* system_get_username();
++
++#endif /* __jack_systemtest_h__ */
diff --git a/debian/patches/series b/debian/patches/series
index dbcfbc3..2c44822 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
+000_sync_vcs.patch
60-libdir.patch
80_ardourino.patch
90_ardour-x-change.patch
--
ardour Debian packaging
More information about the pkg-multimedia-commits
mailing list