fix merge conflicts from master
authorPaul Davis <paul@linuxaudiosystems.com>
Sat, 24 Aug 2013 16:18:06 +0000 (12:18 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Sat, 24 Aug 2013 16:18:06 +0000 (12:18 -0400)
26 files changed:
1  2 
gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/ardour_ui_dialogs.cc
gtk2_ardour/export_video_dialog.cc
gtk2_ardour/main.cc
gtk2_ardour/midi_tracer.cc
gtk2_ardour/port_matrix.cc
gtk2_ardour/sfdb_ui.cc
gtk2_ardour/transcode_ffmpeg.cc
gtk2_ardour/transcode_video_dialog.cc
gtk2_ardour/video_image_frame.cc
gtk2_ardour/video_server_dialog.cc
gtk2_ardour/wscript
libs/ardour/ardour/session.h
libs/ardour/audio_diskstream.cc
libs/ardour/butler.cc
libs/ardour/globals.cc
libs/ardour/lv2_plugin.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_track.cc
libs/ardour/route.cc
libs/ardour/session_ltc.cc
libs/pbd/pbd/pthread_utils.h
libs/pbd/pthread_utils.cc
libs/pbd/wscript
wscript

diff --combined gtk2_ardour/ardour_ui.cc
index 6de90c15c24943f40c6ac2e53166f9d8dd44fd5a,e3e97d8d94a90b50b9af7998c80c3296b4c7bef2..33f5a5099edcc34b6ad3eeb7ac905701c4deaf2c
  #include <cerrno>
  #include <fstream>
  
 +#ifndef WIN32
 +#include <sys/resource.h>
 +#endif
 +
  #include <stdint.h>
  #include <fcntl.h>
  #include <signal.h>
  #include <unistd.h>
  #include <time.h>
  
 -#include <sys/resource.h>
 -#include <sys/types.h>
 -#include <sys/sysctl.h>
 +#include <glib.h>
 +#include <glib/gstdio.h>
  
  #include <gtkmm/messagedialog.h>
  #include <gtkmm/accelmap.h>
@@@ -51,7 -48,6 +51,7 @@@
  #include "pbd/memento_command.h"
  #include "pbd/openuri.h"
  #include "pbd/file_utils.h"
 +#include "pbd/localtime_r.h"
  
  #include "gtkmm2ext/application.h"
  #include "gtkmm2ext/bindings.h"
@@@ -186,6 -182,7 +186,7 @@@ ARDOUR_UI::ARDOUR_UI (int *argcp, char 
        , feedback_alert_button (_("feedback"))
  
        , editor_meter(0)
+       , editor_meter_peak_display()
  
        , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
        , theme_manager (X_("theme-manager"), _("Theme Manager"))
  
        /* and ambiguous files */
  
 -      ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
 +      ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
  
        /* lets get this party started */
  
-       try {
-               if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization, localedir)) {
-                       throw failed_constructor ();
-               }
-               setup_gtk_ardour_enums ();
-               setup_profile ();
-               SessionEvent::create_per_thread_pool ("GUI", 512);
+       setup_gtk_ardour_enums ();
+       setup_profile ();
  
-       } catch (failed_constructor& err) {
-               error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
-               // pass it on up
-               throw;
-       }
+       SessionEvent::create_per_thread_pool ("GUI", 512);
  
        /* we like keyboards */
  
@@@ -782,7 -768,7 +772,7 @@@ ARDOUR_UI::no_memory_warning (
  void
  ARDOUR_UI::check_memory_locking ()
  {
 -#ifdef __APPLE__
 +#if defined(__APPLE__) || defined(WIN32)
        /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
        return;
  #else // !__APPLE__
@@@ -1039,8 -1025,14 +1029,14 @@@ ARDOUR_UI::every_point_zero_something_s
        // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
  
        SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
-       if (editor_meter) {
-               editor_meter->update_meters();
+       if (editor_meter && Config->get_show_editor_meter()) {
+               float mpeak = editor_meter->update_meters();
+               if (mpeak > editor_meter_max_peak) {
+                       if (mpeak >= Config->get_meter_peak()) {
+                               editor_meter_peak_display.set_name ("meterbridge peakindicator on");
+                               editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
+                       }
+               }
        }
        return TRUE;
  }
@@@ -3409,23 -3401,15 +3405,23 @@@ ARDOUR_UI::start_video_server (Gtk::Win
                if (icsd_docroot.empty()) {icsd_docroot = X_("/");}
  
                struct stat sb;
 -              if (!lstat (icsd_docroot.c_str(), &sb) == 0 || !S_ISDIR(sb.st_mode)) {
 +              if (!g_lstat (icsd_docroot.c_str(), &sb) == 0 || !S_ISDIR(sb.st_mode)) {
                        warning << _("Specified docroot is not an existing directory.") << endmsg;
                        continue;
                }
 -              if ( (!lstat (icsd_exec.c_str(), &sb) == 0)
 +#ifndef WIN32
 +              if ( (!g_lstat (icsd_exec.c_str(), &sb) == 0)
                     || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
                        warning << _("Given Video Server is not an executable file.") << endmsg;
                        continue;
                }
 +#else
 +              if ( (!g_lstat (icsd_exec.c_str(), &sb) == 0)
 +                   || (sb.st_mode & (S_IXUSR)) == 0 ) {
 +                      warning << _("Given Video Server is not an executable file.") << endmsg;
 +                      continue;
 +              }
 +#endif
  
                char **argp;
                argp=(char**) calloc(9,sizeof(char*));
@@@ -3530,7 -3514,10 +3526,10 @@@ ARDOUR_UI::add_video (Gtk::Window* floa
                                        return;
                                }
                                if (!transcode_video_dialog->get_audiofile().empty()) {
-                                       editor->embed_audio_from_video(transcode_video_dialog->get_audiofile());
+                                       editor->embed_audio_from_video(
+                                                       transcode_video_dialog->get_audiofile(),
+                                                       video_timeline->get_offset()
+                                                       );
                                }
                                switch (transcode_video_dialog->import_option()) {
                                        case VTL_IMPORT_TRANSCODED:
@@@ -3594,6 -3581,10 +3593,10 @@@ ARDOUR_UI::remove_video (
        video_timeline->close_session();
        editor->toggle_ruler_video(false);
  
+       /* reset state */
+       video_timeline->set_offset_locked(false);
+       video_timeline->set_offset(0);
        /* delete session state */
        XMLNode* node = new XMLNode(X_("Videotimeline"));
        _session->add_extra_xml(*node);
@@@ -4069,7 -4060,7 +4072,7 @@@ ARDOUR_UI::missing_file (Session*s, std
  }
  
  int
 -ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
 +ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
  {
        AmbiguousFileDialog dialog (file, hits);
  
@@@ -4138,6 -4129,9 +4141,9 @@@ ARDOUR_UI::reset_peak_display (
  {
        if (!_session || !_session->master_out() || !editor_meter) return;
        editor_meter->clear_meters();
+       editor_meter_max_peak = -INFINITY;
+       editor_meter_peak_display.set_name ("meterbridge peakindicator");
+       editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
  }
  
  void
diff --combined gtk2_ardour/ardour_ui.h
index e2eae369771b98575d3f337f361cfc7022a923c4,6365e28ea282e767ba7b1c199695cf1ce063cb80..15413b5ac9da6bdd8f2bda0e793dd2e29ffda72b
@@@ -451,6 -451,9 +451,9 @@@ class ARDOUR_UI : public Gtkmm2ext::UI
        Gtk::VBox alert_box;
        Gtk::VBox meter_box;
        LevelMeterHBox * editor_meter;
+       float            editor_meter_max_peak;
+       ArdourButton     editor_meter_peak_display;
+       bool             editor_meter_peak_button_release (GdkEventButton*);
  
        void solo_blink (bool);
        void sync_blink (bool);
        void fontconfig_dialog ();
  
          int missing_file (ARDOUR::Session*s, std::string str, ARDOUR::DataType type);
 -        int ambiguous_file (std::string file, std::string path, std::vector<std::string> hits);
 +        int ambiguous_file (std::string file, std::vector<std::string> hits);
  
        bool click_button_clicked (GdkEventButton *);
  
index f5fc16651ae3472486dfff7e12cc0cc7e1e97486,24f6511b4cdd0f7bd8bba5cfeb91f595b9073730..bca762569fa269cef640157399b0c23f57916404
  #include "ardour/audioengine.h"
  #include "ardour/automation_watch.h"
  
 +#ifdef interface
 +#undef interface
 +#endif
 +
  #include "actions.h"
  #include "add_route_dialog.h"
  #include "add_video_dialog.h"
@@@ -57,6 -53,8 +57,8 @@@
  #include "theme_manager.h"
  #include "time_info_box.h"
  
+ #include <gtkmm2ext/keyboard.h>
  #include "i18n.h"
  
  using namespace ARDOUR;
@@@ -196,6 -194,7 +198,7 @@@ ARDOUR_UI::set_session (Session *s
                meter_box.remove(*editor_meter);
                delete editor_meter;
                editor_meter = 0;
+               editor_meter_peak_display.hide();
        }
  
        if (_session && _session->master_out()) {
                editor_meter->clear_meters();
                editor_meter->set_type (_session->master_out()->meter_type());
                editor_meter->setup_meters (30, 12, 6);
+               editor_meter->show();
                meter_box.pack_start(*editor_meter);
  
                ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
                ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
                ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
+               editor_meter_peak_display.set_name ("meterbridge peakindicator");
+               editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
+               editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
+               editor_meter_peak_display.set_size_request(6, -1);
+               editor_meter_peak_display.set_corner_radius(2);
+               editor_meter_max_peak = -INFINITY;
+               editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
+               if (Config->get_show_editor_meter()) {
+                       meter_box.show();
+                       editor_meter_peak_display.show();
+               } else {
+                       meter_box.hide();
+                       editor_meter_peak_display.hide();
+               }
        }
  
  }
@@@ -254,6 -271,7 +275,7 @@@ ARDOUR_UI::unload_session (bool hide_st
                meter_box.remove(*editor_meter);
                delete editor_meter;
                editor_meter = 0;
+               editor_meter_peak_display.hide();
        }
  
        ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
@@@ -528,3 -546,18 +550,18 @@@ ARDOUR_UI::main_window_state_event_hand
  
        return false;
  }
+ bool
+ ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
+ {
+       if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
+               ArdourMeter::ResetAllPeakDisplays ();
+       } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
+               if (_session->master_out()) {
+                       ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
+               }
+       } else if (_session->master_out()) {
+               ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
+       }
+       return true;
+ }
index fafdd7a50da48092df105e3e943f3208606c8a9f,48d09065b71ad4ca2b11c23e5284e9b1360831ec..0234b579015dfbb88439e05753e240be18e8e1bf
@@@ -30,8 -30,6 +30,8 @@@
  #include <sigc++/bind.h>
  #include <libgen.h>
  
 +#include <glib/gstdio.h>
 +
  #include "pbd/error.h"
  #include "pbd/convert.h"
  #include "gtkmm2ext/utils.h"
@@@ -62,6 -60,7 +62,7 @@@ using namespace Gtk
  using namespace std;
  using namespace PBD;
  using namespace ARDOUR;
+ using namespace VideoUtils;
  
  ExportVideoDialog::ExportVideoDialog (PublicEditor& ed, Session* s)
        : ArdourDialog (_("Export Video File "))
        /* check if ffmpeg can be found */
        transcoder = new TranscodeFfmpeg("");
        if (!transcoder->ffexec_ok()) {
-               l = manage (new Label (_("No ffprobe or ffmpeg executables could be found on this system. Video Export is not possible until you install those tools. See the Log widow for more information."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+               l = manage (new Label (_("No ffprobe or ffmpeg executables could be found on this system. Video Export is not possible until you install those tools. See the Log window for more information."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
                l->set_line_wrap();
                vbox->pack_start (*l, false, false, 8);
                get_vbox()->pack_start (*vbox, false, false);
@@@ -407,8 -406,8 +408,8 @@@ voi
  ExportVideoDialog::finished ()
  {
        if (aborted) {
 -              unlink(outfn_path_entry.get_text().c_str());
 -              unlink (insnd.c_str());
 +              ::g_unlink(outfn_path_entry.get_text().c_str());
 +              ::g_unlink (insnd.c_str());
                Gtk::Dialog::response(RESPONSE_CANCEL);
        } else if (twopass && firstpass) {
                firstpass = false;
                if (twopass_checkbox.get_active()) {
                        std::string outfn = outfn_path_entry.get_text();
                        std::string p2log = Glib::path_get_dirname (outfn) + G_DIR_SEPARATOR + "ffmpeg2pass";
 -                      unlink (p2log.c_str());
 +                      ::g_unlink (p2log.c_str());
                }
 -              unlink (insnd.c_str());
 +              ::g_unlink (insnd.c_str());
                Gtk::Dialog::response(RESPONSE_ACCEPT);
        }
  }
@@@ -556,7 -555,7 +557,7 @@@ ExportVideoDialog::launch_export (
        audio_progress_connection.disconnect();
        status->finish ();
        if (status->aborted()) {
 -              unlink (insnd.c_str());
 +              ::g_unlink (insnd.c_str());
                Gtk::Dialog::response(RESPONSE_CANCEL);
                return;
        }
@@@ -573,14 -572,14 +574,14 @@@ ExportVideoDialog::encode_pass (int pas
        transcoder = new TranscodeFfmpeg(invid);
        if (!transcoder->ffexec_ok()) {
                /* ffmpeg binary was not found. TranscodeFfmpeg prints a warning */
 -              unlink (insnd.c_str());
 +              ::g_unlink (insnd.c_str());
                Gtk::Dialog::response(RESPONSE_CANCEL);
                return;
        }
        if (!transcoder->probe_ok()) {
                /* video input file can not be read */
                warning << _("Export Video: Video input file cannot be read.") << endmsg;
 -        unlink (insnd.c_str());
 +        ::g_unlink (insnd.c_str());
          Gtk::Dialog::response(RESPONSE_CANCEL);
          return;
        }
diff --combined gtk2_ardour/main.cc
index ef96423fb58c827bd1197c0574d3ea3f3d1cac40,e619c9d83bcf40caf34d52c02bc89b9ae1da0544..dfa0bda94540a713972721bbb322d29bbd8e4568
@@@ -31,7 -31,6 +31,7 @@@
  #include "pbd/file_utils.h"
  #include "pbd/textreceiver.h"
  #include "pbd/failed_constructor.h"
 +#include "pbd/pathexpand.h"
  #include "pbd/pthread_utils.h"
  #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
  #include "pbd/boost_debug.h"
@@@ -111,7 -110,7 +111,7 @@@ Please consider the possibilities, and 
  static void export_search_path (const string& base_dir, const char* varname, const char* dir)
  {
        string path;
 -      const char * cstr = getenv (varname);
 +      const char * cstr = g_getenv (varname);
  
        if (cstr) {
                path = cstr;
        path += base_dir;
        path += dir;
  
 -      setenv (varname, path.c_str(), 1);
 +      g_setenv (varname, path.c_str(), 1);
  }
  
  #ifdef __APPLE__
@@@ -135,7 -134,7 +135,7 @@@ extern void set_language_preference ()
  void
  fixup_bundle_environment (int, char* [])
  {
 -      if (!getenv ("ARDOUR_BUNDLED")) {
 +      if (!g_getenv ("ARDOUR_BUNDLED")) {
                return;
        }
  
        export_search_path (bundle_dir, "SUIL_MODULE_DIR", "/lib");
        export_search_path (bundle_dir, "GTK_PATH", "/lib/gtkengines");
  
 -      setenv ("PATH", (bundle_dir + "/MacOS:" + std::string(getenv ("PATH"))).c_str(), 1);
 +      g_setenv ("PATH", (bundle_dir + "/MacOS:" + std::string(getenv ("PATH"))).c_str(), 1);
  
        /* unset GTK_RC_FILES so that we only load the RC files that we define
         */
  
 -      unsetenv ("GTK_RC_FILES");
 +      g_unsetenv ("GTK_RC_FILES");
  
        /* write a pango.rc file and tell pango to use it. we'd love
           to put this into the PROGRAM_NAME.app bundle and leave it there,
                                << endl;
                        pangorc.close ();
                        
 -                      setenv ("PANGO_RC_FILE", path.c_str(), 1);
 +                      g_setenv ("PANGO_RC_FILE", path.c_str(), 1);
                }
        }
        
 -      setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
 -      setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
 -      setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (bundle_dir, "Resources/gdk-pixbuf.loaders").c_str(), 1);
 +      g_setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
 +      g_setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
 +      g_setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (bundle_dir, "Resources/gdk-pixbuf.loaders").c_str(), 1);
  }
  
  static void load_custom_fonts() {
@@@ -259,7 -258,7 +259,7 @@@ fixup_bundle_environment (int /*argc*/
         * acceptable to build paths directly using '/'.
         */
  
 -      if (!getenv ("ARDOUR_BUNDLED")) {
 +      if (!g_getenv ("ARDOUR_BUNDLED")) {
                return;
        }
  
                lpath.push_back (dir_path);
                lpath.push_back ("share");
                lpath.push_back ("locale");
 -              localedir = realpath (Glib::build_filename (lpath).c_str(), NULL);
 +              localedir = canonical_path (Glib::build_filename (lpath)).c_str();
        }
  #endif
  
        export_search_path (dir_path, "SUIL_MODULE_DIR", "/lib");
        export_search_path (dir_path, "GTK_PATH", "/lib/gtkengines");
  
 -      setenv ("PATH", (dir_path + "/bin:" + std::string(getenv ("PATH"))).c_str(), 1);
 +      g_setenv ("PATH", (dir_path + "/bin:" + std::string(getenv ("PATH"))).c_str(), 1);
  
        /* unset GTK_RC_FILES so that we only load the RC files that we define
         */
  
 -      unsetenv ("GTK_RC_FILES");
 +      g_unsetenv ("GTK_RC_FILES");
  
        /* Tell fontconfig where to find fonts.conf. Use the system version
           if it exists, otherwise use the stuff we included in the bundle
        */
  
        if (Glib::file_test ("/etc/fonts/fonts.conf", Glib::FILE_TEST_EXISTS)) {
 -              setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
 -              setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
 +              g_setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
 +              g_setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
        } else {
                error << _("No fontconfig file found on your system. Things may looked very odd or ugly") << endmsg;
        }
                        pangorc.close ();
                }
                
 -              setenv ("PANGO_RC_FILE", path.c_str(), 1);
 +              g_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.
                */
                
 -              setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders").c_str(), 1);
 +              g_setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders").c_str(), 1);
        }
  
          /* this doesn't do much but setting it should prevent various parts of the GTK/GNU stack
             from looking outside the bundle to find the charset.alias file.
          */
 -        setenv ("CHARSETALIASDIR", dir_path.c_str(), 1);
 +        g_setenv ("CHARSETALIASDIR", dir_path.c_str(), 1);
  
  }
  
@@@ -474,7 -473,7 +474,7 @@@ int main (int argc, char *argv[]
        text_receiver.listen_to (warning);
  
  #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
 -      if (getenv ("BOOST_DEBUG")) {
 +      if (g_getenv ("BOOST_DEBUG")) {
                boost_debug_shared_ptr_show_live_debugging (true);
        }
  #endif
                exit (1);
        }
  
-       if (curvetest_file) {
-               return curvetest (curvetest_file);
-       }
        cout << PROGRAM_NAME
             << VERSIONSTRING
             << _(" (built using ")
  
        /* some GUI objects need this */
  
-       PBD::ID::init ();
+       if (!ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization, localedir)) {
+               error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
+               exit (1);
+       }
+       if (curvetest_file) {
+               return curvetest (curvetest_file);
+       }
  
 +#ifndef WIN32
        if (::signal (SIGPIPE, sigpipe_handler)) {
                cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
        }
 +#endif
  
        try {
                ui = new ARDOUR_UI (&argc, &argv, localedir);
index e0deb6dce8da84b973547b5441f4a76db1b1cae5,073fd9cc15a86870ccb373ec5d1fe025a64b2b27..c4fe76252b32a1f8b957267d4ec0348d2c9bc0ca
@@@ -23,9 -23,6 +23,9 @@@
  #include <sys/time.h>
  #include <time.h>
  
 +#include "pbd/localtime_r.h"
 +#include "pbd/timersub.h"
 +
  #include "midi++/parser.h"
  #include "midi++/manager.h"
  
@@@ -306,8 -303,7 +306,7 @@@ MidiTracer::tracer (Parser&, byte* msg
                } else if (len == 3 && msg[0] == MIDI::position) {
  
                        /* MIDI Song Position */
-                       uint16_t midi_beats = (uint16_t) msg[1];
-                       midi_beats |= msg[2];
+                       int midi_beats = (msg[2] << 7) | msg[1];
                        s += snprintf (&buf[s], bufsize, "%16s %d\n", "Position", (int) midi_beats);
                } else {
  
index 5c21d7ff2506c4b6cac73b80e81289baf71131c1,2872ad66051cdecf6facbafee2200dcf01510333..e8108555e6f552d71e9aab673824aae42236291b
@@@ -336,6 -336,13 +336,13 @@@ PortMatrix::select_arrangement (
                _vbox.pack_end (_vnotebook, false, false);
                _vbox.pack_end (_vspacer, true, true);
  
+ #define REMOVE_FROM_GTK_PARENT(WGT) if ((WGT).get_parent()) { (WGT).get_parent()->remove(WGT);}
+               REMOVE_FROM_GTK_PARENT(*_body)
+               REMOVE_FROM_GTK_PARENT(_vscroll)
+               REMOVE_FROM_GTK_PARENT(_hscroll)
+               REMOVE_FROM_GTK_PARENT(_vbox)
+               REMOVE_FROM_GTK_PARENT(_hbox)
                attach (*_body, 2, 3, 1, 2, FILL | EXPAND, FILL | EXPAND);
                attach (_vscroll, 3, 4, 1, 2, SHRINK);
                attach (_hscroll, 2, 3, 3, 4, FILL | EXPAND, SHRINK);
                _vbox.pack_end (_vnotebook, false, false);
                _vbox.pack_end (_vlabel, false, false);
  
+               REMOVE_FROM_GTK_PARENT(*_body)
+               REMOVE_FROM_GTK_PARENT(_vscroll)
+               REMOVE_FROM_GTK_PARENT(_hscroll)
+               REMOVE_FROM_GTK_PARENT(_vbox)
+               REMOVE_FROM_GTK_PARENT(_hbox)
                attach (*_body, 1, 2, 2, 3, FILL | EXPAND, FILL | EXPAND);
                attach (_vscroll, 3, 4, 2, 3, SHRINK);
                attach (_hscroll, 1, 2, 3, 4, FILL | EXPAND, SHRINK);
@@@ -514,7 -527,7 +527,7 @@@ PortMatrix::popup_menu (BundleChannel c
        items.push_back (MenuElem (_("Rescan"), sigc::mem_fun (*this, &PortMatrix::setup_all_ports)));
  
        items.push_back (CheckMenuElem (_("Show individual ports"), sigc::mem_fun (*this, &PortMatrix::toggle_show_only_bundles)));
 -      CheckMenuItem* i = dynamic_cast<CheckMenuItem*> (&items.back());
 +      Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
        _inhibit_toggle_show_only_bundles = true;
        i->set_active (!_show_only_bundles);
        _inhibit_toggle_show_only_bundles = false;
@@@ -733,7 -746,7 +746,7 @@@ PortMatrix::remove_channel (ARDOUR::Bun
                        int const r = io->remove_port (p, this);
                        if (r == -1) {
                                ArdourDialog d (_("Port removal not allowed"));
-                               Label l (_("This port cannot be removed, as the first plugin in the track or buss cannot accept the new number of inputs."));
+                               Label l (_("This port cannot be removed.\nEither the first plugin in the track or buss cannot accept\nthe new number of inputs or the last plugin has more outputs."));
                                d.get_vbox()->pack_start (l);
                                d.add_button (Stock::OK, RESPONSE_ACCEPT);
                                d.set_modal (true);
diff --combined gtk2_ardour/sfdb_ui.cc
index bf2b90355fc5e4c408a963beb46ae693336ae5f8,5f8564374ef20d25ba298289b5a879eb89d167f0..2640af8379e440c0b1691c59ea19a93977bc6665
@@@ -31,8 -31,6 +31,8 @@@
  
  #include <gtkmm/box.h>
  #include <gtkmm/stock.h>
 +
 +#include <glib/gstdio.h>
  #include <glibmm/fileutils.h>
  
  #include "pbd/convert.h"
@@@ -66,9 -64,7 +66,7 @@@
  #include "main_clock.h"
  #include "public_editor.h"
  
- #ifdef FREESOUND
  #include "sfdb_freesound_mootcher.h"
- #endif
  
  #include "i18n.h"
  
@@@ -518,8 -514,6 +516,6 @@@ SoundFileBrowser::SoundFileBrowser (str
        
        notebook.append_page (*vbox, _("Search Tags"));
  
- #ifdef FREESOUND
        //add freesound search
  
        HBox* passbox;
        freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
        freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
        notebook.append_page (*vbox, _("Search Freesound"));
- #endif
  
        notebook.set_size_request (500, -1);
        notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
@@@ -1151,7 -1144,6 +1146,6 @@@ SoundFileBrowser::get_paths (
                        results.push_back (str);
                }
        } else {
- #ifdef FREESOUND
                ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
                for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
                        string str = freesound_get_audio_file (freesound_list->get_iter(*i));
                                results.push_back (str);
                        }
                }
- #endif
        }
  
        return results;
@@@ -1466,9 -1457,6 +1459,9 @@@ SoundFileOmega::check_info (const vecto
  bool
  SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
  {
 +#ifdef WIN32
 +      return false;
 +#else
        std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
        bool ret = false;
  
                        goto out;
                }
  
 -              unlink (tmpc);
 +              ::g_unlink (tmpc);
        }
  
        ret = true;
    out:
        rmdir (tmpdir.c_str());
        return ret;
 +#endif
  }
  
  SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
index aedd7d25ebc44cbaa8612203ccd7b99748bf9313,ea753104dbaf9d887aaac1634503d31cf53e7d13..0a7bf64ecdaee452026d4decf425f47a0bbfdb40
  
  #include "i18n.h"
  
 +#ifdef SearchPath
 +#undef SearchPath
 +#endif
 +
  using namespace PBD;
+ using namespace VideoUtils;
  
  TranscodeFfmpeg::TranscodeFfmpeg (std::string f)
        : infile(f)
@@@ -127,7 -124,7 +128,7 @@@ TranscodeFfmpeg::probe (
         * SystemExec::Terminated is emitted and ffcmd set to NULL */
        int timeout = 300; // 1.5 sec
        while (ffcmd && --timeout > 0) {
 -              usleep(5000);
 +              Glib::usleep(5000);
        }
        if (timeout == 0 || ffoutput.empty()) {
                return false;
@@@ -508,11 -505,7 +509,11 @@@ TranscodeFfmpeg::cancel (
  {
        if (!ffcmd || !ffcmd->is_running()) { return;}
        ffcmd->write_to_stdin("q");
 +#ifdef WIN32
 +      Sleep(1000);
 +#else
        sleep (1);
 +#endif
        if (ffcmd) {
          ffcmd->terminate();
        }
index 2a4e05f076cbb7ff20d35fb174c4003f20209d85,d4ad8a24ed9a2bd3acf73642aea892bf8b6ec8c6..9f18e85b64880e1002d43ae5cb7edf8cb6479a50
@@@ -30,8 -30,6 +30,8 @@@
  #include <sigc++/bind.h>
  #include <libgen.h>
  
 +#include <glib/gstdio.h>
 +
  #include "pbd/error.h"
  #include "pbd/convert.h"
  #include "gtkmm2ext/utils.h"
@@@ -52,6 -50,7 +52,7 @@@ using namespace Gtk
  using namespace std;
  using namespace PBD;
  using namespace ARDOUR;
+ using namespace VideoUtils;
  
  TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
        : ArdourDialog (_("Transcode/Import Video File "))
  
        bool ffok = false;
        if (!transcoder->ffexec_ok()) {
-               l = manage (new Label (_("No ffprobe or ffmpeg executables could be found on this system. Video Import is not possible until you install those tools. See the Log widow for more information."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+               l = manage (new Label (_("No ffprobe or ffmpeg executables could be found on this system. Video Import is not possible until you install those tools. See the Log window for more information."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
                l->set_line_wrap();
                options_box->pack_start (*l, false, true, 4);
                aspect_checkbox.set_sensitive(false);
@@@ -303,9 -302,9 +304,9 @@@ voi
  TranscodeVideoDialog::finished ()
  {
        if (aborted) {
 -              unlink(path_entry.get_text().c_str());
 +              ::g_unlink(path_entry.get_text().c_str());
                if (!audiofile.empty()) {
 -                      unlink(audiofile.c_str());
 +                      ::g_unlink(audiofile.c_str());
                }
                Gtk::Dialog::response(RESPONSE_CANCEL);
        } else {
index 310f3a68d3080a0c28cee394f12f517ca71387ca,38a7a5994f5c74007ffafcfcc77d5b4ea83b79d5..864aca4bb98175386997f3b2b54e391b5c4fcec7
@@@ -36,6 -36,7 +36,7 @@@
  
  using namespace std;
  using namespace ARDOUR;
+ using namespace VideoUtils;
  
  VideoImageFrame::VideoImageFrame (PublicEditor& ed, ArdourCanvas::Group& parent, int w, int h, std::string vsurl, std::string vfn)
        : editor (ed)
@@@ -196,8 -197,8 +197,8 @@@ http_get_thread (void *arg) 
        int timeout = 1000; // * 5ms -> 5sec
        char *res = NULL;
        do {
-               res=curl_http_get(url, &status);
-               if (status == 503) Glib::usleep(5000); // try-again
+               res=a3_curl_http_get(url, &status);
+               if (status == 503) usleep(5000); // try-again
        } while (status == 503 && --timeout > 0);
  
        if (status != 200 || !res) {
@@@ -246,7 -247,7 +247,7 @@@ VideoImageFrame::http_download_done (ch
  
        exposeimg();
        /* don't request frames too quickly, wait after user has zoomed */
 -      usleep(40000);
 +      Glib::usleep(40000);
  
        if (queued_request) {
                http_get_again(want_video_frame_number);
index ce0633b6c3af382caafba860f3b8f932146d3a6c,811c00f64f19405df90e6ae54ef51fc136bc1319..7948908b87eff5413845edf79f70401bf675752f
  #include "ardour/template_utils.h"
  #include "ardour/session.h"
  
 +#ifdef interface
 +#undef interface
 +#endif
 +
  #include "video_server_dialog.h"
  #include "utils_videotl.h"
  #include "i18n.h"
  
 +#ifdef SearchPath
 +#undef SearchPath
 +#endif
 +
  using namespace Gtk;
  using namespace std;
  using namespace PBD;
  using namespace ARDOUR;
+ using namespace VideoUtils;
  
  VideoServerDialog::VideoServerDialog (Session* s)
        : ArdourDialog (_("Launch Video Server"))
diff --combined gtk2_ardour/wscript
index 429b8c2dbde46f7dbabaaafdd6804ce9f889a8e7,4cc9b40cdb1133378252553bd993e331a72aed35..12681cfe2d723aef4e427bfc1bdc5955ebb97b1c
@@@ -103,6 -103,7 +103,7 @@@ gtk2_ardour_sources = 
          'fft.cc',
          'fft_graph.cc',
          'fft_result.cc',
+         'sfdb_freesound_mootcher.cc',
          'gain_meter.cc',
          'generic_pluginui.cc',
          'ghostregion.cc',
@@@ -266,9 -267,8 +267,9 @@@ def configure(conf)
          'gtk2_ardour', conf.env['MAJOR'], conf.env['MINOR'], 0)
      autowaf.configure(conf)
  
 -    if re.search ("linux", sys.platform) != None:
 -        autowaf.check_pkg(conf, 'alsa', uselib_store='ALSA')
 +    if Options.options.dist_target == 'auto':
 +        if re.search ("linux", sys.platform) != None:
 +            autowaf.check_pkg(conf, 'alsa', uselib_store='ALSA')
  
      # TODO: Insert a sanity check for on OS X to ensure CoreAudio is present
  
@@@ -419,9 -419,6 +420,9 @@@ def build(bld)
                           'libardour_cp',
                           'libgtkmm2ext',
                           'libtaglib' ]
 +    if bld.env['build_target'] == 'mingw':
 +      if bld.env['DEBUG'] == False:
 +            obj.linkflags = ['-mwindows']
      if sys.platform == 'darwin':
          obj.use += ' libappleutility'
      obj.defines     = [
          obj.source += [ 'lv2_plugin_ui.cc' ]
          obj.use += [ 'SUIL' ]
  
-     if bld.is_defined('FREESOUND'):
-         obj.source +=  [ 'sfdb_freesound_mootcher.cc' ]
-         obj.defines += [ 'FREESOUND' ]
      if bld.is_defined('NEED_INTL'):
          obj.linkflags = ' -lintl'
  
index 1044d9a2dc59c8fbba71764e8520e824201e48a1,efe51e7b499b172e526289a5daf33689e09c7f60..525dfbd84961b0878a03d4f78b1a45886f439e94
@@@ -822,7 -822,7 +822,7 @@@ class Session : public PBD::StatefulDes
        void request_resume_timecode_transmission ();
        bool timecode_transmission_suspended () const;
  
 -      std::string source_search_path(DataType) const;
 +      std::vector<std::string> source_search_path(DataType) const;
        void ensure_search_path_includes (const std::string& path, DataType type);
  
        std::list<std::string> unknown_processors () const;
        double            ltc_enc_cnt;
        framepos_t        ltc_enc_off;
        bool              restarting;
+       framepos_t        ltc_prev_cycle;
  
        framepos_t        ltc_timecode_offset;
        bool              ltc_timecode_negative_offset;
index 7bfc9426cd56e86bd5a7279c8914e20b29f61c2d,b9ce987c876ae50243ea59fea63eed7ee4ec4715..622a42edf2e935765cfa4714ab87da02125bbd36
@@@ -27,6 -27,8 +27,6 @@@
  #include <fcntl.h>
  #include <cstdlib>
  #include <ctime>
 -#include <sys/stat.h>
 -#include <sys/mman.h>
  
  #include "pbd/error.h"
  #include "pbd/xml++.h"
@@@ -698,6 -700,31 +698,31 @@@ AudioDiskstream::process (BufferSet& bu
        return 0;
  }
  
+ frameoffset_t
+ AudioDiskstream::calculate_playback_distance (pframes_t nframes)
+ {
+       frameoffset_t playback_distance = nframes;
+       if (record_enabled()) {
+               playback_distance = nframes;
+       } else if (_actual_speed != 1.0f && _actual_speed != -1.0f) {
+               interpolation.set_speed (_target_speed);
+               boost::shared_ptr<ChannelList> c = channels.reader();
+               int channel = 0;
+               for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) {
+                       playback_distance = interpolation.interpolate (channel, nframes, NULL, NULL);
+               }
+       } else {
+               playback_distance = nframes;
+       }
+       if (_actual_speed < 0.0) {
+               return -playback_distance;
+       } else {
+               return playback_distance;
+       }
+ }
  /** Update various things including playback_sample, read pointer on each channel's playback_buf
   *  and write pointer on each channel's capture_buf.  Also wout whether the butler is needed.
   *  @return true if the butler is required.
@@@ -898,7 -925,7 +923,7 @@@ AudioDiskstream::internal_playback_see
        boost::shared_ptr<ChannelList> c = channels.reader();
  
        for (chan = c->begin(); chan != c->end(); ++chan) {
-               (*chan)->playback_buf->increment_read_ptr (distance);
+               (*chan)->playback_buf->increment_read_ptr (llabs(distance));
        }
  
        if (first_recordable_frame < max_framepos) {
diff --combined libs/ardour/butler.cc
index 747dfcd575dc164c02ee04b29b896871bfad035e,89b2cc1303cab4ac04b852427517400383c14930..1fe15246183c89575782e5e4f505c562bcbf6bb7
  #include <errno.h>
  #include <fcntl.h>
  #include <unistd.h>
 +
 +#ifndef PLATFORM_WINDOWS
  #include <poll.h>
 +#endif
 +
  #include "pbd/error.h"
  #include "pbd/pthread_utils.h"
  #include "ardour/butler.h"
@@@ -42,7 -38,7 +42,7 @@@ namespace ARDOUR 
  
  Butler::Butler(Session& s)
        : SessionHandleRef (s)
 -      , thread(0)
 +      , thread()
        , audio_dstream_capture_buffer_size(0)
        , audio_dstream_playback_buffer_size(0)
        , midi_dstream_buffer_size(0)
@@@ -72,10 -68,25 +72,10 @@@ Butler::config_changed (std::string p
          }
  }
  
 +#ifndef PLATFORM_WINDOWS
  int
 -Butler::start_thread()
 +Butler::setup_request_pipe ()
  {
 -      const float rate = (float)_session.frame_rate();
 -
 -      /* size is in Samples, not bytes */
 -      audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * rate);
 -      audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * rate);
 -
 -      /* size is in bytes
 -       * XXX: Jack needs to tell us the MIDI buffer size
 -       * (i.e. how many MIDI bytes we might see in a cycle)
 -       */
 -      midi_dstream_buffer_size = (uint32_t) floor (Config->get_midi_track_buffer_seconds() * rate);
 -
 -      MidiDiskstream::set_readahead_frames ((framecnt_t) (Config->get_midi_readahead() * rate));
 -
 -      should_run = false;
 -
        if (pipe (request_pipe)) {
                error << string_compose(_("Cannot create transport request signal pipe (%1)"),
                                strerror (errno)) << endmsg;
                                strerror (errno)) << endmsg;
                return -1;
        }
 +      return 0;
 +}
 +#endif
 +
 +int
 +Butler::start_thread()
 +{
 +      const float rate = (float)_session.frame_rate();
 +
 +      /* size is in Samples, not bytes */
 +      audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * rate);
 +      audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * rate);
 +
 +      /* size is in bytes
 +       * XXX: Jack needs to tell us the MIDI buffer size
 +       * (i.e. how many MIDI bytes we might see in a cycle)
 +       */
 +      midi_dstream_buffer_size = (uint32_t) floor (Config->get_midi_track_buffer_seconds() * rate);
 +
 +      MidiDiskstream::set_readahead_frames ((framecnt_t) (Config->get_midi_readahead() * rate));
 +
 +      should_run = false;
 +
 +#ifndef PLATFORM_WINDOWS
 +      if (setup_request_pipe() != 0) return -1;
 +#endif
  
        if (pthread_create_and_store ("disk butler", &thread, _thread_work, this)) {
                error << _("Session: could not create butler thread") << endmsg;
  void
  Butler::terminate_thread ()
  {
 -      if (thread) {
 -              void* status;
 -              const char c = Request::Quit;
 -              (void) ::write (request_pipe[1], &c, 1);
 -              pthread_join (thread, &status);
 -      }
 +      void* status;
 +      queue_request (Request::Quit);
 +      pthread_join (thread, &status);
  }
  
  void *
@@@ -146,25 -134,28 +146,25 @@@ Butler::_thread_work (void* arg
        return ((Butler *) arg)->thread_work ();
  }
  
 -void *
 -Butler::thread_work ()
 +bool
 +Butler::wait_for_requests ()
  {
 -      uint32_t err = 0;
 -
 +#ifndef PLATFORM_WINDOWS
        struct pollfd pfd[1];
 -      bool disk_work_outstanding = false;
 -      RouteList::iterator i;
  
 -      while (true) {
 -              pfd[0].fd = request_pipe[0];
 -              pfd[0].events = POLLIN|POLLERR|POLLHUP;
 +      pfd[0].fd = request_pipe[0];
 +      pfd[0].events = POLLIN|POLLERR|POLLHUP;
  
 -              if (poll (pfd, 1, (disk_work_outstanding ? 0 : -1)) < 0) {
 +      while(true) {
 +              if (poll (pfd, 1, -1) < 0) {
  
                        if (errno == EINTR) {
                                continue;
                        }
  
                        error << string_compose (_("poll on butler request pipe failed (%1)"),
 -                                        strerror (errno))
 -                            << endmsg;
 +                                      strerror (errno))
 +                              << endmsg;
                        break;
                }
  
                }
  
                if (pfd[0].revents & POLLIN) {
 +                      return true;
 +              }
 +      }
 +      return false;
 +#else
 +      m_request_sem.wait ();
 +      return true;
 +#endif
 +}
  
 -                      char req;
 +bool
 +Butler::dequeue_request (Request::Type& r)
 +{
 +#ifndef PLATFORM_WINDOWS
 +      char req;
 +      size_t nread = ::read (request_pipe[0], &req, sizeof (req));
 +      if (nread == 1) {
 +              r = (Request::Type) req;
 +              return true;
 +      } else if (nread == 0) {
 +              return false;
 +      } else if (errno == EAGAIN) {
 +              return false;
 +      } else {
 +              fatal << _("Error reading from butler request pipe") << endmsg;
 +              /*NOTREACHED*/
 +      }
 +#else
 +      r = (Request::Type) m_request_state.get();
 +#endif
 +      return false;
 +}
  
 -                      /* empty the pipe of all current requests */
 +      void *
 +Butler::thread_work ()
 +{
 +      uint32_t err = 0;
  
 -                      while (1) {
 -                              size_t nread = ::read (request_pipe[0], &req, sizeof (req));
 -                              if (nread == 1) {
 +      bool disk_work_outstanding = false;
 +      RouteList::iterator i;
  
 -                                      switch ((Request::Type) req) {
 +      while (true) {
 +              if(!disk_work_outstanding) {
 +                      if (wait_for_requests ()) {
 +                              Request::Type req;
 +
 +                              /* empty the pipe of all current requests */
 +#ifdef PLATFORM_WINDOWS
 +                              dequeue_request (req);
 +                              {
 +#else
 +                              while(dequeue_request(req)) {
 +#endif
 +                                      switch (req) {
  
                                        case Request::Run:
                                                should_run = true;
                                                break;
  
                                        case Request::Quit:
-                                               pthread_exit_pbd (0);
+                                               return 0;
                                                /*NOTREACHED*/
                                                break;
  
                                        default:
                                                break;
                                        }
 -
 -                              } else if (nread == 0) {
 -                                      break;
 -                              } else if (errno == EAGAIN) {
 -                                      break;
 -                              } else {
 -                                      fatal << _("Error reading from butler request pipe") << endmsg;
 -                                      /*NOTREACHED*/
                                }
                        }
                }
@@@ -372,8 -327,6 +372,6 @@@ restart
                empty_pool_trash ();
        }
  
-       pthread_exit_pbd (0);
-       /*NOTREACHED*/
        return (0);
  }
  
@@@ -385,28 -338,18 +383,28 @@@ Butler::schedule_transport_work (
  }
  
  void
 -Butler::summon ()
 +Butler::queue_request (Request::Type r)
  {
 -      char c = Request::Run;
 +#ifndef PLATFORM_WINDOWS
 +      char c = r;
        (void) ::write (request_pipe[1], &c, 1);
 +#else
 +      m_request_state.set (r);
 +      m_request_sem.post ();
 +#endif
 +}
 +
 +void
 +Butler::summon ()
 +{
 +      queue_request (Request::Run);
  }
  
  void
  Butler::stop ()
  {
        Glib::Threads::Mutex::Lock lm (request_lock);
 -      char c = Request::Pause;
 -      (void) ::write (request_pipe[1], &c, 1);
 +      queue_request (Request::Pause);
        paused.wait(request_lock);
  }
  
@@@ -414,7 -357,8 +412,7 @@@ voi
  Butler::wait_until_finished ()
  {
        Glib::Threads::Mutex::Lock lm (request_lock);
 -      char c = Request::Pause;
 -      (void) ::write (request_pipe[1], &c, 1);
 +      queue_request (Request::Pause);
        paused.wait(request_lock);
  }
  
@@@ -457,6 -401,7 +455,7 @@@ Butler::empty_pool_trash (
  void
  Butler::drop_references ()
  {
+       cerr << "Butler drops pool trash\n";
        SessionEvent::pool->set_trash (0);
  }
  
diff --combined libs/ardour/globals.cc
index 57b1e2db65b14f42b4caf49c936a27a472f26676,986d320aef5d7ec9aa61fc52768b9323c9562ab3..f4cc81a2607de06570e057e09ef7195a377e92c2
  #include "libardour-config.h"
  #endif
  
 +#ifdef interface
 +#undef interface
 +#endif
 +
  #include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
  #include <cstdlib>
  #include <sys/stat.h>
  #include <sys/types.h>
  #include <sys/time.h>
 +#ifndef PLATFORM_WINDOWS
  #include <sys/resource.h>
 +#endif
  #include <unistd.h>
  #include <fcntl.h>
  #include <errno.h>
@@@ -48,7 -42,7 +48,7 @@@
  #include "ardour/audio_unit.h"
  #endif
  
 -#ifdef __SSE__
 +#if defined(__SSE__) || defined(USE_XMMINTRIN)
  #include <xmmintrin.h>
  #endif
  
  #undef check /* stupid Apple and their un-namespaced, generic Carbon macros */
  #endif 
  
- #include <giomm.h>
  #include <glibmm/fileutils.h>
  #include <glibmm/miscutils.h>
  
 +#ifdef HAVE_LRDF
  #include <lrdf.h>
 +#endif
  
  #include "pbd/cpus.h"
  #include "pbd/error.h"
  #include "pbd/id.h"
+ #include "pbd/pbd.h"
  #include "pbd/strsplit.h"
  #include "pbd/fpu.h"
  #include "pbd/file_utils.h"
@@@ -115,6 -106,8 +114,8 @@@ using namespace ARDOUR
  using namespace std;
  using namespace PBD;
  
+ bool libardour_initialized = false;
  compute_peak_t          ARDOUR::compute_peak = 0;
  find_peaks_t            ARDOUR::find_peaks = 0;
  apply_gain_to_buffer_t  ARDOUR::apply_gain_to_buffer = 0;
@@@ -201,7 -194,6 +202,7 @@@ setup_hardware_optimization (bool try_o
  static void
  lotsa_files_please ()
  {
 +#ifndef PLATFORM_WINDOWS
        struct rlimit rl;
  
        if (getrlimit (RLIMIT_NOFILE, &rl) == 0) {
        } else {
                error << string_compose (_("Could not get system open files limit (%1)"), strerror (errno)) << endmsg;
        }
 +#endif
  }
  
- int
+ bool
  ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
  {
-       if (!Glib::thread_supported()) {
-               Glib::thread_init();
+       if (libardour_initialized) {
+               return true;
        }
  
-       // this really should be in PBD::init..if there was one
-       Gio::init ();
+       if (!PBD::init()) return false;
  
  #ifdef ENABLE_NLS
        (void) bindtextdomain(PACKAGE, localedir);
  #endif
  
-       PBD::ID::init ();
        SessionEvent::init_event_pool ();
  
        SessionObject::make_property_quarks ();
        // allow ardour the absolute maximum number of open files
        lotsa_files_please ();
  
 +#ifdef HAVE_LRDF
        lrdf_init();
 +#endif
        Library = new AudioLibrary;
  
        BootMessage (_("Loading configuration"));
        Config = new RCConfiguration;
  
        if (Config->load_state ()) {
-               return -1;
+               return false;
        }
  
        Config->set_use_windows_vst (use_windows_vst);
  
  #ifdef WINDOWS_VST_SUPPORT
        if (Config->get_use_windows_vst() && fst_init (0)) {
-               return -1;
+               return false;
        }
  #endif
  
  #ifdef LXVST_SUPPORT
        if (Config->get_use_lxvst() && vstfx_init (0)) {
-               return -1;
+               return false;
        }
  #endif
  
        EventTypeMap::instance().new_parameter(EnvelopeAutomation);
        EventTypeMap::instance().new_parameter(MidiCCAutomation);
  
-       return 0;
+       libardour_initialized = true;
+       return true;
  }
  
  void
@@@ -368,9 -357,7 +369,9 @@@ in
  ARDOUR::cleanup ()
  {
        delete Library;
 +#ifdef HAVE_LRDF
        lrdf_cleanup ();
 +#endif
        delete &ControlProtocolManager::instance();
  #ifdef WINDOWS_VST_SUPPORT
        fst_exit ();
  #ifdef LXVST_SUPPORT
        vstfx_exit();
  #endif
-       EnumWriter::destroy ();
+       PBD::cleanup ();
        return 0;
  }
  
index 4ae1c7b4524a61e6635d1af18e27e8ee252f2042,484965e8f45b645c75a9e6f4bade84f968d146c5..fc8630d59b79c5aeafa6f261321d42a2da340391
@@@ -25,7 -25,6 +25,7 @@@
  #include <cstdlib>
  #include <cstring>
  
 +#include <glib/gstdio.h>
  #include <giomm/file.h>
  #include <glib/gprintf.h>
  #include <glibmm.h>
@@@ -1091,7 -1090,7 +1091,7 @@@ LV2Plugin::do_remove_preset(string name
                        name + ".ttl"
                )
        );
 -      unlink(preset_file.c_str());
 +      ::g_unlink(preset_file.c_str());
  }
  
  bool
@@@ -1119,16 -1118,16 +1119,16 @@@ LV2Plugin::write_to(RingBuffer<uint8_t>
                      uint32_t             size,
                      const uint8_t*       body)
  {
 -      const uint32_t buf_size = sizeof(UIMessage) + size;
 -      uint8_t        buf[buf_size];
 +      const uint32_t  buf_size = sizeof(UIMessage) + size;
 +      vector<uint8_t> buf(buf_size);
  
 -      UIMessage* msg = (UIMessage*)buf;
 +      UIMessage* msg = (UIMessage*)&buf[0];
        msg->index    = index;
        msg->protocol = protocol;
        msg->size     = size;
        memcpy(msg + 1, body, size);
  
 -      return (dest->write(buf, buf_size) == buf_size);
 +      return (dest->write(&buf[0], buf_size) == buf_size);
  }
  
  bool
@@@ -1138,8 -1137,20 +1138,20 @@@ LV2Plugin::write_from_ui(uint32_
                           const uint8_t* body)
  {
        if (!_from_ui) {
-               _from_ui = new RingBuffer<uint8_t>(
-                       _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS);
+               size_t rbs = _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS;
+               /* buffer data communication from plugin UI to plugin instance.
+                * this buffer needs to potentially hold
+                *   (port's minimumSize) * (audio-periods) / (UI-periods)
+                * bytes.
+                *
+                *  e.g 48kSPS / 128fpp -> audio-periods = 375 Hz
+                *  ui-periods = 25 Hz (SuperRapidScreenUpdate)
+                *  default minimumSize = 32K (see LV2Plugin::allocate_atom_event_buffers()
+                *  -> 15 * 32K
+                * it is safe to overflow (but the plugin state may be inconsistent).
+                */
+               rbs = max((size_t) 32768 * 6, rbs);
+               _from_ui = new RingBuffer<uint8_t>(rbs);
        }
  
        if (!write_to(_from_ui, index, protocol, size, body)) {
  LV2Plugin::enable_ui_emmission()
  {
        if (!_to_ui) {
-               _to_ui = new RingBuffer<uint8_t>(
-                       _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS);
+               /* see note in LV2Plugin::write_from_ui() */
+               size_t rbs = _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS;
+               rbs = max((size_t) 32768 * 8, rbs);
+               _to_ui = new RingBuffer<uint8_t>(rbs);
        }
  }
  
@@@ -1185,13 -1198,13 +1199,13 @@@ LV2Plugin::emit_to_ui(void* controller
                        error << "Error reading from Plugin=>UI RingBuffer" << endmsg;
                        break;
                }
 -              uint8_t body[msg.size];
 -              if (_to_ui->read(body, msg.size) != msg.size) {
 +              vector<uint8_t> body(msg.size);
 +              if (_to_ui->read(&body[0], msg.size) != msg.size) {
                        error << "Error reading from Plugin=>UI RingBuffer" << endmsg;
                        break;
                }
  
 -              sink(controller, msg.index, msg.size, msg.protocol, body);
 +              sink(controller, msg.index, msg.size, msg.protocol, &body[0]);
  
                read_space -= sizeof(msg) + msg.size;
        }
@@@ -1354,11 -1367,6 +1368,6 @@@ LV2Plugin::describe_parameter(Evoral::P
                        return X_("hidden");
                }
  
-               if (lilv_port_has_property(_impl->plugin,
-                                       lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.lv2_sampleRate)) {
-                       return X_("hidden");
-               }
                if (lilv_port_has_property(_impl->plugin,
                                        lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.lv2_reportsLatency)) {
                        return X_("latency");
@@@ -1671,15 -1679,15 +1680,15 @@@ LV2Plugin::connect_and_run(BufferSet& b
                                error << "Error reading from UI=>Plugin RingBuffer" << endmsg;
                                break;
                        }
 -                      uint8_t body[msg.size];
 -                      if (_from_ui->read(body, msg.size) != msg.size) {
 +                      vector<uint8_t> body(msg.size);
 +                      if (_from_ui->read(&body[0], msg.size) != msg.size) {
                                error << "Error reading from UI=>Plugin RingBuffer" << endmsg;
                                break;
                        }
                        if (msg.protocol == urids.atom_eventTransfer) {
                                LV2_Evbuf*            buf  = _ev_buffers[msg.index];
                                LV2_Evbuf_Iterator    i    = lv2_evbuf_end(buf);
 -                              const LV2_Atom* const atom = (const LV2_Atom*)body;
 +                              const LV2_Atom* const atom = (const LV2_Atom*)&body[0];
                                if (!lv2_evbuf_write(&i, nframes, 0, atom->type, atom->size,
                                                (const uint8_t*)(atom + 1))) {
                                        error << "Failed to write data to LV2 event buffer\n";
@@@ -1902,7 -1910,7 +1911,7 @@@ LV2Plugin::Impl::designated_input (cons
        return port;
  }
  
- static bool lv2_filter (const string& str, void *arg)
+ static bool lv2_filter (const string& str, void * /* arg*/)
  {
        /* Not a dotfile, has a prefix before a period, suffix is "lv2" */
        
@@@ -1983,7 -1991,7 +1992,7 @@@ LV2World::load_bundled_plugins(
                vector<string *> *plugin_objects = scanner (ARDOUR::lv2_bundled_search_path().to_string(), lv2_filter, 0, true, true);
                if (plugin_objects) {
                        for ( vector<string *>::iterator x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
 -#ifdef WINDOWS
 +#ifdef PLATFORM_WINDOWS
                                string uri = "file:///" + **x + "/";
  #else
                                string uri = "file://" + **x + "/";
index d27c2fa9c75f44b3c49f386c196f3f24ebfded45,489a84e477cbea5708768d80b6f5535db8579e90..cf143bf59506e8896afcb7937bff88d8218e65ce
  #include <fcntl.h>
  #include <cstdlib>
  #include <ctime>
 -#include <strings.h> // for ffs(3)
  #include <sys/stat.h>
 -#include <sys/mman.h>
  
  #include "pbd/error.h"
 +#include "pbd/ffs.h"
  #include "pbd/basename.h"
  #include <glibmm/threads.h>
  #include "pbd/xml++.h"
@@@ -438,7 -439,7 +438,7 @@@ MidiDiskstream::process (BufferSet& buf
                                break;
                        case ForceChannel:
                                if (ev.is_channel_event()) {
 -                                      ev.set_channel (ffs(mask) - 1);
 +                                      ev.set_channel (PBD::ffs(mask) - 1);
                                }
                                _capture_buf->write(transport_frame + loop_offset + ev.time(),
                                                    ev.type(), ev.size(), ev.buffer());
        return 0;
  }
  
+ frameoffset_t
+ MidiDiskstream::calculate_playback_distance (pframes_t nframes)
+ {
+       frameoffset_t playback_distance = nframes;
+       /* XXX: should be doing varispeed stuff once it's implemented in ::process() above */
+       if (_actual_speed < 0.0) {
+               return -playback_distance;
+       } else {
+               return playback_distance;
+       }
+ }
  bool
  MidiDiskstream::commit (framecnt_t playback_distance)
  {
index 6e193c3c099eb6aa56e1215d0fd024d9530e5356,f88c331c2ca8a0e7b171b7f1a4aea9a5f9ac7ba9..6a998de90e42b1c1565a3fbf938b4dcd03836ab6
@@@ -17,7 -17,8 +17,7 @@@
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  
 -#include <strings.h> // for ffs(3)
 -
 +#include "pbd/ffs.h"
  #include "pbd/enumwriter.h"
  #include "pbd/convert.h"
  #include "evoral/midi_util.h"
@@@ -318,6 -319,12 +318,12 @@@ MidiTrack::roll (pframes_t nframes, fra
  {
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
        if (!lm.locked()) {
+               boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
+               framecnt_t playback_distance = diskstream->calculate_playback_distance(nframes);
+               if (can_internal_playback_seek(llabs(playback_distance))) {
+                       /* TODO should declick, and/or note-off */
+                       internal_playback_seek(playback_distance);
+               }
                return 0;
        }
  
@@@ -506,7 -513,7 +512,7 @@@ MidiTrack::filter_channels (BufferSet& 
                                }
                                break;
                        case ForceChannel:
 -                              ev.set_channel (ffs (mask) - 1);
 +                              ev.set_channel (PBD::ffs (mask) - 1);
                                ++e;
                                break;
                        case AllChannels:
@@@ -626,9 -633,9 +632,9 @@@ voi
  MidiTrack::MidiControl::set_value(double val)
  {
        bool valid = false;
 -      if (std::isinf(val)) {
 +      if (isinf(val)) {
                cerr << "MIDIControl value is infinity" << endl;
 -      } else if (std::isnan(val)) {
 +      } else if (isnan(val)) {
                cerr << "MIDIControl value is NaN" << endl;
        } else if (val < _list->parameter().min()) {
                cerr << "MIDIControl value is < " << _list->parameter().min() << endl;
diff --combined libs/ardour/route.cc
index bb25c1f9b0a0ceb5341ed568ff02d4158233bcb0,2e1517fe21a0307452e87f359f433335031c6cc7..232f295df68c5147c0e941b429452bcca7de2f4a
@@@ -98,6 -98,7 +98,7 @@@ Route::Route (Session& sess, string nam
        , _default_type (default_type)
        , _remote_control_id (0)
        , _in_configure_processors (false)
+       , _initial_io_setup (false)
        , _custom_meter_position_noted (false)
        , _last_custom_meter_was_at_end (false)
  {
@@@ -136,6 -137,7 +137,7 @@@ Route::init (
        _input->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::input_port_count_changing, this, _1));
  
        _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
+       _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1));
  
        /* add amp processor  */
  
@@@ -1614,9 -1616,7 +1616,9 @@@ Route::reset_instrument_info (
  int
  Route::configure_processors (ProcessorStreams* err)
  {
 +#ifndef PLATFORM_WINDOWS
        assert (!AudioEngine::instance()->process_lock().trylock());
 +#endif
  
        if (!_in_configure_processors) {
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
@@@ -1687,9 -1687,7 +1689,9 @@@ Route::try_configure_processors_unlocke
  int
  Route::configure_processors_unlocked (ProcessorStreams* err)
  {
 +#ifndef PLATFORM_WINDOWS
        assert (!AudioEngine::instance()->process_lock().trylock());
 +#endif
  
        if (_in_configure_processors) {
                return 0;
        }
  
        ChanCount out;
+       bool seen_mains_out = false;
+       processor_out_streams = _input->n_ports();
+       processor_max_streams.reset();
  
        list< pair<ChanCount,ChanCount> >::iterator c = configuration.begin();
        for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) {
                processor_max_streams = ChanCount::max(processor_max_streams, c->first);
                processor_max_streams = ChanCount::max(processor_max_streams, c->second);
                out = c->second;
+               if (boost::dynamic_pointer_cast<Delivery> (*p)
+                               && boost::dynamic_pointer_cast<Delivery> (*p)->role() == Delivery::Main) {
+                       /* main delivery will increase port count to match input.
+                        * the Delivery::Main is usually the last processor - followed only by
+                        * 'MeterOutput'.
+                        */
+                       seen_mains_out = true;
+               }
+               if (!seen_mains_out) {
+                       processor_out_streams = out;
+               }
        }
  
        if (_meter) {
                _meter->reset_max_channels (processor_max_streams);
        }
@@@ -1999,6 -2013,7 +2017,7 @@@ Route::set_state (const XMLNode& node, 
        }
  
        set_id (node);
+       _initial_io_setup = true;
  
        if ((prop = node.property (X_("flags"))) != 0) {
                _flags = Flag (string_2_enum (prop->value(), _flags));
                _meter_type = MeterType (string_2_enum (prop->value (), _meter_type));
        }
  
+       _initial_io_setup = false;
        set_processor_state (processor_state);
  
        // this looks up the internal instrument in processors
@@@ -2833,7 -2850,7 +2854,7 @@@ Route::feeds (boost::shared_ptr<Route> 
  {
        const FedBy& fed_by (other->fed_by());
  
 -      for (FedBy::iterator f = fed_by.begin(); f != fed_by.end(); ++f) {
 +      for (FedBy::const_iterator f = fed_by.begin(); f != fed_by.end(); ++f) {
                boost::shared_ptr<Route> sr = f->r.lock();
  
                if (sr && (sr.get() == this)) {
@@@ -2946,6 -2963,9 +2967,9 @@@ voi
  Route::output_change_handler (IOChange change, void * /*src*/)
  {
        bool need_to_queue_solo_change = true;
+       if (_initial_io_setup) {
+               return;
+       }
  
        if ((change.type & IOChange::ConfigurationChanged)) {
                /* This is called with the process lock held if change 
@@@ -3758,6 -3778,19 +3782,19 @@@ Route::input_port_count_changing (ChanC
        return false;
  }
  
+ /** Called when there is a proposed change to the output port count */
+ bool
+ Route::output_port_count_changing (ChanCount to)
+ {
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               if (processor_out_streams.get(*t) > to.get(*t)) {
+                       return true;
+               }
+       }
+       /* The change is ok */
+       return false;
+ }
  list<string>
  Route::unknown_processors () const
  {
index daf7c2c78e921bf2611a507bd5ddecbbe3904dd9,d6cc201a5c40e53126169be375d7e70fb3150359..2671bfccf40b6b9589460ef74a9433f2ef5a3eca
@@@ -31,6 -31,7 +31,6 @@@
  
  using namespace std;
  using namespace ARDOUR;
 -using namespace MIDI;
  using namespace PBD;
  using namespace Timecode;
  
@@@ -81,6 -82,7 +81,7 @@@ Session::ltc_tx_initialize(
         * since the fps can change and A3's  min fps: 24000/1001 */
        ltc_enc_buf = (ltcsnd_sample_t*) calloc((nominal_frame_rate() / 23), sizeof(ltcsnd_sample_t));
        ltc_speed = 0;
+       ltc_prev_cycle = -1;
        ltc_tx_reset();
        ltc_tx_resync_latency();
        Xrun.connect_same_thread (*this, boost::bind (&Session::ltc_tx_reset, this));
@@@ -131,6 -133,7 +132,7 @@@ Session::ltc_tx_parse_offset() 
        offset_tc.drop = timecode_drop_frames();
        timecode_to_sample(offset_tc, ltc_timecode_offset, false, false);
        ltc_timecode_negative_offset = !offset_tc.negative;
+       ltc_prev_cycle = -1;
  }
  
  void
@@@ -213,7 -216,7 +215,7 @@@ Session::ltc_tx_send_time_code_for_cycl
        if (cur_timecode != ltc_enc_tcformat) {
                DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX1: TC format mismatch - reinit sr: %1 fps: %2\n", nominal_frame_rate(), timecode_to_frames_per_second(cur_timecode)));
                if (ltc_encoder_reinit(ltc_encoder, nominal_frame_rate(),
-                                       timecode_to_frames_per_second(cur_timecode), 
+                                       timecode_to_frames_per_second(cur_timecode),
                                        TV_STANDARD(cur_timecode), 0
                                        )) {
                        PBD::error << _("LTC encoder: invalid framerate - LTC encoding is disabled for the remainder of this session.") << endmsg;
         * The _generated timecode_ is offset by the port-latency,
         * therefore the offset depends on the direction of transport.
         */
-       framepos_t cycle_start_frame = (current_speed < 0) ? (start_frame - ltc_out_latency.max) : (start_frame + ltc_out_latency.max);
+       framepos_t cycle_start_frame;
+       if (current_speed < 0) {
+               cycle_start_frame = (start_frame - ltc_out_latency.max);
+       } else if (current_speed > 0) {
+               cycle_start_frame = (start_frame + ltc_out_latency.max);
+       } else {
+               /* There is no need to compensate for latency when not rolling
+                * rather send the accurate NOW timecode
+                * (LTC encoder compenates latency by sending earlier timecode)
+                */
+               cycle_start_frame = start_frame;
+       }
  
        /* LTC TV standard offset */
-       cycle_start_frame -= ltc_frame_alignment(frames_per_timecode_frame(), TV_STANDARD(cur_timecode));
+       if (current_speed != 0) {
+               /* ditto - send "NOW" if not rolling */
+               cycle_start_frame -= ltc_frame_alignment(frames_per_timecode_frame(), TV_STANDARD(cur_timecode));
+       }
  
        /* cycle-start may become negative due to latency compensation */
        if (cycle_start_frame < 0) { cycle_start_frame = 0; }
                ltc_tx_reset();
        }
  
-       if (ltc_speed != new_ltc_speed) {
+       if (ltc_speed != new_ltc_speed
+                       /* but only once if, current_speed changes to 0. In that case
+                        * new_ltc_speed is > 0 because (end_frame - start_frame) == jack-period for no-roll
+                        * but ltc_speed will still be 0
+                        */
+                       && (current_speed != 0 || ltc_speed != current_speed)
+                       ) {
                /* check ./libs/ardour/interpolation.cc  CubicInterpolation::interpolate
                 * if target_speed != current_speed we should interpolate, too.
                 *
                 * end_frame is calculated from 'frames_moved' which includes the interpolation.
                 * so we're good.
                 */
-               DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX2: speed change old: %1 cur: %2 tgt: %3 ctd: %4\n", ltc_speed, current_speed, target_speed, fabs(current_speed) - target_speed));
+               DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX2: speed change old: %1 cur: %2 tgt: %3 ctd: %4\n", ltc_speed, current_speed, target_speed, fabs(current_speed) - target_speed, new_ltc_speed));
                speed_changed = true;
                ltc_encoder_set_filter(ltc_encoder, LTC_RISE_TIME(new_ltc_speed));
        }
                        ltc_speed = new_ltc_speed;
                        return;
                }
+               if (start_frame != ltc_prev_cycle) {
+                       DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX2: no-roll seek from %1 to %2 (%3)\n", ltc_prev_cycle, start_frame, cycle_start_frame));
+                       ltc_tx_reset();
+               }
        }
  
        if (fabs(new_ltc_speed) > 10.0) {
                }
        }
  
+       ltc_prev_cycle = start_frame;
        ltc_speed = new_ltc_speed;
        DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX2: transport speed %1.\n", ltc_speed));
  
  
        /* difference between current frame and TC frame in samples */
        frameoffset_t soff = cycle_start_frame - tc_sample_start;
+       if (current_speed == 0) {
+               soff = 0;
+       }
        DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX3: A3cycle: %1 = A3tc: %2 +off: %3\n",
                                cycle_start_frame, tc_sample_start, soff));
  
  
                DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX4: now: %1 trs: %2 toff %3\n", cycle_start_frame, tc_sample_start, soff));
  
-               uint32_t cyc_off;
+               int32_t cyc_off;
                if (soff < 0 || soff >= fptcf) {
                        /* session framerate change between (2) and now */
                        ltc_tx_reset();
                        restarting = true;
                }
  
-               if (cyc_off > 0 && cyc_off <= nframes) {
+               if (cyc_off >= 0 && cyc_off <= (int32_t) nframes) {
                        /* offset in this cycle */
                        txf= rint(cyc_off / fabs(ltc_speed));
                        memset(out, 0, cyc_off * sizeof(Sample));
index 3d89d5581e1e226231cc37a544bfb7a3e7308236,0c7b5f3ac142b458b68456dacdde73cb15205956..f57833941004c7560486437be75110f96701c6f9
  #ifndef __pbd_pthread_utils__
  #define __pbd_pthread_utils__
  
 +#ifdef COMPILER_MSVC
 +#include <ardourext/pthread.h>
 +#else
  #include <pthread.h>
 +#endif
  #include <signal.h>
  #include <string>
  #include <stdint.h>
@@@ -35,7 -31,6 +35,6 @@@ int  pthread_create_and_store (std::str
  void pthread_cancel_one (pthread_t thread);
  void pthread_cancel_all ();
  void pthread_kill_all (int signum);
- void pthread_exit_pbd (void* status);
  const char* pthread_name ();
  void pthread_set_name (const char* name);
  
index 91d93ec4f8a73c8b28fdc68ac557bca980b7cc28,3d3cb96fb5cb313f31df83bda7cc3e9229e26057..b8ca8fc09346274d7dd441ae68d1e0671e7c8534
  #include <fst.h>
  #endif
  
 +#ifdef COMPILER_MSVC
 +DECLARE_DEFAULT_COMPARISONS(pthread_t)  // Needed for 'DECLARE_DEFAULT_COMPARISONS'. Objects in an STL container can be
 +                                        // searched and sorted. Thus, when instantiating the container, MSVC complains
 +                                        // if the type of object being contained has no appropriate comparison operators
 +                                        // defined (specifically, if operators '<' and '==' are undefined). This seems
 +                                        // to be the case with ptw32 'pthread_t' which is a simple struct.
 +#endif
 +
  using namespace std;
  
 -typedef std::set<pthread_t> ThreadMap;
 +typedef std::list<pthread_t> ThreadMap;
  static ThreadMap all_threads;
  static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
  static Glib::Threads::Private<char> thread_name (free);
@@@ -80,12 -72,34 +80,34 @@@ fake_thread_start (void* arg
        void* (*thread_work)(void*) = ts->thread_work;
        void* thread_arg = ts->arg;
  
+       /* name will be deleted by the default handler for GStaticPrivate, when the thread exits */
        pthread_set_name (ts->name.c_str());
  
+       /* we don't need this object anymore */
        delete ts;
-       /* name will be deleted by the default handler for GStaticPrivate, when the thread exits */
  
-       return thread_work (thread_arg);
+       /* actually run the thread's work function */
+       void* ret = thread_work (thread_arg);
+       /* cleanup */
+       pthread_mutex_lock (&thread_map_lock);
+       for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
+               if (pthread_equal ((*i), pthread_self())) {
+                       all_threads.erase (i);
+                       break;
+               }
+       }
+       pthread_mutex_unlock (&thread_map_lock);
+       /* done */
+       return ret;
  }
  
  int  
@@@ -102,7 -116,7 +124,7 @@@ pthread_create_and_store (string name, 
  
        if ((ret = thread_creator (thread, &default_attr, fake_thread_start, ts)) == 0) {
                pthread_mutex_lock (&thread_map_lock);
 -              all_threads.insert (*thread);
 +              all_threads.push_back (*thread);
                pthread_mutex_unlock (&thread_map_lock);
        }
  
@@@ -135,7 -149,7 +157,7 @@@ pthread_kill_all (int signum
  {     
        pthread_mutex_lock (&thread_map_lock);
        for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
 -              if ((*i) != pthread_self()) {
 +              if (!pthread_equal ((*i), pthread_self())) {
                        pthread_kill ((*i), signum);
                }
        }
@@@ -147,10 -161,16 +169,17 @@@ voi
  pthread_cancel_all () 
  {     
        pthread_mutex_lock (&thread_map_lock);
-       for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
++
+       for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ) {
+               ThreadMap::iterator nxt = i;
+               ++nxt;
                if (!pthread_equal ((*i), pthread_self())) {
                        pthread_cancel ((*i));
                }
+               i = nxt;
        }
        all_threads.clear();
        pthread_mutex_unlock (&thread_map_lock);
@@@ -171,18 -191,3 +200,3 @@@ pthread_cancel_one (pthread_t thread
        pthread_mutex_unlock (&thread_map_lock);
  }
  
- void
- pthread_exit_pbd (void* status) 
- {     
-       pthread_t thread = pthread_self();
-       pthread_mutex_lock (&thread_map_lock);
-       for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
-               if (pthread_equal ((*i), thread)) {
-                       all_threads.erase (i);
-                       break;
-               }
-       }
-       pthread_mutex_unlock (&thread_map_lock);
-       pthread_exit (status);
- }
diff --combined libs/pbd/wscript
index 6907dd76938f8d2cef4fd831431afb095989948a,ffbe0e0d19a996e16057559df6ddedbc91ee473d..59f7a3368b89492bd9fd753944bf29264559cf44
@@@ -38,6 -38,7 +38,6 @@@ libpbd_sources = 
      'controllable.cc',
      'controllable_descriptor.cc',
      'clear_dir.cc',
 -    'crossthread.cc',
      'cpus.cc',
      'debug.cc',
      'enumwriter.cc',
      'enums.cc',
      'epa.cc',
      'error.cc',
 +    'ffs.cc',
      'file_manager.cc',
      'file_utils.cc',
      'fpu.cc',
 +    'glib_semaphore.cc',
      'id.cc',
      'locale_guard.cc',
 +    'localtime_r.cc',
      'malign.cc',
      'mountpoint.cc',
      'openuri.cc',
      'pathexpand.cc',
      'pathscanner.cc',
+     'pbd.cc',
      'pool.cc',
      'property_list.cc',
      'pthread_utils.cc',
      'receiver.cc',
 +    'resource.cc',
      'search_path.cc',
      'semutils.cc',
      'shortpath.cc',
@@@ -92,18 -90,20 +93,18 @@@ def configure(conf)
      autowaf.configure(conf)
      autowaf.check_pkg(conf, 'libxml-2.0', uselib_store='XML')
      autowaf.check_pkg(conf, 'sigc++-2.0', uselib_store='SIGCPP', atleast_version='2.0')
 -    if sys.platform != 'darwin':
 -        autowaf.check_pkg(conf, 'uuid', uselib_store='UUID')
  
      conf.check(function_name='getmntent', header_name='mntent.h', define_name='HAVE_GETMNTENT',mandatory=False)
      conf.check(header_name='execinfo.h', define_name='HAVE_EXECINFO',mandatory=False)
      conf.check(header_name='unistd.h', define_name='HAVE_UNISTD',mandatory=False)
      conf.check_cc(function_name='posix_memalign', header_name='stdlib.h', cflags='-D_XOPEN_SOURCE=600', define_name='HAVE_POSIX_MEMALIGN', mandatory=False)
 +    conf.check(function_name='localtime_r', header_name='time.h', define_name='HAVE_LOCALTIME_R',mandatory=False)
  
      conf.write_config_header('libpbd-config.h', remove=False)
  
      # Boost headers
      autowaf.check_header(conf, 'cxx', 'boost/shared_ptr.hpp')
      autowaf.check_header(conf, 'cxx', 'boost/weak_ptr.hpp')
 -    # autowaf.check_header(conf, 'cxx', 'boost/uuid/uuid.hpp')
  
  def build(bld):
      
      if bld.is_defined('DEBUG_RT_ALLOC'):
          obj.source += 'debug_rt_alloc.c'
  
 +    if bld.env['build_target'] != 'mingw':
 +        obj.source += [ 'crossthread.cc' ]
 +
      obj.export_includes = ['.']
      obj.includes     = ['.']
      obj.name         = 'libpbd'
          testobj.source       = '''
                  test/testrunner.cc
                  test/xpath.cc
 +                test/mutex_test.cc
                  test/scalar_properties.cc
                  test/signals_test.cc
                  test/convert_test.cc
          testobj.uselib       = 'CPPUNIT XML SNDFILE'
          testobj.use          = 'libpbd'
          testobj.name         = 'libpbd-tests'
 -        if sys.platform != 'darwin':
 +        if sys.platform != 'darwin' and bld.env['build_target'] != 'mingw':
              testobj.linkflags    = ['-lrt']
  
  
diff --combined wscript
index 1eec0eba5f856ce2a0ff81dfd4dbd33c7a52e30c,d887fe68220351a2934b9d0b3d39422c1eb66842..80dfa7533901927f6e4ac059efb7ad3f47883bb8
+++ b/wscript
@@@ -32,6 -32,7 +32,6 @@@ children = 
          'libs/timecode',
          'libs/ardour',
          'libs/gtkmm2ext',
 -        'libs/clearlooks-newer',
          'libs/audiographer',
          'gtk2_ardour',
          'export',
@@@ -46,6 -47,15 +46,6 @@@ i18n_children = 
          'libs/gtkmm2ext',
  ]
  
 -if sys.platform == 'linux2':
 -    children += [ 'tools/sanity_check' ]
 -    lxvst_default = True
 -elif sys.platform == 'darwin':
 -    children += [ 'libs/appleutility' ]
 -    lxvst_default = False
 -else:
 -    lxvst_default = False
 -
  # Version stuff
  
  def fetch_gcc_version (CC):
@@@ -244,7 -254,7 +244,7 @@@ def set_compiler_flags (conf,opt)
          print("However, this is tricky and not recommended for beginners.")
          sys.exit (-1)
  
 -    if opt.lxvst:
 +    if conf.env['LXVST_SUPPORT'] == True:
          if conf.env['build_target'] == 'x86_64':
              conf.env.append_value('CXXFLAGS', "-DLXVST_64BIT")
          else:
@@@ -400,7 -410,7 +400,7 @@@ def options(opt)
      opt.add_option('--depstack-root', type='string', default='~', dest='depstack_root',
                      help='Directory/folder where dependency stack trees (gtk, a3) can be found (defaults to ~)')
      opt.add_option('--dist-target', type='string', default='auto', dest='dist_target',
 -                    help='Specify the target for cross-compiling [auto,none,x86,i386,i686,x86_64,powerpc,tiger,leopard]')
 +                    help='Specify the target for cross-compiling [auto,none,x86,i386,i686,x86_64,powerpc,tiger,leopard,mingw]')
      opt.add_option('--fpu-optimization', action='store_true', default=True, dest='fpu_optimization',
                      help='Build runtime checked assembler code (default)')
      opt.add_option('--no-fpu-optimization', action='store_false', dest='fpu_optimization')
                      help='Install MIME type, icons and .desktop file as per freedesktop.org standards')
      opt.add_option('--freebie', action='store_true', default=False, dest='freebie',
                      help='Build a version suitable for distribution as a zero-cost binary')
-     opt.add_option('--no-freesound', action='store_false', default=True, dest='freesound',
-                     help='Do not build with Freesound database support')
      opt.add_option('--gprofile', action='store_true', default=False, dest='gprofile',
                      help='Compile for use with gprofile')
      opt.add_option('--internal-shared-libs', action='store_true', default=True, dest='internal_shared_libs',
                      help='Compile with support for LV2 (if Lilv+Suil is available)')
      opt.add_option('--no-lv2', action='store_false', dest='lv2',
                      help='Do not compile with support for LV2')
 -    opt.add_option('--lxvst', action='store_true', default=lxvst_default, dest='lxvst',
 +    opt.add_option('--lxvst', action='store_true', default=True, dest='lxvst',
                      help='Compile with support for linuxVST plugins')
      opt.add_option('--nls', action='store_true', default=True, dest='nls',
                      help='Enable i18n (native language support) (default)')
@@@ -603,6 -611,13 +601,6 @@@ def configure(conf)
  
      autowaf.check_header(conf, 'cxx', 'jack/session.h', define="JACK_SESSION", mandatory = False)
  
 -    conf.check_cxx(fragment = "#include <boost/version.hpp>\nint main(void) { return (BOOST_VERSION >= 103900 ? 0 : 1); }\n",
 -                  execute = "1",
 -                  mandatory = True,
 -                  msg = 'Checking for boost library >= 1.39',
 -                  okmsg = 'ok',
 -                  errmsg = 'too old\nPlease install boost version 1.39 or higher.')
 -
      autowaf.check_pkg(conf, 'glib-2.0', uselib_store='GLIB', atleast_version='2.2')
      autowaf.check_pkg(conf, 'gthread-2.0', uselib_store='GTHREAD', atleast_version='2.2')
      autowaf.check_pkg(conf, 'glibmm-2.4', uselib_store='GLIBMM', atleast_version='2.32.0')
      autowaf.check_pkg(conf, 'libcurl', uselib_store='CURL', atleast_version='7.0.0')
      autowaf.check_pkg(conf, 'liblo', uselib_store='LO', atleast_version='0.26')
  
 -    conf.check_cc(function_name='dlopen', header_name='dlfcn.h', lib='dl', uselib_store='DL')
 +    if Options.options.dist_target == 'mingw':
 +        Options.options.fpu_optimization = False
 +        conf.env.append_value('CFLAGS', '-DPLATFORM_WINDOWS')
 +        conf.env.append_value('CFLAGS', '-DCOMPILER_MINGW')
 +        conf.env.append_value('CXXFLAGS', '-DPLATFORM_WINDOWS')
 +        conf.env.append_value('CXXFLAGS', '-DCOMPILER_MINGW')
 +        conf.env.append_value('LIB', 'pthreadGC2')
 +        # needed for at least libsmf
 +        conf.check_cc(function_name='htonl', header_name='winsock2.h', lib='ws2_32')
 +        conf.env.append_value('LIB', 'ws2_32')
 +        # needed for mingw64 packages, not harmful on normal mingw build
 +        conf.env.append_value('LIB', 'intl')
 +        conf.check_cc(function_name='regcomp', header_name='regex.h',
 +                      lib='regex', uselib_store="REGEX", define_name='HAVE_REGEX_H')
 +        # TODO put this only where it is needed
 +        conf.env.append_value('LIB', 'regex')
 +
 +    if Options.options.dist_target != 'mingw':
 +        conf.check_cc(function_name='dlopen', header_name='dlfcn.h', lib='dl', uselib_store='DL')
 +
 +        conf.check_cxx(fragment = "#include <boost/version.hpp>\nint main(void) { return (BOOST_VERSION >= 103900 ? 0 : 1); }\n",
 +                      execute = "1",
 +                      mandatory = True,
 +                      msg = 'Checking for boost library >= 1.39',
 +                      okmsg = 'ok',
 +                      errmsg = 'too old\nPlease install boost version 1.39 or higher.')
  
      # Tell everyone that this is a waf build
  
          conf.env['PHONE_HOME'] = True
      if opts.fpu_optimization:
          conf.env['FPU_OPTIMIZATION'] = True
-     if opts.freesound:
-         conf.define('FREESOUND',1)
-         conf.env['FREESOUND'] = True
      if opts.nls:
          conf.define('ENABLE_NLS', 1)
          conf.env['ENABLE_NLS'] = True
          conf.env.append_value('CXXFLAGS', '-I' + Options.options.wine_include)
          autowaf.check_header(conf, 'cxx', 'windows.h', mandatory = True)
      if opts.lxvst:
 -        conf.define('LXVST_SUPPORT', 1)
 -        conf.env['LXVST_SUPPORT'] = True
 +        if sys.platform == 'darwin':
 +            conf.env['LXVST_SUPPORT'] = False
 +        elif Options.options.dist_target == 'mingw':
 +            conf.env['LXVST_SUPPORT'] = False
 +      else:
 +          conf.define('LXVST_SUPPORT', 1)
 +          conf.env['LXVST_SUPPORT'] = True
      if bool(conf.env['JACK_SESSION']):
          conf.define('HAVE_JACK_SESSION', 1)
      conf.define('WINDOWS_KEY', opts.windows_key)
  
      set_compiler_flags (conf, Options.options)
  
 +    if sys.platform == 'darwin':
 +        sub_config_and_use(conf, 'libs/appleutility')
 +    elif Options.options.dist_target != 'mingw':
 +        sub_config_and_use(conf, 'tools/sanity_check')
 +
 +    if Options.options.dist_target != 'mingw':
 +        sub_config_and_use(conf, 'libs/clearlooks-newer')
 +
      for i in children:
          sub_config_and_use(conf, i)
  
@@@ -739,7 -713,6 +734,6 @@@ const char* const ardour_config_info = 
      write_config_text('FLAC',                  conf.is_defined('HAVE_FLAC'))
      write_config_text('FPU optimization',      opts.fpu_optimization)
      write_config_text('Freedesktop files',     opts.freedesktop)
-     write_config_text('Freesound',             opts.freesound)
      write_config_text('JACK session support',  conf.is_defined('JACK_SESSION'))
      write_config_text('LV2 UI embedding',      conf.is_defined('HAVE_SUIL'))
      write_config_text('LV2 support',           conf.is_defined('LV2_SUPPORT'))
@@@ -785,14 -758,6 +779,14 @@@ def build(bld)
  
      autowaf.set_recursive()
  
 +    if sys.platform == 'darwin':
 +        bld.recurse('libs/appleutility')
 +    elif bld.env['build_target'] != 'mingw':
 +        bld.recurse('tools/sanity_check')
 +
 +    if bld.env['build_target'] != 'mingw':
 +        bld.recurse('libs/clearlooks-newer')
 +
      for i in children:
          bld.recurse(i)