Merge branch 'patches' of https://github.com/jdekozak/ardour
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 29 Mar 2013 18:18:08 +0000 (14:18 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 29 Mar 2013 18:18:08 +0000 (14:18 -0400)
87 files changed:
gtk2_ardour/add_video_dialog.cc
gtk2_ardour/add_video_dialog.h
gtk2_ardour/ardour.menus.in
gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/ardour_ui_ed.cc
gtk2_ardour/ardour_window.cc
gtk2_ardour/ardour_window.h
gtk2_ardour/canvas-note-event.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_canvas.cc
gtk2_ardour/editor_canvas_events.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_videotimeline.cc
gtk2_ardour/export_channel_selector.cc
gtk2_ardour/export_channel_selector.h
gtk2_ardour/export_video_dialog.cc
gtk2_ardour/midi_channel_selector.cc
gtk2_ardour/midi_channel_selector.h
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_region_view.h
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/midi_time_axis.h
gtk2_ardour/mono_panner.cc
gtk2_ardour/plugin_selector.cc
gtk2_ardour/public_editor.h
gtk2_ardour/rc_option_editor.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/system_exec.cc
gtk2_ardour/transcode_ffmpeg.cc
gtk2_ardour/transcode_video_dialog.cc
gtk2_ardour/transcode_video_dialog.h
gtk2_ardour/utils_videotl.cc
gtk2_ardour/utils_videotl.h
gtk2_ardour/video_copy_dialog.cc [deleted file]
gtk2_ardour/video_copy_dialog.h [deleted file]
gtk2_ardour/video_image_frame.cc
gtk2_ardour/video_monitor.cc
gtk2_ardour/video_server_dialog.cc
gtk2_ardour/video_server_dialog.h
gtk2_ardour/video_timeline.cc
gtk2_ardour/wscript
libs/ardour/ardour/audio_buffer.h
libs/ardour/ardour/audio_diskstream.h
libs/ardour/ardour/diskstream.h
libs/ardour/ardour/meter.h
libs/ardour/ardour/midi_buffer.h
libs/ardour/ardour/midi_diskstream.h
libs/ardour/ardour/midi_model.h
libs/ardour/ardour/midi_ring_buffer.h
libs/ardour/ardour/midi_track.h
libs/ardour/ardour/rc_configuration_vars.h
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/ardour/track.h
libs/ardour/audio_buffer.cc
libs/ardour/audio_diskstream.cc
libs/ardour/audio_track.cc
libs/ardour/lv2_plugin.cc
libs/ardour/meter.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_model.cc
libs/ardour/midi_port.cc
libs/ardour/midi_ring_buffer.cc
libs/ardour/midi_track.cc
libs/ardour/plugin_manager.cc
libs/ardour/return.cc
libs/ardour/route.cc
libs/ardour/send.cc
libs/ardour/session_process.cc
libs/ardour/track.cc
libs/evoral/evoral/ControlSet.hpp
libs/evoral/evoral/PatchChange.hpp
libs/evoral/evoral/Sequence.hpp
libs/evoral/evoral/types.hpp
libs/evoral/src/Sequence.cpp
libs/gtkmm2ext/gtkmm2ext/visibility_tracker.h [new file with mode: 0644]
libs/gtkmm2ext/visibility_tracker.cc [new file with mode: 0644]
libs/gtkmm2ext/wscript
libs/pbd/debug.cc
libs/pbd/wscript
tools/linux_packaging/ardour.sh.in
tools/linux_packaging/build
tools/linux_packaging/define_versions.sh [new file with mode: 0644]
tools/linux_packaging/package
tools/linux_packaging/stage2.run
tools/linux_packaging/uninstall.sh.in

index d6e18bb718895b9451e7edf2573ccc43027640af..7e3c3e853c8b84647a75cc7292013a7c5377a94a 100644 (file)
@@ -76,46 +76,45 @@ AddVideoDialog::AddVideoDialog (Session* s)
        set_size_request (800, -1);
 
        harvid_initialized = false;
-       std::string dstdir = video_dest_dir(_session->session_directory().video_path(), Config->get_video_server_docroot());
+       std::string dstdir = video_dest_dir(_session->session_directory().video_path(), video_get_docroot(Config));
 
+       if (Config->get_video_advanced_setup()) {
 
-       /* Harvid Browser */
-       harvid_list_view.append_column("", pixBufRenderer);
-       harvid_list_view.append_column(_("Filename"), harvid_list_columns.filename);
+               /* Harvid Browser */
+               harvid_list_view.append_column("", pixBufRenderer);
+               harvid_list_view.append_column(_("Filename"), harvid_list_columns.filename);
 
-       harvid_list_view.get_column(0)->set_alignment(0.5);
-       harvid_list_view.get_column(0)->add_attribute(pixBufRenderer, "stock-id", harvid_list_columns.id);
-       harvid_list_view.get_column(1)->set_expand(true);
-       harvid_list_view.get_column(1)->set_sort_column(harvid_list_columns.filename);
-       harvid_list_view.set_enable_search(true);
-       harvid_list_view.set_search_column(1);
+               harvid_list_view.get_column(0)->set_alignment(0.5);
+               harvid_list_view.get_column(0)->add_attribute(pixBufRenderer, "stock-id", harvid_list_columns.id);
+               harvid_list_view.get_column(1)->set_expand(true);
+               harvid_list_view.get_column(1)->set_sort_column(harvid_list_columns.filename);
+               harvid_list_view.set_enable_search(true);
+               harvid_list_view.set_search_column(1);
 
+               harvid_list_view.get_selection()->set_mode (SELECTION_SINGLE);
 
-       //Glib::RefPtr<Gtk::TreeModelSort> refTreeModelSort = Gtk::TreeModelSort::create(harvid_list_view.get_model());
-       //refTreeModelSort->set_sort_column(harvid_list_columns.filename, Gtk::SORT_ASCENDING);
-       //harvid_list_view.set_model(refTreeModelSort);
+               harvid_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &AddVideoDialog::harvid_list_view_selected));
+               harvid_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &AddVideoDialog::harvid_list_view_activated));
 
-       harvid_list_view.get_selection()->set_mode (SELECTION_SINGLE);
+               VBox* vbox = manage (new VBox);
+               Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
+               scroll->add(harvid_list_view);
+               scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
 
-       harvid_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &AddVideoDialog::harvid_list_view_selected));
-       harvid_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &AddVideoDialog::harvid_list_view_activated));
-
-       VBox* vbox = manage (new VBox);
-       Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
-       scroll->add(harvid_list_view);
-       scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
-
-       HBox* hbox = manage (new HBox);
-       harvid_path.set_alignment (0, 0.5);
-       hbox->pack_start (harvid_path, true, true);
-       hbox->pack_start (harvid_reset, false, false);
-
-       vbox->pack_start (*hbox, false, false);
-       vbox->pack_start (*scroll, true, true);
-
-       notebook.append_page (*vbox, _("VideoServerIndex"));
+               HBox* hbox = manage (new HBox);
+               harvid_path.set_alignment (0, 0.5);
+               hbox->pack_start (harvid_path, true, true);
+               hbox->pack_start (harvid_reset, false, false);
 
+               vbox->pack_start (*hbox, false, false);
+               vbox->pack_start (*scroll, true, true);
 
+               notebook.append_page (*vbox, _("VideoServerIndex"));
+       } else {
+               /* dummy entry */
+               VBox* vbox = manage (new VBox);
+               notebook.append_page (*vbox, _("VideoServerIndex"));
+       }
 
        /* file chooser */
        chooser.set_border_width (4);
@@ -137,19 +136,12 @@ AddVideoDialog::AddVideoDialog (Session* s)
        chooser.add_filter (matchall_filter);
        chooser.set_select_multiple (false);
 
-       /* file import options */
-       import_combo.set_name ("PaddedButton");
-       import_combo.append_text(_("Reference From Current Location"));
-       import_combo.append_text(_("Hardlink or Copy to Session"));
-       import_combo.append_text(_("Transcode to Session"));
-       import_combo.set_active(2);
-
-       vbox = manage (new VBox);
-       vbox->pack_start (chooser, true, true, 0);
-       vbox->pack_start (import_combo, false, true, 4);
+       VBox* vboxfb = manage (new VBox);
+       vboxfb->pack_start (chooser, true, true, 0);
 
-       if (Config->get_video_server_docroot().size() > 0) {
-               notebook.append_page (*vbox, _("Browse Files"));
+       if (video_get_docroot(Config).size() > 0 &&
+                       Config->get_video_advanced_setup()) {
+               notebook.append_page (*vboxfb, _("Browse Files"));
        }
 
        /* Global Options*/
@@ -190,7 +182,7 @@ AddVideoDialog::AddVideoDialog (Session* s)
        preview_image->set(imgbuf);
        seek_slider.set_draw_value(false);
 
-       hbox = manage (new HBox);
+       HBox* hbox = manage (new HBox);
        hbox->pack_start (*table, true, false);
 
        Gtk::Alignment *al = manage(new Gtk::Alignment());
@@ -203,7 +195,11 @@ AddVideoDialog::AddVideoDialog (Session* s)
 
        /* Overall layout */
        hbox = manage (new HBox);
-       hbox->pack_start (notebook, true, true);
+       if (Config->get_video_advanced_setup()) {
+               hbox->pack_start (notebook, true, true);
+       } else {
+               hbox->pack_start (*vboxfb, true, true);
+       }
        hbox->pack_start (*previewpane, false, false);
 
        get_vbox()->set_spacing (4);
@@ -214,7 +210,7 @@ AddVideoDialog::AddVideoDialog (Session* s)
        /* xjadeo checkbox */
        if (ARDOUR_UI::instance()->video_timeline->found_xjadeo()
                        /* TODO xjadeo setup w/ xjremote */
-                       && Config->get_video_server_docroot().size() > 0) {
+                       && video_get_docroot(Config).size() > 0) {
                xjadeo_checkbox.set_active(true);  /* set in ardour_ui.cpp ?! */
        } else {
                printf("xjadeo was not found or video-server docroot is unset (remote video-server)\n");
@@ -295,7 +291,7 @@ std::string
 AddVideoDialog::file_name (bool &local_file)
 {
        int n = notebook.get_current_page ();
-       if (n == 1) {
+       if (n == 1 || ! Config->get_video_advanced_setup()) {
                local_file = true;
                return chooser.get_filename();
        } else {
@@ -304,10 +300,10 @@ AddVideoDialog::file_name (bool &local_file)
                if(!iter) return "";
 
                std::string uri = (*iter)[harvid_list_columns.uri];
-               std::string video_server_url = Config->get_video_server_url();
+               std::string video_server_url = video_get_server_url(Config);
 
                /* check if video server is running locally */
-               if (Config->get_video_server_docroot().size() > 0
+               if (video_get_docroot(Config).size() > 0
                                && !video_server_url.compare(0, 16, "http://localhost"))
                {
                        /* check if the file can be accessed */
@@ -315,7 +311,7 @@ AddVideoDialog::file_name (bool &local_file)
                        CURL *curl;
                        curl = curl_easy_init();
                        char *ue = curl_easy_unescape(curl, uri.c_str(), uri.length(), &plen);
-                       std::string path = Config->get_video_server_docroot() + ue;
+                       std::string path = video_get_docroot(Config) + ue;
                        if (!::access(path.c_str(), R_OK)) {
                                uri = path;
                                local_file = true;
@@ -331,9 +327,8 @@ enum VtlImportOption
 AddVideoDialog::import_option ()
 {
        int n = notebook.get_current_page ();
-       if (n == 0) { return VTL_IMPORT_NONE; }
-       int i = import_combo.get_active_row_number();
-       return static_cast<VtlImportOption>(i);
+       if (n == 0 && Config->get_video_advanced_setup()) { return VTL_IMPORT_NONE; }
+       return VTL_IMPORT_TRANSCODE;
 }
 
 bool
@@ -377,7 +372,7 @@ AddVideoDialog::file_selection_changed ()
                                && !Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR);
                set_action_ok(ok);
                if (ok) {
-                       request_preview(video_map_path(Config->get_video_server_docroot(), path));
+                       request_preview(video_map_path(video_get_docroot(Config), path));
                }
        } else {
                set_action_ok(false);
@@ -443,7 +438,7 @@ void
 AddVideoDialog::harvid_load_docroot() {
        set_action_ok(false);
 
-       std::string video_server_url = Config->get_video_server_url();
+       std::string video_server_url = video_get_server_url(Config);
        char url[2048];
        snprintf(url, sizeof(url), "%s%sindex/"
                , video_server_url.c_str()
@@ -454,7 +449,7 @@ AddVideoDialog::harvid_load_docroot() {
 
 bool
 AddVideoDialog::page_switch() {
-       if (notebook.get_current_page () == 1) {
+       if (notebook.get_current_page () == 1 || Config->get_video_advanced_setup()) {
                file_selection_changed();
                return true;
        }
@@ -540,7 +535,7 @@ AddVideoDialog::seek_preview()
 void
 AddVideoDialog::request_preview(std::string u)
 {
-       std::string video_server_url = Config->get_video_server_url();
+       std::string video_server_url = video_get_server_url(Config);
 
        double video_file_fps;
        long long int video_duration;
index 12409895eefa73052cd2e8ed64dca43934804896..7d8bdbc1ff74d3349bf3b13958b7442d026bfeba 100644 (file)
@@ -33,8 +33,7 @@
 
 enum VtlImportOption {
  VTL_IMPORT_NONE = 0,
- VTL_IMPORT_COPY = 1,
- VTL_IMPORT_TRANSCODE = 2,
+ VTL_IMPORT_TRANSCODE = 1,
 };
 
 class AddVideoDialog : public ArdourDialog
@@ -74,7 +73,6 @@ class AddVideoDialog : public ArdourDialog
 
        Gtk::CheckButton  xjadeo_checkbox;
        Gtk::CheckButton  set_session_fps_checkbox;
-       Gtk::ComboBoxText import_combo;
        Gtk::Notebook notebook;
        Gtk::Button *ok_button;
 
index 1e470162807cb1661bc3fe05281a30e757e10a0e..0451146b2a4ae9a093e17bb8944a737bdcb77e4c 100644 (file)
@@ -36,6 +36,7 @@
       <!--menuitem action='importFromSession'/-->
 #ifdef WITH_VIDEOTIMELINE
       <menuitem action='OpenVideo'/>
+      <menuitem action='CloseVideo'/>
       <menu name='Video' action='Video'>
         <menuitem action='StartVideoServer'/>
         <menuitem action='StopVideoServer'/>
       <menuitem action='ToggleSummary'/>
       <menuitem action='ToggleGroupTabs'/>
       <menuitem action='show-marker-lines'/>
-#ifdef WITH_VIDEOTIMELINE
-      <menuitem action='ToggleJadeo'/>
-#endif
     </menu>
     <menu name='JACK' action='JACK'>
       <menuitem action='JACKDisconnect'/>
 
       <separator/>
 
+#ifdef WITH_VIDEOTIMELINE
+      <menuitem action='ToggleJadeo'/>
+      <separator/>
+#endif
+
       <menuitem action='NewMIDITracer'/>
       <menuitem action='toggle-audio-connection-manager'/>
       <menuitem action='toggle-midi-connection-manager'/>
index 238c530627f21c2fafc8b586b22d435af580d922..e24ec69abd2fac95850fad7c9fb549b0a0cf1139 100644 (file)
@@ -120,7 +120,6 @@ typedef uint64_t microseconds_t;
 #include "video_server_dialog.h"
 #include "add_video_dialog.h"
 #include "transcode_video_dialog.h"
-#include "video_copy_dialog.h"
 #include "system_exec.h" /* to launch video-server */
 #endif
 
@@ -3336,7 +3335,7 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
 
                std::string icsd_exec = video_server_dialog->get_exec_path();
                std::string icsd_docroot = video_server_dialog->get_docroot();
-               if (icsd_docroot.empty()) {icsd_docroot = "/";}
+               if (icsd_docroot.empty()) {icsd_docroot = X_("/");}
 
                struct stat sb;
                if (!lstat (icsd_docroot.c_str(), &sb) == 0 || !S_ISDIR(sb.st_mode)) {
@@ -3362,10 +3361,16 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
                argp[8] = 0;
                stop_video_server();
 
-               std::ostringstream osstream;
-               osstream << "http://localhost:" << video_server_dialog->get_listenport() << "/";
-               Config->set_video_server_url(osstream.str());
-               Config->set_video_server_docroot(icsd_docroot);
+               if (icsd_docroot == X_("/")) {
+                       Config->set_video_advanced_setup(false);
+               } else {
+                       std::ostringstream osstream;
+                       osstream << "http://localhost:" << video_server_dialog->get_listenport() << "/";
+                       Config->set_video_server_url(osstream.str());
+                       Config->set_video_server_docroot(icsd_docroot);
+                       Config->set_video_advanced_setup(true);
+               }
+
                video_server_process = new SystemExec(icsd_exec, argp);
                video_server_process->start();
                sleep(1);
@@ -3414,43 +3419,38 @@ ARDOUR_UI::add_video (Gtk::Window* float_window)
        }
 
        switch (add_video_dialog->import_option()) {
-               case VTL_IMPORT_COPY:
-               {
-                       VideoCopyDialog *video_copy_dialog;
-                       video_copy_dialog = new VideoCopyDialog(_session, path);
-                       //video_copy_dialog->setup_non_interactive_copy();
-                       ResponseType r = (ResponseType) video_copy_dialog->run ();
-                       video_copy_dialog->hide();
-                       if (r != RESPONSE_ACCEPT) { return; }
-                       path = video_copy_dialog->get_filename();
-                       delete video_copy_dialog;
-               }
-                       break;
                case VTL_IMPORT_TRANSCODE:
-               {
-                       TranscodeVideoDialog *transcode_video_dialog;
-                       transcode_video_dialog = new TranscodeVideoDialog (_session, path);
-                       ResponseType r = (ResponseType) transcode_video_dialog->run ();
-                       transcode_video_dialog->hide();
-                       if (r != RESPONSE_ACCEPT) { return; }
-                       path = transcode_video_dialog->get_filename();
-                       if (!transcode_video_dialog->get_audiofile().empty()) {
-                               editor->embed_audio_from_video(transcode_video_dialog->get_audiofile());
+                       {
+                               TranscodeVideoDialog *transcode_video_dialog;
+                               transcode_video_dialog = new TranscodeVideoDialog (_session, path);
+                               ResponseType r = (ResponseType) transcode_video_dialog->run ();
+                               transcode_video_dialog->hide();
+                               if (r != RESPONSE_ACCEPT) {
+                                       delete transcode_video_dialog;
+                                       return;
+                               }
+                               if (!transcode_video_dialog->get_audiofile().empty()) {
+                                       editor->embed_audio_from_video(transcode_video_dialog->get_audiofile());
+                               }
+                               switch (transcode_video_dialog->import_option()) {
+                                       case VTL_IMPORT_TRANSCODED:
+                                               path = transcode_video_dialog->get_filename();
+                                               local_file = true;
+                                               break;
+                                       case VTL_IMPORT_REFERENCE:
+                                               break;
+                                       default:
+                                               delete transcode_video_dialog;
+                                               return;
+                               }
+                               delete transcode_video_dialog;
                        }
-                       delete transcode_video_dialog;
-               }
                        break;
                default:
                case VTL_IMPORT_NONE:
                        break;
        }
 
-       if (path.empty()) {
-               /* may have been overriden by 'audio only import'
-                * in transcode_video_dialog */
-               path = add_video_dialog->file_name(local_file);;
-       }
-
        /* strip _session->session_directory().video_path() from video file if possible */
        if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
                 path=path.substr(_session->session_directory().video_path().size());
@@ -3478,6 +3478,19 @@ ARDOUR_UI::add_video (Gtk::Window* float_window)
        }
 }
 
+void
+ARDOUR_UI::remove_video ()
+{
+       video_timeline->close_session();
+       editor->toggle_ruler_video(false);
+
+       /* delete session state */
+       XMLNode* node = new XMLNode(X_("Videotimeline"));
+       _session->add_extra_xml(*node);
+       node = new XMLNode(X_("Videomonitor"));
+       _session->add_extra_xml(*node);
+}
+
 void
 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
 {
index 071681343614f942c71afa6978f5eccee85f6434..6c7edff1ba437fb4189e2b8778d375bc5c7659de 100644 (file)
@@ -227,6 +227,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
         void add_routes_thread ();
 #ifdef WITH_VIDEOTIMELINE
        void add_video (Gtk::Window* float_window);
+       void remove_video ();
        void start_video_server_menu (Gtk::Window* float_window);
        bool start_video_server (Gtk::Window* float_window, bool popup_msg);
        void stop_video_server (bool ask_confirm=false);
index 6228fcb4ba8e0c322fc419e9db05e8630f93a94e..5d6b2307964099a8d1424c20a00d605d7674d269 100644 (file)
@@ -136,6 +136,9 @@ ARDOUR_UI::install_actions ()
        act = ActionManager::register_action (main_actions, X_("OpenVideo"), _("Open Video"),
                                              sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::add_video), (Gtk::Window*) 0));
        ActionManager::session_sensitive_actions.push_back (act);
+       act = ActionManager::register_action (main_actions, X_("CloseVideo"), _("Remove Video"),
+                                             sigc::mem_fun (*this, &ARDOUR_UI::remove_video));
+       ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_action (main_actions, X_("ExportVideo"), _("Export To Video File"),
                                              sigc::mem_fun (*editor, &PublicEditor::export_video));
        ActionManager::session_sensitive_actions.push_back (act);
index 8d3821fe8711974f1f468006cbef2421e40529b1..616cfbcb66d5e4032d0bf822d95307217d1e6e42 100644 (file)
@@ -31,6 +31,7 @@ using namespace Gtkmm2ext;
 
 ArdourWindow::ArdourWindow (string title)
        : Window ()
+       , VisibilityTracker (*((Gtk::Window*)this))
 {
        set_title (title);
        init ();
@@ -38,6 +39,7 @@ ArdourWindow::ArdourWindow (string title)
 
 ArdourWindow::ArdourWindow (Gtk::Window& parent, string /*title*/)
        : Window ()
+       , VisibilityTracker (*((Gtk::Window*)this))
 {
        init ();
        set_transient_for (parent);
@@ -74,3 +76,4 @@ ArdourWindow::init ()
 {
        set_border_width (10);
 }
+
index 0590234140bf7115532a48115f90462cb540de51..3b8628d5a7b0d636d654f45b1743359975c18f7f 100644 (file)
@@ -23,6 +23,8 @@
 #include <gtkmm/window.h>
 #include <gtkmm/window.h>
 
+#include "gtkmm2ext/visibility_tracker.h"
+
 #include "ardour/session_handle.h"
 
 /**
@@ -31,7 +33,7 @@
  * method of connecting and disconnecting from a Session with
  * all other objects that have a handle on a Session.
  */
-class ArdourWindow : public Gtk::Window, public ARDOUR::SessionHandlePtr
+class ArdourWindow : public Gtk::Window, public ARDOUR::SessionHandlePtr, public Gtkmm2ext::VisibilityTracker
 {
   public:
        ArdourWindow (std::string title);
index 94b675b22466990c126da1ddf1b52b07afd81e7f..867e3cdf1c63d6e3f2cbe1cb378014e6e26b8c23 100644 (file)
@@ -22,6 +22,7 @@
 #include "gtkmm2ext/keyboard.h"
 
 #include "canvas-note-event.h"
+#include "midi_channel_selector.h"
 #include "midi_region_view.h"
 #include "public_editor.h"
 #include "editing_syms.h"
index b082a80f21b605187ef461f0c396e83975068edc..8ecd5cc07de48dba5ed7ecaeb89b6e4d2788bdf3 100644 (file)
@@ -1455,7 +1455,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        void toggle_video_timeline_locked ();
        void set_video_timeline_locked (const bool);
        void queue_visual_videotimeline_update ();
-       void embed_audio_from_video (std::string);
+       void embed_audio_from_video (std::string, framepos_t n = 0);
 #endif
 
        bool canvas_imageframe_item_view_event(GdkEvent* event, ArdourCanvas::Item*,ImageFrameView*);
index 8c9970275d97290622b5b7de80d45b9196f54a25..8be0e61a7b10f7658453d15a53f1c30fad2a1eff 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "ardour/profile.h"
 #include "ardour/rc_configuration.h"
+#include "ardour/smf_source.h"
 
 #include "ardour_ui.h"
 #include "editor.h"
@@ -422,6 +423,23 @@ void
 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
 {
        RouteTimeAxisView* tv;
+       
+       /* MIDI files must always be imported, because we consider them
+        * writable. So split paths into two vectors, and follow the import
+        * path on the MIDI part.
+        */
+
+       vector<string> midi_paths;
+       vector<string> audio_paths;
+
+       for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+               if (SMFSource::safe_midi_file_extension (*i)) {
+                       midi_paths.push_back (*i);
+               } else {
+                       audio_paths.push_back (*i);
+               }
+       }
+
 
        std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
        if (tvp.first == 0) {
@@ -430,24 +448,28 @@ Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, doub
 
                frame = 0;
 
+               do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
+               
                if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
-                       do_import (paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
+                       do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
                } else {
-                       do_embed (paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
+                       do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
                }
 
        } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
 
-               /* check that its an audio track, not a bus */
+               /* check that its a track, not a bus */
 
                if (tv->track()) {
                        /* select the track, then embed/import */
                        selection->set (tv);
 
+                       do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
+
                        if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
-                               do_import (paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
+                               do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
                        } else {
-                               do_embed (paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
+                               do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
                        }
                }
        }
index 7cd25ca92c8098764e05340f483ca66d9794d943..e76b4ce8ee8fc86c5996e77f925b989d276f576e 100644 (file)
@@ -1031,46 +1031,59 @@ Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context,
        (void) event_frame (&event, &px, &py);
 
        std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
-
+       bool can_drop = false;
+       
        if (tv.first != 0) {
 
+               /* over a time axis view of some kind */
+
                rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
                
                if (rtav != 0 && rtav->is_track ()) {
-
-                       region = _regions->get_dragged_region ();
+                       /* over a track, not a bus */
+                       can_drop = true;
+               }
                        
-                       if (region) {
-       
-                               if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
-                                   dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
-                                   (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
-                                    dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
 
-                                       /* audio to audio 
-                                          OR 
-                                          midi to midi
-                                       */
+       } else {
+               /* not over a time axis view, so drop is possible */
+               can_drop = true;
+       }
 
-                                       context->drag_status (context->get_suggested_action(), time);
-                                       return true;
-                               }
+       if (can_drop) {
+               region = _regions->get_dragged_region ();
+               
+               if (region) {
+                       
+                       if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
+                            dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
+                           (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
+                            dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
+                               
+                               /* audio to audio 
+                                  OR 
+                                  midi to midi
+                               */
+                               
+                               context->drag_status (context->get_suggested_action(), time);
+                               return true;
+                       }
+               } else {
+                       /* DND originating from outside ardour
+                        *
+                        * TODO: check if file is audio/midi, allow drops on same track-type only,
+                        * currently: if audio is dropped on a midi-track, it is only added to the region-list
+                        */
+                       if (Profile->get_sae() || Config->get_only_copy_imported_files()) {
+                               context->drag_status(Gdk::ACTION_COPY, time);
                        } else {
-                               /* DND originating from outside ardour
-                                *
-                                * TODO: check if file is audio/midi, allow drops on same track-type only,
-                                * currently: if audio is dropped on a midi-track, it is only added to the region-list
-                                */
-                               if (Profile->get_sae() || Config->get_only_copy_imported_files()) {
+                               if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
                                        context->drag_status(Gdk::ACTION_COPY, time);
                                } else {
-                                       if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY)
-                                               context->drag_status(Gdk::ACTION_COPY, time);
-                                       else
-                                               context->drag_status(Gdk::ACTION_LINK, time);
+                                       context->drag_status(Gdk::ACTION_LINK, time);
                                }
-                               return true;
                        }
+                       return true;
                }
        }
 
index 80bde8298e1eb82d38434c3e9807419e215d8cfb..1713fe58c08e1f5e7b2d7375e59b0f856133530d 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 
 #include <stdint.h>
+#include <algorithm>
 
 #include "pbd/memento_command.h"
 #include "pbd/basename.h"
@@ -1751,6 +1752,12 @@ VideoTimeLineDrag::finished (GdkEvent * /*event*/, bool movement_occurred)
                _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
        }
 
+       _editor->session()->maybe_update_session_range(
+                       std::max(ARDOUR_UI::instance()->video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
+                       std::max(ARDOUR_UI::instance()->video_timeline->get_offset() + ARDOUR_UI::instance()->video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0)
+                       );
+
+
        _editor->commit_reversible_command ();
        _editor->update_canvas_now ();
 }
index 18a49fc9b6479fa8144ca240a47ee697c10a9f51..a58a896fdd6f0341e4bfb0af82fc1da3b851959f 100644 (file)
@@ -90,10 +90,9 @@ Editor::toggle_video_timeline_locked ()
 }
 
 void
-Editor::embed_audio_from_video (std::string path)
+Editor::embed_audio_from_video (std::string path, framepos_t n)
 {
        vector<std::string> paths;
-       framepos_t n = 0; /* -1: use file's timestamp - but br0ken with ffmpeg wav extract */
        paths.push_back(path);
 #if 0
        do_embed (paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, n);
index 6b90f7a36c12cabd65f74bdc98e47462fccc2b1c..6f32ae783e3b75e244246d7f6ece1b8cd68fc7e5 100644 (file)
@@ -527,13 +527,25 @@ RegionExportChannelSelector::handle_selection ()
        CriticalSelectionChanged ();
 }
 
+/* Track export channel selector */
+
 TrackExportChannelSelector::TrackExportChannelSelector (ARDOUR::Session * session, ProfileManagerPtr manager)
   : ExportChannelSelector(session, manager)
+  , region_contents_button(source_group, _("Export region contents"))
+  , track_output_button(source_group, _("Export track output"))
 {
+       pack_start(main_layout);
+
+       // Options
+       options_box.pack_start(region_contents_button);
+       options_box.pack_start(track_output_button);
+       main_layout.pack_start(options_box);
+
+       // Track scroller
        track_scroller.add (track_view);
        track_scroller.set_size_request (-1, 130);
        track_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
-       pack_start(track_scroller);
+       main_layout.pack_start(track_scroller);
 
        // Track list
        track_list = Gtk::ListStore::create (track_cols);
@@ -613,22 +625,23 @@ TrackExportChannelSelector::update_config()
 
                boost::shared_ptr<Route> route = row[track_cols.route];
 
-               /* Output of track code. TODO make this an option also
-               uint32_t outs = route->n_ports().n_audio();
-               for (uint32_t i = 0; i < outs; ++i) {
-                       AudioPort * port = route->audio (i);
-                       if (port) {
-                               ExportChannelPtr channel (new PortExportChannel ());
-                               PortExportChannel * pec = static_cast<PortExportChannel *> (channel.get());
-                               pec->add_port(port);
-                               state->config->register_channel(channel);
+               if (track_output_button.get_active()) {
+                       uint32_t outs = route->n_outputs().n_audio();
+                       for (uint32_t i = 0; i < outs; ++i) {
+                               boost::shared_ptr<AudioPort> port = route->output()->audio (i);
+                               if (port) {
+                                       ExportChannelPtr channel (new PortExportChannel ());
+                                       PortExportChannel * pec = static_cast<PortExportChannel *> (channel.get());
+                                       pec->add_port(port);
+                                       state->config->register_channel(channel);
+                               }
                        }
+               } else {
+                       std::list<ExportChannelPtr> list;
+                       RouteExportChannel::create_from_route (list, route);
+                       state->config->register_channels (list);
                }
-               */
 
-               std::list<ExportChannelPtr> list;
-               RouteExportChannel::create_from_route (list, route);
-               state->config->register_channels (list);
                state->config->set_name (route->name());
        }
 
index 79e943a569e5b4d7d0b66c147aaa00ae490ab0db..984026a74873b4b14df556e11734ddec42b30f8f 100644 (file)
@@ -235,15 +235,17 @@ class TrackExportChannelSelector : public ExportChannelSelector
   private:
 
        void fill_list();
-        void add_track (boost::shared_ptr<ARDOUR::Route> route);
+       void add_track (boost::shared_ptr<ARDOUR::Route> route);
        void update_config();
 
        ChannelConfigList configs;
 
+       Gtk::VBox main_layout;
+
        struct TrackCols : public Gtk::TreeModelColumnRecord
        {
          public:
-               Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Route> > route;
+               Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Route> > route;
                Gtk::TreeModelColumn<std::string>     label;
                Gtk::TreeModelColumn<bool>            selected;
 
@@ -256,6 +258,10 @@ class TrackExportChannelSelector : public ExportChannelSelector
 
        Gtk::ScrolledWindow          track_scroller;
 
+       Gtk::HBox                    options_box;
+       Gtk::RadioButton::Group      source_group;
+       Gtk::RadioButton             region_contents_button;
+       Gtk::RadioButton             track_output_button;
 };
 
 #endif /* __export_channel_selector_h__ */
index 89693aee8ebb99441d2aa68e975a9047be6d47aa..104a1c5c6d2b9f63e41af867d217e0224a66903d 100644 (file)
@@ -92,7 +92,6 @@ ExportVideoDialog::ExportVideoDialog (PublicEditor& ed, Session* s)
 {
        set_session (s);
 
-       transcoder = 0;
 
        set_name ("ExportVideoDialog");
        set_position (Gtk::WIN_POS_MOUSE);
@@ -105,15 +104,18 @@ ExportVideoDialog::ExportVideoDialog (PublicEditor& ed, Session* s)
        VBox* options_box = manage (new VBox);
        HBox* path_hbox;
 
-#if 0
-       l = manage (new Label (_("<b>Export Video File</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
-       l->set_use_markup ();
-       vbox->pack_start (*l, false, false);
-       l = manage (new Label (_("The file-format is determined by the extension you choose for the output file."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
-       l->set_size_request(700,-1);
-       l->set_line_wrap();
-       vbox->pack_start (*l, false, false, 8);
-#endif
+       /* 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->set_line_wrap();
+               vbox->pack_start (*l, false, false, 8);
+               get_vbox()->pack_start (*vbox, false, false);
+               add_button (Stock::OK, RESPONSE_CANCEL);
+               show_all_children ();
+               return;
+       }
+       delete transcoder; transcoder = 0;
 
        l = manage (new Label (_("<b>Files:</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
        l->set_use_markup ();
@@ -538,7 +540,7 @@ ExportVideoDialog::encode_pass (int pass)
         */
        transcoder = new TranscodeFfmpeg(invid);
        if (!transcoder->ffexec_ok()) {
-               warning << _("No ffprobe or ffmpeg executables could be found on this system. Transcoding is not possible until you install those tools.") << endmsg;
+               /* ffmpeg binary was not found.  TranscodeFfmpeg prints a warning */
                unlink (insnd.c_str());
                Gtk::Dialog::response(RESPONSE_CANCEL);
                return;
index 6770f0e60d0c57d31f9248e3afeb1f0a4d3fef73..2f5ca729a6b942480d51ae963304670f181189d6 100644 (file)
@@ -1,6 +1,6 @@
 /*
-    Copyright (C) 2008 Paul Davis
-    Author: Hans Baier
+    Copyright (C) 2008-2013 Paul Davis
+    Original Author: Hans Baier
 
     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
 
 #include <algorithm>
 #include <sstream>
+#include <gtkmm/separator.h>
+#include <gtkmm/box.h>
+#include <gtkmm/label.h>
+#include <gtkmm/togglebutton.h>
+#include <gtkmm/radiobutton.h>
+#include <gtkmm/table.h>
+
+#include "pbd/compose.h"
+
+#include "gtkmm2ext/gtk_ui.h"
+#include "gtkmm2ext/gui_thread.h"
+#include "gtkmm2ext/utils.h"
+
+#include "ardour/midi_track.h"
 
 #include "midi_channel_selector.h"
-#include "gtkmm/separator.h"
-#include "i18n.h"
 #include "rgb_macros.h"
 
+#include "i18n.h"
+
 using namespace std;
 using namespace Gtk;
 using namespace ARDOUR;
@@ -310,3 +324,568 @@ MidiMultipleChannelSelector::invert_selection(void)
        mode_changed.emit(_channel_mode, get_selected_channels());
 }
 
+/*-----------------------------------------*/
+
+MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr<MidiTrack> mt)
+       : ArdourWindow (_("MIDI Channel Control"))
+       , track (mt)
+       , playback_all_button (playback_button_group, _("Playback all channels"))
+       , playback_filter_button (playback_button_group, _("Play only selected channels"))
+       , playback_force_button (playback_button_group, _("Use a single fixed channel for all playback"))
+       , capture_all_button (capture_button_group, _("Record all channels"))
+       , capture_filter_button (capture_button_group, _("Record only selected channels"))
+       , capture_force_button (capture_button_group, _("Force all channels to 1 channel"))
+       , last_drawn_capture_mode (AllChannels)
+       , last_drawn_playback_mode (AllChannels)
+{
+       build ();
+
+       playback_mode_changed ();
+       capture_mode_changed ();
+
+       playback_mask_changed ();
+       capture_mask_changed ();
+
+       track->PlaybackChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context());
+       track->PlaybackChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mode_changed, this), gui_context());
+       track->CaptureChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mask_changed, this), gui_context());
+       track->CaptureChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
+}
+
+MidiChannelSelectorWindow::~MidiChannelSelectorWindow()
+{
+}
+
+void
+MidiChannelSelectorWindow::build ()
+{
+       VBox* vpacker;
+       HBox* capture_controls;
+       HBox* playback_controls;
+        Button* b;
+        Label* l;
+
+        vpacker = manage (new VBox);
+        vpacker->set_spacing (6);
+        vpacker->set_border_width (12);
+
+       l = manage (new Label (string_compose (("<span size=\"larger\" weight=\"bold\">%1: %2</span>"), _("MIDI Channel Control"), track->name())));
+       l->set_use_markup (true);
+       l->set_alignment (0.5, 0.0);
+
+       vpacker->pack_start (*l, true, true);
+
+        l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Inbound"))));
+       l->set_use_markup (true);
+        vpacker->pack_start (*l);
+
+
+       vpacker->pack_start (capture_all_button);
+       capture_all_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), AllChannels));
+       
+       vpacker->pack_start (capture_filter_button);
+       capture_filter_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), FilterChannels));
+       
+       vpacker->pack_start (capture_force_button);
+       capture_force_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), ForceChannel));
+
+        vpacker->pack_start (capture_mask_box);
+       
+       capture_controls = manage (new HBox);
+       capture_controls->set_spacing (6);
+
+        b = manage (new Button (_("All")));
+       Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable recording all channels"));
+       capture_controls->pack_start (*b);
+       capture_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_capture_mask)); 
+        b = manage (new Button (_("None")));
+       Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to disable recording all channels"));
+       capture_controls->pack_start (*b);
+       capture_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_capture_mask)); 
+        b = manage (new Button (_("Invert")));
+       Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to invert currently selected recording channels"));
+       capture_controls->pack_start (*b);
+       capture_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_capture_mask)); 
+
+        vpacker->pack_start (*capture_controls);
+
+        l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Playback"))));
+       l->set_use_markup (true);
+        vpacker->pack_start (*l);
+
+       vpacker->pack_start (playback_all_button);
+       playback_all_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), AllChannels));
+       
+       vpacker->pack_start (playback_filter_button);
+       playback_filter_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), FilterChannels));
+       
+       vpacker->pack_start (playback_force_button);
+       playback_force_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), ForceChannel));
+
+       vpacker->pack_start (playback_mask_box);
+
+       playback_controls = manage (new HBox);
+       playback_controls->set_spacing (6);
+
+        b = manage (new Button (_("All")));
+       Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable playback of all channels"));
+       playback_controls->pack_start (*b);
+       playback_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_playback_mask)); 
+        b = manage (new Button (_("None")));
+       Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to disable playback of all channels"));
+       playback_controls->pack_start (*b);
+       playback_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_playback_mask)); 
+       b = manage (new Button (_("Invert")));
+       Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to invert current selected playback channels"));
+       playback_controls->pack_start (*b);
+       playback_mask_controls.push_back (b);
+       b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_playback_mask));
+
+        vpacker->pack_start (*playback_controls);
+
+        add (*vpacker);
+}
+
+void
+MidiChannelSelectorWindow::fill_playback_mask ()
+{
+       if (track->get_playback_channel_mode() == FilterChannels) {
+               track->set_playback_channel_mask (0xffff);
+       }
+}
+
+void
+MidiChannelSelectorWindow::zero_playback_mask ()
+{
+       if (track->get_playback_channel_mode() == FilterChannels) {
+               track->set_playback_channel_mask (0);
+       }
+}
+
+void
+MidiChannelSelectorWindow::invert_playback_mask ()
+{
+       if (track->get_playback_channel_mode() == FilterChannels) {
+               track->set_playback_channel_mask (~track->get_playback_channel_mask());
+       }
+}
+
+void
+MidiChannelSelectorWindow::fill_capture_mask ()
+{
+       if (track->get_capture_channel_mode() == FilterChannels) {
+               track->set_capture_channel_mask (0xffff);
+       }
+}
+
+void
+MidiChannelSelectorWindow::zero_capture_mask ()
+{
+       if (track->get_capture_channel_mode() == FilterChannels) {
+               track->set_capture_channel_mask (0);
+       }
+}
+
+void
+MidiChannelSelectorWindow::invert_capture_mask ()
+{
+       if (track->get_capture_channel_mode() == FilterChannels) {
+               track->set_capture_channel_mask (~track->get_capture_channel_mask());
+       }
+}
+               
+void
+MidiChannelSelectorWindow::set_playback_selected_channels (uint16_t mask)
+{
+       switch (track->get_playback_channel_mode()) {
+       case AllChannels:
+               /* they are insensitive, so we don't care */
+               break;
+
+       case FilterChannels:
+               for (uint16_t i = 0; i < 16; i++) {
+                       playback_buttons[i]->set_active ((1<<i) & mask);
+               }
+               break;
+               
+       case ForceChannel:
+               /* only set the lowest set channel in the mask as active */
+               for (uint16_t i = 0; i < 16; i++) {
+                       playback_buttons[i]->set_active (i == (ffs (mask) - 1));
+               }
+               break;
+       }
+}
+
+void
+MidiChannelSelectorWindow::set_capture_selected_channels (uint16_t mask)
+{
+       switch (track->get_capture_channel_mode()) {
+       case AllChannels:
+               /* they are insensitive, so we don't care */
+               break;
+
+       case FilterChannels:
+               for (uint16_t i = 0; i < 16; i++) {
+                       capture_buttons[i]->set_active ((1<<i) & mask);
+               }
+               break;
+               
+       case ForceChannel:
+               /* only set the lowest set channel in the mask as active */
+               for (uint16_t i = 0; i < 16; i++) {
+                       capture_buttons[i]->set_active (i == (ffs (mask) - 1));
+               }
+               break;
+       }
+}
+
+void
+MidiChannelSelectorWindow::playback_mask_changed ()
+{
+       set_playback_selected_channels (track->get_playback_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::capture_mask_changed ()
+{
+       set_capture_selected_channels (track->get_capture_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::playback_mode_changed ()
+{
+       uint32_t first_channel = 0;
+       ChannelMode mode = track->get_playback_channel_mode();
+
+       switch (mode) {
+       case AllChannels:
+               if (last_drawn_playback_mode == ForceChannel) {
+                       /* force mode used radio buttons. not what we want,
+                        * though one could argue that we want no buttons
+                        * at since they are insensitive
+                        */
+                       playback_buttons.clear ();
+               }
+               for (vector<Widget*>::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+               playback_all_button.set_active ();
+               break;
+
+       case FilterChannels:
+               if (last_drawn_playback_mode == ForceChannel) {
+                       playback_buttons.clear ();
+               } else if (last_drawn_playback_mode == AllChannels) {
+                       for (vector<ToggleButton*>::iterator i = playback_buttons.begin(); i != playback_buttons.end(); ++i) {
+                               (*i)->set_sensitive (true);
+                       }
+               }
+               for (vector<Widget*>::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (true);
+               }
+               playback_filter_button.set_active ();
+               break;
+
+       case ForceChannel:
+               if (last_drawn_playback_mode == AllChannels || last_drawn_playback_mode == FilterChannels) {
+                       playback_buttons.clear ();
+                       first_channel = ffs (track->get_playback_channel_mask()) - 1;
+               }
+               for (vector<Widget*>::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+               playback_force_button.set_active ();
+               break;
+       }
+
+       if (playback_buttons.empty()) {
+
+               Gtkmm2ext::container_clear (playback_mask_box);
+               
+               ToggleButton* tb;
+               RadioButtonGroup group;
+               
+               for (uint32_t n = 0; n < 16; ++n) {
+                       char buf[3];
+                       snprintf (buf, sizeof (buf), "%d", n+1);
+
+                       switch (mode) {
+                       case AllChannels:
+                       case FilterChannels:
+                               tb = manage (new ToggleButton (buf));
+                               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle playback of channel %1"), n+1));
+                               break;
+                       case ForceChannel:
+                               tb = manage (new RadioButton (group, buf));
+                               tb->property_draw_indicator() = false;
+                               if (n == first_channel) {
+                                       tb->set_active (true);
+                               }
+                               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to force all MIDI channel messages to channel %1"), n+1));
+                               break;
+                       }
+                       playback_buttons.push_back (tb);
+                       tb->set_name (X_("MidiChannelSelectorButton"));
+                       playback_mask_box.pack_start (*tb);
+                       tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_channel_clicked), n));
+                       tb->show ();
+
+                       if (mode == AllChannels) {
+                               tb->set_sensitive (false);
+                       }
+               }
+               
+               if (mode != ForceChannel) {
+                       set_playback_selected_channels (track->get_playback_channel_mask());
+               }
+       }
+
+       if (mode == AllChannels) {
+               for (vector<ToggleButton*>::iterator i = playback_buttons.begin(); i != playback_buttons.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+       }
+
+       last_drawn_playback_mode = mode;
+}
+
+void
+MidiChannelSelectorWindow::capture_mode_changed ()
+{
+       uint32_t first_channel = 0;
+       ChannelMode mode = track->get_capture_channel_mode();
+
+       switch (mode) {
+       case AllChannels:
+               if (last_drawn_capture_mode == ForceChannel) {
+                       /* force mode used radio buttons. not what we want,
+                        * though one could argue that we want no buttons
+                        * at since they are insensitive
+                        */
+                       capture_buttons.clear ();
+               }
+               for (vector<Widget*>::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+               capture_all_button.set_active ();
+               break;
+
+       case FilterChannels:
+               if (last_drawn_capture_mode == ForceChannel) {
+                       capture_buttons.clear ();
+               } else if (last_drawn_capture_mode == AllChannels) {
+                       for (vector<ToggleButton*>::iterator i = capture_buttons.begin(); i != capture_buttons.end(); ++i) {
+                               (*i)->set_sensitive (true);
+                       }
+               }
+               for (vector<Widget*>::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (true);
+               }
+               capture_filter_button.set_active ();
+               break;
+
+       case ForceChannel:
+               if (last_drawn_capture_mode == AllChannels || last_drawn_capture_mode == FilterChannels) {
+                       capture_buttons.clear ();
+                       first_channel = ffs (track->get_capture_channel_mask()) - 1;
+               }
+               for (vector<Widget*>::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+               capture_force_button.set_active ();
+               break;
+       }
+
+       if (capture_buttons.empty()) {
+
+               Gtkmm2ext::container_clear (capture_mask_box);
+               
+               ToggleButton* tb;
+               RadioButtonGroup group;
+               
+               for (uint32_t n = 0; n < 16; ++n) {
+                       char buf[3];
+                       snprintf (buf, sizeof (buf), "%d", n+1);
+
+                       switch (mode) {
+                       case AllChannels:
+                       case FilterChannels:
+                               tb = manage (new ToggleButton (buf));
+                               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle recording of channel %1"), n+1));
+                               break;
+                       case ForceChannel:
+                               tb = manage (new RadioButton (group, buf));
+                               tb->property_draw_indicator() = false;
+                               if (n == first_channel) {
+                                       tb->set_active (true);
+                               }
+                               Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to force all recorded channels to %1"), n+1));
+                               break;
+                       }
+                       capture_buttons.push_back (tb);
+                       tb->set_name (X_("MidiChannelSelectorButton"));
+                       capture_mask_box.pack_start (*tb);
+                       tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_channel_clicked), n));
+                       tb->show ();
+
+                       if (mode == AllChannels) {
+                               tb->set_sensitive (false);
+                       }
+               }
+               
+               if (mode != ForceChannel) {
+                       set_capture_selected_channels (track->get_capture_channel_mask());
+               } 
+       }
+
+       if (mode == AllChannels) {
+               for (vector<ToggleButton*>::iterator i = capture_buttons.begin(); i != capture_buttons.end(); ++i) {
+                       (*i)->set_sensitive (false);
+               }
+       }
+
+       last_drawn_capture_mode = mode;
+}
+
+void
+MidiChannelSelectorWindow::playback_channel_clicked (uint16_t n)
+{
+       if (playback_buttons[n]->get_active()) {
+               switch (track->get_playback_channel_mode()) {
+               case AllChannels:
+                       break;
+               case FilterChannels:
+                       track->set_playback_channel_mask (track->get_playback_channel_mask() | (1<<n));
+                       break;
+               case ForceChannel:
+                       track->set_playback_channel_mask (1<<n);
+                       break;
+               }
+       } else {
+               if (track->get_playback_channel_mode() == FilterChannels) {
+                       track->set_playback_channel_mask (track->get_playback_channel_mask() & ~(1<<n));
+               }
+       }
+}
+
+void
+MidiChannelSelectorWindow::capture_channel_clicked (uint16_t n)
+{
+       if (capture_buttons[n]->get_active()) {
+               switch (track->get_capture_channel_mode()) {
+               case AllChannels:
+                       break;
+               case FilterChannels:
+                       track->set_capture_channel_mask (track->get_capture_channel_mask() | (1<<n));
+                       break;
+               case ForceChannel:
+                       track->set_capture_channel_mask (1<<n);
+                       break;
+               }
+       } else {
+               if (track->get_capture_channel_mode() == FilterChannels) {
+                       track->set_capture_channel_mask (track->get_capture_channel_mask() & ~(1<<n));
+               }
+       }
+}
+
+void
+MidiChannelSelectorWindow::capture_mode_toggled (ChannelMode mode)
+{
+       /* this is called twice for every radio button change. the first time
+          is for the button/mode that has been turned off, and the second is for the
+          button/mode that has been turned on.
+
+          so we take action only if the button is active (i.e it is the one
+          just clicked on)
+       */
+       
+       switch (mode) {
+       case AllChannels:
+               if (capture_all_button.get_active()) {
+                       track->set_capture_channel_mode (AllChannels, track->get_capture_channel_mask());
+               }
+               break;
+       case FilterChannels:
+               if (capture_filter_button.get_active()) {
+                       track->set_capture_channel_mode (FilterChannels, track->get_capture_channel_mask());
+               }
+               break;
+       case ForceChannel:
+               if (capture_force_button.get_active()) {
+                       track->set_capture_channel_mode (ForceChannel, track->get_capture_channel_mask());
+               }
+               break;
+       }
+}
+
+void
+MidiChannelSelectorWindow::playback_mode_toggled (ChannelMode mode)
+{
+       /* this is called twice for every radio button change. the first time
+          is for the button/mode that has been turned off, and the second is for the
+          button/mode that has been turned on.
+
+          so we take action only if the button is active (i.e it is the one
+          just clicked on)
+       */
+       
+       switch (mode) {
+       case AllChannels:
+               if (playback_all_button.get_active()) {
+                       track->set_playback_channel_mode (AllChannels, track->get_playback_channel_mask());
+               }
+               break;
+       case FilterChannels:
+               if (playback_filter_button.get_active()) {
+                       track->set_playback_channel_mode (FilterChannels, track->get_playback_channel_mask());
+               }
+               break;
+       case ForceChannel:
+               if (playback_force_button.get_active()) {
+                       track->set_playback_channel_mode (ForceChannel, track->get_playback_channel_mask());
+               }
+               break;
+       }
+}
+
+void
+MidiChannelSelectorWindow::set_channel_colors (const uint32_t new_channel_colors[16])
+{
+       for (uint32_t n = 0; n < 16; ++n) {
+
+               char color_normal[8];
+               char color_active[8];
+               
+               snprintf(color_normal, 8, "#%x", UINT_INTERPOLATE(new_channel_colors[n], 0x000000ff, 0.6));
+               snprintf(color_active, 8, "#%x", new_channel_colors[n]);
+
+               playback_buttons[n]->modify_bg(STATE_NORMAL, Gdk::Color(color_normal));
+               playback_buttons[n]->modify_bg(STATE_ACTIVE, Gdk::Color(color_active));
+
+               capture_buttons[n]->modify_bg(STATE_NORMAL, Gdk::Color(color_normal));
+               capture_buttons[n]->modify_bg(STATE_ACTIVE, Gdk::Color(color_active));
+       }
+}
+
+void
+MidiChannelSelectorWindow::set_default_channel_color()
+{
+       for (uint32_t n = 0; n < 16; ++n) {
+               playback_buttons[n]->unset_fg (STATE_NORMAL);
+               playback_buttons[n]->unset_bg (STATE_NORMAL);
+               playback_buttons[n]->unset_fg (STATE_ACTIVE);
+               playback_buttons[n]->unset_bg (STATE_ACTIVE);
+
+               capture_buttons[n]->unset_fg (STATE_NORMAL);
+               capture_buttons[n]->unset_bg (STATE_NORMAL);
+               capture_buttons[n]->unset_fg (STATE_ACTIVE);
+               capture_buttons[n]->unset_bg (STATE_ACTIVE);
+       }
+}
index 5764a8d813d76c4c2d85a9af46ce9e37129b4b28..f10c128b920aaae9a0760ecaa75e0b7917d38491 100644 (file)
 
 #include "gtkmm/table.h"
 #include "gtkmm/button.h"
+#include "gtkmm/radiobutton.h"
 #include "gtkmm/label.h"
 #include "gtkmm2ext/stateful_button.h"
 
 #include "ardour/types.h"
 
+#include "ardour_window.h"
+
+namespace ARDOUR {
+       class MidiTrack;
+}
+
 class MidiChannelSelector : public Gtk::Table
 {
-public:
-       MidiChannelSelector(int n_rows = 4, int n_columns = 4, int start_row = 0, int start_column = 0);
-       virtual ~MidiChannelSelector() = 0;
+  public:
+    MidiChannelSelector(int n_rows = 4, int n_columns = 4, int start_row = 0, int start_column = 0);
+    virtual ~MidiChannelSelector() = 0;
 
-       sigc::signal<void> clicked;
+    sigc::signal<void> clicked;
 
-       void set_channel_colors(const uint32_t new_channel_colors[16]);
-       void set_default_channel_color();
+    void set_channel_colors(const uint32_t new_channel_colors[16]);
+    void set_default_channel_color();
 
-protected:
-       virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr) = 0;
-       Gtk::Label                      _button_labels[4][4];
-       Gtkmm2ext::StatefulToggleButton _buttons[4][4];
-       int                             _recursion_counter;
+  protected:
+    virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr) = 0;
+    Gtk::Label                      _button_labels[4][4];
+    Gtkmm2ext::StatefulToggleButton _buttons[4][4];
+    int                             _recursion_counter;
 
-       bool              was_clicked (GdkEventButton*);
+    bool              was_clicked (GdkEventButton*);
 };
 
 class SingleMidiChannelSelector : public MidiChannelSelector
 {
-public:
-       SingleMidiChannelSelector(uint8_t active_channel = 0);
+  public:
+    SingleMidiChannelSelector(uint8_t active_channel = 0);
 
-       uint8_t get_active_channel() const { return _active_channel; }
+    uint8_t get_active_channel() const { return _active_channel; }
 
-       sigc::signal<void, uint8_t> channel_selected;
+    sigc::signal<void, uint8_t> channel_selected;
 
-protected:
-       virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr);
+  protected:
+    virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr);
 
-       Gtk::ToggleButton* _last_active_button;
-       uint8_t            _active_channel;
+    Gtk::ToggleButton* _last_active_button;
+    uint8_t            _active_channel;
 };
 
 class MidiMultipleChannelSelector : public MidiChannelSelector
 {
-public:
-       MidiMultipleChannelSelector(ARDOUR::ChannelMode mode = ARDOUR::FilterChannels,
-                                   uint16_t initial_selection = 0xFFFF);
-
-       virtual ~MidiMultipleChannelSelector();
-
-       /** The channel mode or selected channel(s) has changed.
-        *  First parameter is the new channel mode, second parameter is a bitmask
-        *  of the currently selected channels.
-        */
-       sigc::signal<void, ARDOUR::ChannelMode, uint16_t> mode_changed;
-
-       void set_channel_mode(ARDOUR::ChannelMode mode, uint16_t mask);
-       ARDOUR::ChannelMode get_channel_mode () const { return _channel_mode; }
-
-       /**
-        * @return each bit in the returned word represents a midi channel, eg.
-        *         bit 0 represents channel 0 and bit 15 represents channel 15
-        *
-        */
-       uint16_t get_selected_channels() const;
-       void     set_selected_channels(uint16_t selected_channels);
-
-protected:
-       ARDOUR::ChannelMode _channel_mode;
-       ARDOUR::NoteMode    _note_mode;
-
-       virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr);
-       void force_channels_button_toggled();
-
-       void select_all(bool on);
-       void invert_selection(void);
-
-       Gtk::Button       _select_all;
-       Gtk::Button       _select_none;
-       Gtk::Button       _invert_selection;
-       Gtk::ToggleButton _force_channel;
+  public:
+    MidiMultipleChannelSelector(ARDOUR::ChannelMode mode = ARDOUR::FilterChannels,
+                               uint16_t initial_selection = 0xFFFF);
+
+    virtual ~MidiMultipleChannelSelector();
+
+    /** The channel mode or selected channel(s) has changed.
+     *  First parameter is the new channel mode, second parameter is a bitmask
+     *  of the currently selected channels.
+     */
+    sigc::signal<void, ARDOUR::ChannelMode, uint16_t> mode_changed;
+
+    void set_channel_mode(ARDOUR::ChannelMode mode, uint16_t mask);
+    ARDOUR::ChannelMode get_channel_mode () const { return _channel_mode; }
+
+    /**
+     * @return each bit in the returned word represents a midi channel, eg.
+     *         bit 0 represents channel 0 and bit 15 represents channel 15
+     *
+     */
+    uint16_t get_selected_channels() const;
+    void     set_selected_channels(uint16_t selected_channels);
+
+  protected:
+    ARDOUR::ChannelMode _channel_mode;
+    ARDOUR::NoteMode    _note_mode;
+
+    virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr);
+    void force_channels_button_toggled();
+
+    void select_all(bool on);
+    void invert_selection(void);
+
+    Gtk::Button       _select_all;
+    Gtk::Button       _select_none;
+    Gtk::Button       _invert_selection;
+    Gtk::ToggleButton _force_channel;
+};
+
+class MidiChannelSelectorWindow : public ArdourWindow, public PBD::ScopedConnectionList
+{
+  public:
+    MidiChannelSelectorWindow (boost::shared_ptr<ARDOUR::MidiTrack>);
+    ~MidiChannelSelectorWindow ();
+
+    void set_channel_colors (const uint32_t new_channel_colors[16]);
+    void set_default_channel_color();
+
+  private:
+    boost::shared_ptr<ARDOUR::MidiTrack> track;
+    std::vector<Gtk::ToggleButton*> playback_buttons;
+    std::vector<Gtk::ToggleButton*> capture_buttons;
+
+    std::vector<Gtk::Widget*> playback_mask_controls;
+    std::vector<Gtk::Widget*> capture_mask_controls;
+
+    Gtk::HBox         capture_mask_box;
+    Gtk::HBox         playback_mask_box;
+    Gtk::RadioButtonGroup playback_button_group;
+    Gtk::RadioButton playback_all_button;
+    Gtk::RadioButton playback_filter_button;
+    Gtk::RadioButton playback_force_button;
+    Gtk::RadioButtonGroup capture_button_group;
+    Gtk::RadioButton capture_all_button;
+    Gtk::RadioButton capture_filter_button;
+    Gtk::RadioButton capture_force_button;
+
+    ARDOUR::ChannelMode last_drawn_capture_mode;
+    ARDOUR::ChannelMode last_drawn_playback_mode;
+
+    void build();
+    void set_capture_selected_channels (uint16_t);
+    void set_playback_selected_channels (uint16_t);
+
+    void fill_playback_mask ();
+    void zero_playback_mask ();
+    void invert_playback_mask ();
+
+    void fill_capture_mask ();
+    void zero_capture_mask ();
+    void invert_capture_mask ();
+
+    void playback_mask_changed ();
+    void capture_mask_changed ();
+    void playback_mode_changed ();
+    void capture_mode_changed ();
+
+    void playback_channel_clicked (uint16_t);
+    void capture_channel_clicked (uint16_t);
+
+    void playback_all_clicked();
+    void playback_none_clicked();
+    void playback_invert_clicked();
+
+    void capture_all_clicked();
+    void capture_none_clicked();
+    void capture_invert_clicked();
+
+    void capture_mode_toggled (ARDOUR::ChannelMode);
+    void playback_mode_toggled (ARDOUR::ChannelMode);
 };
 
 #endif /*__ardour_ui_midi_channel_selector_h__*/
index 81e5cf23e974d09ddc1c55774ae0a3917189041e..d6b6935e1129f25460521b6660b71e5637f76ecb 100644 (file)
@@ -66,6 +66,7 @@
 #include "mouse_cursors.h"
 #include "note_player.h"
 #include "public_editor.h"
+#include "route_time_axis.h"
 #include "rgb_macros.h"
 #include "selection.h"
 #include "simpleline.h"
@@ -89,7 +90,6 @@ PBD::Signal1<void, MidiRegionView *> MidiRegionView::SelectionCleared;
 MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv,
                                 boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color const & basic_color)
        : RegionView (parent, tv, r, spu, basic_color)
-       , _last_channel_selection(0xFFFF)
        , _current_range_min(0)
        , _current_range_max(0)
        , _active_notes(0)
@@ -116,13 +116,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
        _note_group->raise_to_top();
        PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
 
-
-       MidiTimeAxisView *time_axis = dynamic_cast<MidiTimeAxisView *>(&tv);
-       if (time_axis) {
-               _last_channel_mode = time_axis->channel_selector().get_channel_mode();
-               _last_channel_selection = time_axis->channel_selector().get_selected_channels();
-       }
-
        Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
        connect_to_diskstream ();
 
@@ -133,7 +126,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
                                 boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color& basic_color,
                                 TimeAxisViewItem::Visibility visibility)
        : RegionView (parent, tv, r, spu, basic_color, false, visibility)
-       , _last_channel_selection(0xFFFF)
        , _current_range_min(0)
        , _current_range_max(0)
        , _active_notes(0)
@@ -160,12 +152,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
        _note_group->raise_to_top();
        PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
 
-       MidiTimeAxisView *time_axis = dynamic_cast<MidiTimeAxisView *>(&tv);
-       if (time_axis) {
-               _last_channel_mode = time_axis->channel_selector().get_channel_mode();
-               _last_channel_selection = time_axis->channel_selector().get_selected_channels();
-       }
-
        connect_to_diskstream ();
 
        SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
@@ -184,7 +170,6 @@ MidiRegionView::parameter_changed (std::string const & p)
 MidiRegionView::MidiRegionView (const MidiRegionView& other)
        : sigc::trackable(other)
        , RegionView (other)
-       , _last_channel_selection(0xFFFF)
        , _current_range_min(0)
        , _current_range_max(0)
        , _active_notes(0)
@@ -219,7 +204,6 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
 
 MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<MidiRegion> region)
        : RegionView (other, boost::shared_ptr<Region> (region))
-       , _last_channel_selection(0xFFFF)
        , _current_range_min(0)
        , _current_range_max(0)
        , _active_notes(0)
@@ -293,8 +277,10 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
        group->raise_to_top();
        group->signal_event().connect (sigc::mem_fun (this, &MidiRegionView::canvas_event), false);
 
-       midi_view()->signal_channel_mode_changed().connect(
-               sigc::mem_fun(this, &MidiRegionView::midi_channel_mode_changed));
+
+       midi_view()->midi_track()->PlaybackChannelModeChanged.connect (_channel_mode_changed_connection, invalidator (*this),
+                                                                      boost::bind (&MidiRegionView::midi_channel_mode_changed, this),
+                                                                      gui_context ());
 
        instrument_info().Changed.connect (_instrument_changed_connection, invalidator (*this),
                                           boost::bind (&MidiRegionView::instrument_settings_changed, this), gui_context());
@@ -1214,7 +1200,7 @@ void
 MidiRegionView::display_patch_changes ()
 {
        MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
-       uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
+       uint16_t chn_mask = mtv->midi_track()->get_playback_channel_mask();
 
        for (uint8_t i = 0; i < 16; ++i) {
                display_patch_changes_on_channel (i, chn_mask & (1 << i));
@@ -1673,7 +1659,7 @@ MidiRegionView::update_note (CanvasNote* ev, bool update_ghost_regions)
                /* outline all edges */
                ev->property_outline_what() = (guint32) 0xF;
        }
-
+       
        if (update_ghost_regions) {
                for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
                        MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
@@ -1751,7 +1737,7 @@ MidiRegionView::add_note(const boost::shared_ptr<NoteType> note, bool visible)
                        event->show_velocity();
                }
 
-               event->on_channel_selection_change(_last_channel_selection);
+               event->on_channel_selection_change (get_selected_channels());
                _events.push_back(event);
 
                if (visible) {
@@ -3220,20 +3206,21 @@ MidiRegionView::set_frame_color()
 }
 
 void
-MidiRegionView::midi_channel_mode_changed(ChannelMode mode, uint16_t mask)
+MidiRegionView::midi_channel_mode_changed ()
 {
+       MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+       uint16_t mask = mtv->midi_track()->get_playback_channel_mask();
+       ChannelMode mode = mtv->midi_track()->get_playback_channel_mode ();
+
        if (mode == ForceChannel) {
                mask = 0xFFFF; // Show all notes as active (below)
        }
 
        // Update notes for selection
        for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
-               (*i)->on_channel_selection_change(mask);
+               (*i)->on_channel_selection_change (mask);
        }
 
-       _last_channel_selection = mask;
-       _last_channel_mode = mode;
-
        _patch_changes.clear ();
        display_patch_changes ();
 }
@@ -3399,7 +3386,7 @@ MidiRegionView::goto_next_note (bool add_to_selection)
        time_sort_events ();
 
        MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
-       uint16_t const channel_mask = mtv->channel_selector().get_selected_channels ();
+       uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask();
 
        for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
                if ((*i)->selected()) {
@@ -3436,7 +3423,7 @@ MidiRegionView::goto_previous_note (bool add_to_selection)
        time_sort_events ();
 
        MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
-       uint16_t const channel_mask = mtv->channel_selector().get_selected_channels ();
+       uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask ();
 
        for (Events::reverse_iterator i = _events.rbegin(); i != _events.rend(); ++i) {
                if ((*i)->selected()) {
@@ -3562,7 +3549,7 @@ MidiRegionView::maybe_select_by_position (GdkEventButton* ev, double /*x*/, doub
        Events e;
        MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
 
-       uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
+       uint16_t chn_mask = mtv->midi_track()->get_playback_channel_mask();
 
        if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
                get_events (e, Evoral::Sequence<Evoral::MusicalTime>::PitchGreaterThanOrEqual, (uint8_t) floor (note), chn_mask);
@@ -3687,8 +3674,8 @@ MidiRegionView::data_recorded (boost::weak_ptr<MidiSource> w)
                Evoral::MIDIEvent<MidiBuffer::TimeType> const ev (*i, false);
 
                if (ev.is_channel_event()) {
-                       if (_last_channel_mode == FilterChannels) {
-                               if (((uint16_t(1) << ev.channel()) & _last_channel_selection) == 0) {
+                       if (get_channel_mode() == FilterChannels) {
+                               if (((uint16_t(1) << ev.channel()) & get_selected_channels()) == 0) {
                                        continue;
                                }
                        }
@@ -3883,3 +3870,18 @@ MidiRegionView::note_button_release ()
        delete _note_player;
        _note_player = 0;
 }
+
+ChannelMode
+MidiRegionView::get_channel_mode () const
+{
+       RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (&trackview);
+       return rtav->midi_track()->get_playback_channel_mode();
+}
+
+uint16_t
+MidiRegionView::get_selected_channels () const
+{
+       RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (&trackview);
+       return rtav->midi_track()->get_playback_channel_mask();
+}
+
index 689e0ab2d0d9bc2e8ef5bb7987a507634a76863a..5f374da55cc85620e99b808369c15ca57fe6dd4c 100644 (file)
@@ -355,7 +355,8 @@ private:
        bool canvas_event(GdkEvent* ev);
        bool note_canvas_event(GdkEvent* ev);
 
-       void midi_channel_mode_changed(ARDOUR::ChannelMode mode, uint16_t mask);
+       void midi_channel_mode_changed ();
+        PBD::ScopedConnection _channel_mode_changed_connection;
        void instrument_settings_changed ();
        PBD::ScopedConnection _instrument_changed_connection;
 
@@ -377,9 +378,6 @@ private:
        void show_verbose_cursor (std::string const &, double, double) const;
        void show_verbose_cursor (boost::shared_ptr<NoteType>) const;
 
-       ARDOUR::ChannelMode _last_channel_mode;
-       uint16_t _last_channel_selection;
-
        uint8_t  _current_range_min;
        uint8_t  _current_range_max;
 
@@ -480,6 +478,9 @@ private:
        Gdk::Cursor* pre_press_cursor;
 
        NotePlayer* _note_player;
+
+        ARDOUR::ChannelMode get_channel_mode() const;
+        uint16_t get_selected_channels () const;
 };
 
 
index 9fe3a774502b455e30fb4f56ddcd7b5efb0eb1de..3b8e4932fbde7bea9fc2f15ba10da55f92412388 100644 (file)
@@ -19,6 +19,8 @@
 #include <cstdlib>
 #include <cmath>
 
+#include <strings.h> // for ffs(3)
+
 #include <algorithm>
 #include <string>
 #include <vector>
@@ -66,6 +68,7 @@
 #include "ghostregion.h"
 #include "gui_thread.h"
 #include "keyboard.h"
+#include "midi_channel_selector.h"
 #include "midi_scroomer.h"
 #include "midi_streamview.h"
 #include "midi_region_view.h"
@@ -94,8 +97,8 @@ using namespace Gtkmm2ext;
 using namespace Editing;
 
 // Minimum height at which a control is displayed
-static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
-static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
+static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 140;
+static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
 
 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
        : AxisView(sess) // virtually inherited
@@ -110,6 +113,7 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& can
        , _meter_color_mode_item(0)
        , _channel_color_mode_item(0)
        , _track_color_mode_item(0)
+       , _channel_selector (0)
        , _step_edit_item (0)
        , controller_menu (0)
        , _step_editor (0)
@@ -210,6 +214,22 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
                _view->RegionViewAdded.connect (
                        sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
 
+               midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
+                                                                 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
+                                                                 gui_context());
+               midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
+                                                                 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
+                                                                 gui_context());
+               midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
+                                                                 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
+                                                                 gui_context());
+               midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
+                                                                 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
+                                                                 gui_context());
+
+               playback_channel_mode_changed ();
+               capture_channel_mode_changed ();
+
                if (!_editor.have_idled()) {
                        /* first idle will do what we need */
                } else {
@@ -245,29 +265,38 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
        _midi_controls_box.set_homogeneous(false);
        _midi_controls_box.set_border_width (10);
 
-       if (!patch_manager.all_models().empty()) {
-               _channel_selector.set_border_width(2);
-               _channel_selector.show_all ();
+       _channel_status_box.set_homogeneous (false);
+       _channel_status_box.set_spacing (6);
+       
+       _channel_selector_button.set_label (_("Chns"));
 
-               _midi_controls_box.resize(3, 2);
-               _midi_controls_box.attach(_channel_selector, 0, 2, 0, 1);
-               
-               _midi_controls_box.attach(*manage(new HSeparator()), 0, 2, 1, 2);
+       /* fixed sized labels to prevent silly nonsense */
+
+       _playback_channel_status.set_size_request (65, -1);
+       _capture_channel_status.set_size_request (60, -1);
+
+       _channel_status_box.pack_start (_playback_channel_status, false, false);
+       _channel_status_box.pack_start (_capture_channel_status, false, false);
+       _channel_status_box.pack_start (_channel_selector_button, false, false);
+       _channel_status_box.show_all ();
+
+       _channel_selector_button.signal_clicked().connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
+       
+       _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
+
+       if (!patch_manager.all_models().empty()) {
 
                _midnam_model_selector.set_size_request(22, 30);
                _midnam_model_selector.set_border_width(2);
                _midnam_model_selector.show ();
-               _midi_controls_box.attach(_midnam_model_selector, 0, 1, 2, 3);
+               _midi_controls_box.pack_start (_midnam_model_selector);
 
                _midnam_custom_device_mode_selector.set_size_request(10, 30);
                _midnam_custom_device_mode_selector.set_border_width(2);
                _midnam_custom_device_mode_selector.show ();
 
-               _midi_controls_box.attach(_midnam_custom_device_mode_selector, 0, 1, 3, 4);
-       } else {
-               _midi_controls_box.attach(_channel_selector, 0, 1, 0, 1);
-               _channel_selector.show_all ();
-       }
+               _midi_controls_box.pack_start (_midnam_custom_device_mode_selector);
+       } 
 
        model_changed();
        custom_device_mode_changed();
@@ -279,19 +308,11 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
 
        controls_vbox.pack_start(_midi_controls_box, false, false);
 
-       // restore channel selector settings
-       _channel_selector.set_channel_mode(midi_track()->get_channel_mode(),
-                                          midi_track()->get_channel_mask());
-       _channel_selector.mode_changed.connect(
-               sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
-       _channel_selector.mode_changed.connect(
-               sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
-
        const string color_mode = gui_property ("color-mode");
        if (!color_mode.empty()) {
                _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
-               if (_color_mode == ChannelColors) {
-                       _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+               if (_channel_selector && _color_mode == ChannelColors) {
+                       _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
                }
        }
 
@@ -334,6 +355,8 @@ MidiTimeAxisView::first_idle ()
 
 MidiTimeAxisView::~MidiTimeAxisView ()
 {
+       delete _channel_selector;
+
        delete _piano_roll_header;
        _piano_roll_header = 0;
 
@@ -468,10 +491,36 @@ MidiTimeAxisView::append_extra_display_menu_items ()
 
        items.push_back (MenuElem (_("Note Range"), *range_menu));
        items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
+       items.push_back (MenuElem (_("Channel Selector"),
+                                  sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
 
+       color_mode_menu = build_color_mode_menu();
+       if (color_mode_menu) {
+               items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
+       }
+       
        items.push_back (SeparatorElem ());
 }
 
+void
+MidiTimeAxisView::toggle_channel_selector ()
+{
+       if (!_channel_selector) {
+               _channel_selector = new MidiChannelSelectorWindow (midi_track());
+
+               if (_color_mode == ChannelColors) {
+                       _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+               } else {
+                       _channel_selector->set_default_channel_color ();
+               }
+
+               _channel_selector->set_position (WIN_POS_MOUSE);
+               _channel_selector->show_all ();
+       } else {
+               _channel_selector->cycle_visibility ();
+       }
+}
+
 void
 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
 {
@@ -493,7 +542,7 @@ MidiTimeAxisView::build_automation_action_menu (bool for_selection)
 
        MenuList& automation_items = automation_action_menu->items();
 
-       uint16_t selected_channels = _channel_selector.get_selected_channels();
+       uint16_t selected_channels = midi_track()->get_playback_channel_mask();
 
        if (selected_channels !=  0) {
 
@@ -537,7 +586,7 @@ MidiTimeAxisView::build_automation_action_menu (bool for_selection)
 void
 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
 {
-       const uint16_t selected_channels = _channel_selector.get_selected_channels();
+       const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
 
        for (uint8_t chn = 0; chn < 16; chn++) {
                if (selected_channels & (0x0001 << chn)) {
@@ -564,7 +613,7 @@ MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
           structure if there is more than 1 selected.
         */
 
-       const uint16_t selected_channels = _channel_selector.get_selected_channels();
+       const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
        int chn_cnt = 0;
 
        for (uint8_t chn = 0; chn < 16; chn++) {
@@ -665,7 +714,7 @@ MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl
 {
        using namespace Menu_Helpers;
 
-       const uint16_t selected_channels = _channel_selector.get_selected_channels();
+       const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
        for (uint8_t chn = 0; chn < 16; chn++) {
                if (selected_channels & (0x0001 << chn)) {
 
@@ -706,7 +755,7 @@ MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_
 {
        using namespace Menu_Helpers;
 
-       const uint16_t selected_channels = _channel_selector.get_selected_channels();
+       const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
 
        Menu* chn_menu = manage (new Menu);
        MenuList& chn_items (chn_menu->items());
@@ -804,7 +853,7 @@ MidiTimeAxisView::build_controller_menu ()
           combination covering the currently selected channels for this track
        */
 
-       const uint16_t selected_channels = _channel_selector.get_selected_channels();
+       const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
 
        /* count the number of selected channels because we will build a different menu
           structure if there is more than 1 selected.
@@ -982,10 +1031,12 @@ MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bo
                        return;
                }
                
-               if (mode == ChannelColors) {
-                       _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
-               } else {
-                       _channel_selector.set_default_channel_color();
+               if (_channel_selector) {
+                       if (mode == ChannelColors) {
+                               _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+                       } else {
+                               _channel_selector->set_default_channel_color();
+                       }
                }
                
                _color_mode = mode;
@@ -1168,7 +1219,7 @@ MidiTimeAxisView::set_note_selection (uint8_t note)
                return;
        }
 
-       uint16_t chn_mask = _channel_selector.get_selected_channels();
+       uint16_t chn_mask = midi_track()->get_playback_channel_mask();
 
        if (_view->num_selected_regionviews() == 0) {
                _view->foreach_regionview (
@@ -1188,7 +1239,7 @@ MidiTimeAxisView::add_note_selection (uint8_t note)
                return;
        }
 
-       const uint16_t chn_mask = _channel_selector.get_selected_channels();
+       const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
 
        if (_view->num_selected_regionviews() == 0) {
                _view->foreach_regionview (
@@ -1208,7 +1259,7 @@ MidiTimeAxisView::extend_note_selection (uint8_t note)
                return;
        }
 
-       const uint16_t chn_mask = _channel_selector.get_selected_channels();
+       const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
 
        if (_view->num_selected_regionviews() == 0) {
                _view->foreach_regionview (
@@ -1228,7 +1279,7 @@ MidiTimeAxisView::toggle_note_selection (uint8_t note)
                return;
        }
 
-       const uint16_t chn_mask = _channel_selector.get_selected_channels();
+       const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
 
        if (_view->num_selected_regionviews() == 0) {
                _view->foreach_regionview (
@@ -1272,7 +1323,7 @@ MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
           the right ones.
        */
 
-       const uint16_t selected_channels = _channel_selector.get_selected_channels();
+       const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
        bool changed = false;
 
        no_redraw = true;
@@ -1392,7 +1443,7 @@ MidiTimeAxisView::stop_step_editing ()
 uint8_t
 MidiTimeAxisView::get_channel_for_add () const
 {
-       uint16_t const chn_mask = _channel_selector.get_selected_channels ();
+       uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
        int chn_cnt = 0;
        uint8_t channel = 0;
 
@@ -1426,3 +1477,35 @@ MidiTimeAxisView::contents_height_changed ()
 {
        _range_scroomer->set_size_request (-1, _view->child_height ());
 }
+
+void
+MidiTimeAxisView::playback_channel_mode_changed ()
+{
+       switch (midi_track()->get_playback_channel_mode()) {
+       case AllChannels:
+               _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), ("all")));
+               break;
+       case FilterChannels:
+               _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), ("some")));
+               break;
+       case ForceChannel:
+               _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), ("all"), ffs (midi_track()->get_playback_channel_mask())));
+               break;
+       }
+}
+
+void
+MidiTimeAxisView::capture_channel_mode_changed ()
+{
+       switch (midi_track()->get_capture_channel_mode()) {
+       case AllChannels:
+               _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), ("all")));
+               break;
+       case FilterChannels:
+               _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), ("some")));
+               break;
+       case ForceChannel:
+               _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), ("all"), ffs (midi_track()->get_capture_channel_mask())));
+               break;
+       }
+}
index 1f179baca67cfa25548181524c920920d940ad17..25e89fc2e08e47ff922c8d1b3eeb260d87ab9f70 100644 (file)
@@ -39,7 +39,6 @@
 #include "route_time_axis.h"
 #include "canvas.h"
 #include "midi_streamview.h"
-#include "midi_channel_selector.h"
 
 namespace MIDI {
 namespace Name {
@@ -62,6 +61,7 @@ class MidiScroomer;
 class PianoRollHeader;
 class StepEntry;
 class StepEditor;
+class MidiChannelSelectorWindow;
 
 class MidiTimeAxisView : public RouteTimeAxisView
 {
@@ -92,12 +92,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
 
        void update_range();
 
-       sigc::signal<void, ARDOUR::ChannelMode, uint16_t>& signal_channel_mode_changed() {
-               return _channel_selector.mode_changed;
-       }
-
-       const MidiMultipleChannelSelector& channel_selector() { return _channel_selector; }
-
        Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
 
        StepEditor* step_editor() { return _step_editor; }
@@ -140,8 +134,12 @@ class MidiTimeAxisView : public RouteTimeAxisView
        Gtk::RadioMenuItem*          _meter_color_mode_item;
        Gtk::RadioMenuItem*          _channel_color_mode_item;
        Gtk::RadioMenuItem*          _track_color_mode_item;
-       Gtk::Table                   _midi_controls_box;
-       MidiMultipleChannelSelector  _channel_selector;
+        Gtk::Label                   _playback_channel_status;
+        Gtk::Label                   _capture_channel_status;
+       Gtk::HBox                    _channel_status_box;
+        Gtk::Button                  _channel_selector_button;
+       Gtk::VBox                    _midi_controls_box;
+       MidiChannelSelectorWindow*   _channel_selector;
        Gtk::ComboBoxText            _midnam_model_selector;
        Gtk::ComboBoxText            _midnam_custom_device_mode_selector;
 
@@ -157,6 +155,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
        void add_single_channel_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, int ctl, const std::string& name);
        void add_multi_channel_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, int ctl, const std::string& name);
        void build_controller_menu ();
+        void toggle_channel_selector ();
+        void channel_selector_hidden ();
        void set_channel_mode (ARDOUR::ChannelMode, uint16_t);
 
        void set_note_selection (uint8_t note);
@@ -176,6 +176,9 @@ class MidiTimeAxisView : public RouteTimeAxisView
        ParameterMenuMap _controller_menu_map;
 
        StepEditor* _step_editor;
+
+        void capture_channel_mode_changed();
+        void playback_channel_mode_changed();
 };
 
 #endif /* __ardour_midi_time_axis_h__ */
index 37078b8d04a6ed306db0f3be89b71dd6334fecf2..daec1eede1c8f8bcc5c04681885637dabd03b414 100644 (file)
@@ -412,10 +412,6 @@ MonoPanner::on_key_press_event (GdkEventKey* ev)
                 step = one_degree * 5.0;
         }
 
-        /* up/down control width because we consider pan position more "important"
-           (and thus having higher "sense" priority) than width.
-        */
-
         switch (ev->keyval) {
         case GDK_Left:
                 pv -= step;
@@ -425,6 +421,10 @@ MonoPanner::on_key_press_event (GdkEventKey* ev)
                 pv += step;
                 position_control->set_value (pv);
                 break;
+       case GDK_0:
+       case GDK_KP_0:
+               position_control->set_value (0.0);
+               break;
         default:
                 return false;
         }
index 77b8f26ca9533e6e4c63aa58ce00084199174b97..5bca4c7be07e7534350ff702093151e2625b15e3 100644 (file)
@@ -83,7 +83,7 @@ PluginSelector::PluginSelector (PluginManager& mgr)
           related to "hidden"
        */
        plugin_display.append_column (_("Fav"), plugin_columns.favorite);
-       plugin_display.append_column (_("Hid"), plugin_columns.hidden);
+       plugin_display.append_column (_("Hide"), plugin_columns.hidden);
        plugin_display.append_column (_("Available Plugins"), plugin_columns.name);
        plugin_display.append_column (_("Type"), plugin_columns.type_name);
        plugin_display.append_column (_("Category"), plugin_columns.category);
@@ -820,6 +820,8 @@ PluginSelector::hidden_changed (const std::string& path)
                manager.set_status (pi->type, pi->unique_id, status);
 
                manager.save_statuses ();
+
+               build_plugin_menu ();
        }
        in_row_change = false;
 }
index 788951f143a62e3b1061357489be546281c49f28..0dabc5f5e8e1bc0e741179e9b4145fa40c98cc2e 100644 (file)
@@ -299,7 +299,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible {
        virtual void set_xjadeo_sensitive (bool onoff) = 0;
        virtual int  get_videotl_bar_height () const = 0;
        virtual void set_video_timeline_height (const int h) = 0;
-       virtual void embed_audio_from_video (std::string) = 0;
+       virtual void embed_audio_from_video (std::string, framepos_t n = 0) = 0;
        virtual void export_video () = 0;
 #endif
 
index d58ad2994c1c05504bc4306a5f5600a440c40e80..4a115b0f31363e8281a9f59f299b431150b46d1f 100644 (file)
@@ -818,35 +818,43 @@ public:
                , _show_xjadeo_setup_button (_("Show Video Monitor Option Dialog"))
                , _show_video_export_info_button (_("Show Video Export Info before export"))
                , _show_video_server_dialog_button (_("Show Video Server Startup Dialog"))
+               , _video_advanced_setup_button (_("Advanced Setup (remote video server)"))
        {
-               Table* t = manage (new Table (2, 6));
+               Table* t = manage (new Table (2, 7));
                t->set_spacings (4);
 
+               t->attach (_video_advanced_setup_button, 0, 2, 0, 1);
+               _video_advanced_setup_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::video_advanced_setup_toggled));
+               Gtkmm2ext::UI::instance()->set_tip (_video_advanced_setup_button,
+                                           _("<b>When enabled</b> you can speficify a custom video-server URL and docroot. - Do not enable this option unless you know what you are doing."));
+
                Label* l = manage (new Label (_("Video Server URL:")));
                l->set_alignment (0, 0.5);
-               t->attach (*l, 0, 1, 0, 1, FILL);
-               t->attach (_video_server_url_entry, 1, 2, 0, 1, FILL);
+               t->attach (*l, 0, 1, 1, 2, FILL);
+               t->attach (_video_server_url_entry, 1, 2, 1, 2, FILL);
                Gtkmm2ext::UI::instance()->set_tip (_video_server_url_entry,
                                            _("Base URL of the video-server including http prefix. This is usually 'http://hostname.example.org:1554/' and defaults to 'http://localhost:1554/' when the video-server is runing locally"));
 
-               l = manage (new Label (_("Video Server Docroot:")));
+               l = manage (new Label (_("Video Folder:")));
                l->set_alignment (0, 0.5);
-               t->attach (*l, 0, 1, 1, 2, FILL);
-               t->attach (_video_server_docroot_entry, 1, 2, 1, 2);
+               t->attach (*l, 0, 1, 2, 3, FILL);
+               t->attach (_video_server_docroot_entry, 1, 2, 2, 3);
                Gtkmm2ext::UI::instance()->set_tip (_video_server_docroot_entry,
-                                           _("Local path to the video-server docroot. If the server runs remotely, it should point to a network mounted folder of the server's docroot or be left empty if it is unvailable. It is used for the local video-monitor and file-browsing when opening/adding a video file."));
+                                           _("Local path to the video-server document-root. Only files below this directory will be accessible by the video-server. If the server run on a remote host, it should point to a network mounted folder of the server's docroot or be left empty if it is unvailable. It is used for the local video-monitor and file-browsing when opening/adding a video file."));
 
-               t->attach (_show_xjadeo_setup_button, 0, 2, 3, 4);
+               /* small vspace  y=3..4 */
+
+               t->attach (_show_xjadeo_setup_button, 0, 2, 4, 5);
                _show_xjadeo_setup_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_xjadeo_setup_toggled));
                Gtkmm2ext::UI::instance()->set_tip (_show_xjadeo_setup_button,
                                            _("<b>When enabled</b> an option dialog is presented before opening the video monitor"));
 
-               t->attach (_show_video_export_info_button, 0, 2, 4, 5);
+               t->attach (_show_video_export_info_button, 0, 2, 5, 6);
                _show_video_export_info_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_export_info_toggled));
                Gtkmm2ext::UI::instance()->set_tip (_show_video_export_info_button,
                                            _("<b>When enabled</b> an information window with details is displayed before the video-export dialog."));
 
-               t->attach (_show_video_server_dialog_button, 0, 2, 5, 6);
+               t->attach (_show_video_server_dialog_button, 0, 2, 6, 7);
                _show_video_server_dialog_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_server_dialog_toggled));
                Gtkmm2ext::UI::instance()->set_tip (_show_video_server_dialog_button,
                                            _("<b>When enabled</b> the video server is never launched automatically without confirmation"));
@@ -887,6 +895,12 @@ public:
                _rc_config->set_show_video_server_dialog (x);
        }
 
+       void video_advanced_setup_toggled ()
+       {
+               bool const x = _video_advanced_setup_button.get_active ();
+               _rc_config->set_video_advanced_setup(x);
+       }
+
        void parameter_changed (string const & p)
        {
                if (p == "video-server-url") {
@@ -899,6 +913,14 @@ public:
                } else if (p == "show-video-export-info") {
                        bool const x = _rc_config->get_show_video_export_info();
                        _show_video_export_info_button.set_active (x);
+               } else if (p == "show-video-server-dialog") {
+                       bool const x = _rc_config->get_show_video_server_dialog();
+                       _show_video_server_dialog_button.set_active (x);
+               } else if (p == "video-advanced-setup") {
+                       bool const x = _rc_config->get_video_advanced_setup();
+                       _video_advanced_setup_button.set_active(x);
+                       _video_server_docroot_entry.set_sensitive(x);
+                       _video_server_url_entry.set_sensitive(x);
                }
        }
 
@@ -908,7 +930,8 @@ public:
                parameter_changed ("video-server-docroot");
                parameter_changed ("video-monitor-setup-dialog");
                parameter_changed ("show-video-export-info");
-               parameter_changed ("how-video-server-dialog");
+               parameter_changed ("show-video-server-dialog");
+               parameter_changed ("video-advanced-setup");
        }
 
 private:
@@ -918,6 +941,7 @@ private:
        CheckButton _show_xjadeo_setup_button;
        CheckButton _show_video_export_info_button;
        CheckButton _show_video_server_dialog_button;
+       CheckButton _video_advanced_setup_button;
 };
 #endif
 
index 041cbb59e16c6c5428ae84519c7abfc90b1f7015..784203bf6f2aae16afa0d189e83d7a72225f94d1 100644 (file)
@@ -639,10 +639,6 @@ RouteTimeAxisView::build_display_menu ()
                        items.push_back (MenuElem (_("Mode"), *mode_menu));
                }
 
-               color_mode_menu = build_color_mode_menu();
-               if (color_mode_menu) {
-                       items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
-               }
 
                items.push_back (SeparatorElem());
 
index 22e71d75343a4b2d47e570a398f96ef18040fe51..00b212710e63392a610d702523b9eac09c0fc83f 100644 (file)
@@ -306,7 +306,6 @@ SystemExec::output_interposer()
                ReadStdout(data, bytesRead);/* EMIT SIGNAL */
        }
        Terminated();/* EMIT SIGNAL */
-       terminate();
 }
 
 void
@@ -409,6 +408,7 @@ SystemExec::make_argp(std::string args) {
 void
 SystemExec::terminate ()
 {
+       ::pthread_mutex_lock(&write_lock);
        close_stdin();
        if (pid) {
                ::usleep(100000);
@@ -428,6 +428,8 @@ SystemExec::terminate ()
 
        wait();
        if (thread_active) pthread_join(thread_id_tt, NULL);
+       thread_active = false;
+       ::pthread_mutex_unlock(&write_lock);
 }
 
 int
@@ -615,7 +617,6 @@ SystemExec::output_interposer()
                ReadStdout(rv, r);/* EMIT SIGNAL */
        }
        Terminated();/* EMIT SIGNAL */
-       terminate();
 }
 
 void
@@ -626,6 +627,7 @@ SystemExec::close_stdin()
        ::close(pin[1]);
        ::close(pout[0]);
        ::close(pout[1]);
+       pin[1] = - 1; // mark as closed
 }
 
 int
@@ -655,6 +657,7 @@ SystemExec::write_to_stdin(std::string d, size_t len)
                }
                c += r;
        }
+       fsync(pin[1]);
        ::pthread_mutex_unlock(&write_lock);
        return c;
 }
index a38d9c45f094321d89898e5e43181ed61a452a01..e886c64f6441c01e8636b1083a584c3603654970 100644 (file)
@@ -47,22 +47,35 @@ TranscodeFfmpeg::TranscodeFfmpeg (std::string f)
 #endif
 
        std::string ff_file_path;
-       if (find_file_in_search_path (PBD::SearchPath(Glib::getenv("PATH")), X_("ffmpeg"), ff_file_path)) { ffmpeg_exe = ff_file_path; }
-       else if (find_file_in_search_path (PBD::SearchPath(Glib::getenv("PATH")), X_("avconv"), ff_file_path)) { ffmpeg_exe = ff_file_path; }
-       else if (find_file_in_search_path (PBD::SearchPath(std::string("/usr/local/bin/")), X_("ffmpeg_harvid"), ff_file_path)) { ffmpeg_exe = ff_file_path; }
+       if (find_file_in_search_path (PBD::SearchPath(Glib::getenv("PATH")), X_("ffmpeg_harvid"), ff_file_path)) { ffmpeg_exe = ff_file_path; }
+       else if (Glib::file_test(X_("C:\\Program Files\\harvid\\ffmpeg.exe"), Glib::FILE_TEST_EXISTS)) {
+               ffmpeg_exe = X_("C:\\Program Files\\ffmpeg\\ffmpeg.exe");
+       }
        else if (Glib::file_test(X_("C:\\Program Files\\ffmpeg\\ffmpeg.exe"), Glib::FILE_TEST_EXISTS)) {
                ffmpeg_exe = X_("C:\\Program Files\\ffmpeg\\ffmpeg.exe");
        }
 
-       if (find_file_in_search_path (PBD::SearchPath(Glib::getenv("PATH")), X_("ffprobe"), ff_file_path)) { ffprobe_exe = ff_file_path; }
-//else if (find_file_in_search_path (PBD::SearchPath(Glib::getenv("PATH")), X_("avprobe"), ff_file_path)) { ffprobe_exe = ff_file_path; }
-       else if (find_file_in_search_path (PBD::SearchPath(std::string("/usr/local/bin/")), X_("ffprobe_harvid"), ff_file_path)) { ffprobe_exe = ff_file_path; }
+       if (find_file_in_search_path (PBD::SearchPath(Glib::getenv("PATH")), X_("ffprobe_harvid"), ff_file_path)) { ffprobe_exe = ff_file_path; }
+       else if (Glib::file_test(X_("C:\\Program Files\\harvid\\ffprobe.exe"), Glib::FILE_TEST_EXISTS)) {
+               ffprobe_exe = X_("C:\\Program Files\\ffmpeg\\ffprobe.exe");
+       }
        else if (Glib::file_test(X_("C:\\Program Files\\ffmpeg\\ffprobe.exe"), Glib::FILE_TEST_EXISTS)) {
                ffprobe_exe = X_("C:\\Program Files\\ffmpeg\\ffprobe.exe");
        }
 
        if (ffmpeg_exe.empty() || ffprobe_exe.empty()) {
-               PBD::warning << _("No ffprobe or ffmpeg executables could be found on this system. Transcoding is not possible until you install those tools.") << endmsg;
+               PBD::warning << _(
+                               "No ffprobe or ffmpeg executables could be found on this system.\n"
+                               "Video import and export is not possible until you install those tools.\n"
+                               "Ardour requires ffmpeg and ffprobe from ffmpeg.org - version 1.1 or newer.\n"
+                               "\n"
+                               "The tools are included with the Ardour releases from ardour.org "
+                               "and also available with the video-server at http://x42.github.com/harvid/\n"
+                               "\n"
+                               "Important: the files need to be installed in $PATH and named ffmpeg_harvid and ffprobe_harvid.\n"
+                               "If you already have a suitable ffmpeg installation on your system, we recommend creating "
+                               "symbolic links from ffmpeg to ffmpeg_harvid and from ffprobe to ffprobe_harvid.\n"
+                               ) << endmsg;
                return;
        }
        ffexecok = true;
@@ -85,8 +98,8 @@ TranscodeFfmpeg::probe ()
        char **argp;
        argp=(char**) calloc(7,sizeof(char*));
        argp[0] = strdup(ffprobe_exe.c_str());
-       argp[1] = strdup("-print_format"); // "-of"  ; new version and avprobe compat but avprobe does not yet support csv
-       argp[2] = strdup("csv"); // TODO use "csv=nk=0" and parse key/value pairs -> ffprobe version agnostic or parse XML or JSON key/value
+       argp[1] = strdup("-print_format");
+       argp[2] = strdup("csv=nk=0");
        argp[3] = strdup("-show_format");
        argp[4] = strdup("-show_streams");
        argp[5] = strdup(infile.c_str());
@@ -110,113 +123,100 @@ TranscodeFfmpeg::probe ()
        m_codec.clear();
        m_audio.clear();
 
+#define PARSE_FRACTIONAL_FPS \
+       { \
+               std::string::size_type pos; \
+               m_fps = atof(value.c_str()); \
+               pos = value.find_first_of('/'); \
+               if (pos != std::string::npos) { \
+                       m_fps = atof(value.substr(0, pos).c_str()) / atof(value.substr(pos+1).c_str()); \
+               } \
+       }
+
        for (std::vector<std::vector<std::string> >::iterator i = lines.begin(); i != lines.end(); ++i) {
                if (i->at(0) == X_("format")) {
                        /* format,filename,#streams,format-name,format-long-name,start-time,duration,size,bitrate */
                } else
                if (i->at(0) == X_("stream")) {
-                       /*--------- Stream format
-                        * stream,index,codec-name,codec-name-long,PROFILE,
-                        *   codec_time_base,codec_tag_string,codec_tag[hex],
-                        * VIDEO:
-                        *   width,height,has_b_frames,sample_aspect_ratio,display_aspect_ratio
-                        *   pix_fmt,level,
-                        *   timecode
-                        * AUDIO:
-                        *   sample_fmt,sample_rate,channels,bits_per_sample
-                        *
-                        * all cont'd;
-                        *   r_frame_rate,avg_frame_rate,time_base,start_time,duration,
-                        *   bit_rate,nb_frames,nb_read_frames,nb_read_packets
-                        *
-                        *---------- Example
-                        * stream,0,mpeg2video,MPEG-2 video,video,1/50,[0][0][0][0],0x0000,720,576,1,16:15,4:3,yuv420p,8,00:02:30:00,0x1e0,25/1,25/1,1/90000,0.360000,N/A,7000000,N/A,N/A,N/A
-                        * stream,1,ac3,ATSC A/52A (AC-3),audio,1/48000,[0][0][0][0],0x0000,s16,48000,6,0,-1,-1.000000,-1.000000,-1.000000,-1.000000,0x80,0/0,0/0,1/90000,0.280000,312.992000,448000,N/A,N/A,N/A
-                        * stream,2,ac3,ATSC A/52A (AC-3),audio,1/48000,[0][0][0][0],0x0000,s16,48000,2,0,-1,-1.000000,-1.000000,-1.000000,-1.000000,0x82,0/0,0/0,1/90000,0.280000,312.992000,384000,N/A,N/A,N/A
-                        * stream,3,ac3,ATSC A/52A (AC-3),audio,1/48000,[0][0][0][0],0x0000,s16,48000,2,0,-1,-1.000000,-1.000000,-1.000000,-1.000000,0x81,0/0,0/0,1/90000,0.280000,312.992000,192000,N/A,N/A,N/A
-                        */
-                       if (i->at(4) == X_("video") && m_width == 0) {
-                               std::string::size_type pos;
-
-                               m_width = atoi(i->at(8).c_str());
-                               m_height = atoi(i->at(9).c_str());
-                               m_codec = i->at(3) + " -- " + i->at(2);
-                               m_fps = atof(i->at(17).c_str());
-
-                               pos = i->at(17).find_first_of('/');
-                               if (pos != std::string::npos) {
-                                       m_fps = atof(i->at(17).substr(0, pos).c_str()) / atof(i->at(17).substr(pos+1).c_str());
+                       if (i->at(5) == X_("codec_type=video") && m_width == 0) {
+
+                               for (std::vector<std::string>::iterator kv = i->begin(); kv != i->end(); ++kv) {
+                                       const size_t kvsep = kv->find('=');
+                                       if(kvsep == std::string::npos) continue;
+                                       std::string key = kv->substr(0, kvsep);
+                                       std::string value = kv->substr(kvsep + 1);
+
+                                       if (key == X_("width")) {
+                                               m_width = atoi(value.c_str());
+                                       } else if (key == X_("height")) {
+                                               m_height = atoi(value.c_str());
+                                       } else if (key == X_("codec_name")) {
+                                               if (!m_codec.empty()) m_codec += " ";
+                                               m_codec += value;
+                                       } else if (key == X_("codec_long_name")) {
+                                               if (!m_codec.empty()) m_codec += " ";
+                                               m_codec += "[" + value + "]";
+                                       } else if (key == X_("codec_tag_string")) {
+                                               if (!m_codec.empty()) m_codec += " ";
+                                               m_codec += "(" + value + ")";
+                                       } else if (key == X_("r_frame_rate")) {
+                                               PARSE_FRACTIONAL_FPS
+                                       } else if (key == X_("time_base") && m_fps == 0) {
+                                               PARSE_FRACTIONAL_FPS
+                                       } else if (key == X_("timecode") && m_duration == 0) {
+                                               int h,m,s; char f[7];
+                                               if (sscanf(i->at(16).c_str(), "%d:%d:%d:%s",&h,&m,&s,f) == 4) {
+                                                       m_duration = (ARDOUR::framecnt_t) floor(m_fps * (
+                                                                       h * 3600.0
+                                                               + m * 60.0
+                                                               + s * 1.0
+                                                               + atoi(f) / pow(10, strlen(f))
+                                                       ));
+                                               }
+                                       } else if (key == X_("duration_ts")) {
+                                               m_duration = atof(value.c_str());
+                                       } else if (key == X_("duration") && m_duration == 0 && m_fps != 0) {
+                                               m_duration = atof(value.c_str()) * m_fps;
+                                       } else if (key == X_("display_aspect_ratio")) {
+                                               std::string::size_type pos;
+                                               pos = value.find_first_of(':');
+                                               if (pos != std::string::npos && atof(value.substr(pos+1).c_str()) != 0) {
+                                                       m_aspect = atof(value.substr(0, pos).c_str()) / atof(value.substr(pos+1).c_str());
+                                               }
+                                       }
                                }
 
-                               pos = i->at(12).find_first_of(':');
-                               m_aspect = 0;
-                               if (pos != std::string::npos && atof(i->at(12).substr(pos+1).c_str()) != 0) {
-                                       m_aspect = atof(i->at(12).substr(0, pos).c_str()) / atof(i->at(12).substr(pos+1).c_str());
-                               }
                                if (m_aspect == 0) {
                                        m_aspect = (double)m_width / (double)m_height;
                                }
 
-                               int h,m,s; char f[7];
-                               if (sscanf(i->at(15).c_str(), "%d:%d:%d:%s",&h,&m,&s,f) == 4) {
-                                       m_duration = (ARDOUR::framecnt_t) floor(m_fps * (
-                                                       h * 3600.0
-                                               + m * 60.0
-                                               + s * 1.0
-                                               + atoi(f) / pow(10, strlen(f))
-                                       ));
-                               } else {
-                                       m_duration = atof(i->at(21).c_str()) * m_fps;
-                               }
-
-                       } else if (i->at(4) == X_("audio")) {
+                       } else if (i->at(5) == X_("codec_type=audio")) { /* new ffprobe */
                                AudioStream as;
-                               as.name = i->at(3) + " " + i->at(2) + " " + i->at(8) + " " + i->at(9);
-                               as.stream_id  = i->at(1);
-                               as.channels   = atoi(i->at(10).c_str());
-                               m_audio.push_back(as);
-
-                       } else if (i->at(5) == X_("video") && m_width == 0) { /* new ffprobe */
-                               std::string::size_type pos;
+                               for (std::vector<std::string>::iterator kv = i->begin(); kv != i->end(); ++kv) {
+                                       const size_t kvsep = kv->find('=');
+                                       if(kvsep == std::string::npos) continue;
+                                       std::string key = kv->substr(0, kvsep);
+                                       std::string value = kv->substr(kvsep + 1);
+
+                                       if (key == X_("channels")) {
+                                               as.channels   = atoi(value.c_str());
+                                       } else if (key == X_("index")) {
+                                               as.stream_id  = value;
+                                       } else if (key == X_("codec_long_name")) {
+                                               if (!as.name.empty()) as.name += " ";
+                                               as.name += value;
+                                       } else if (key == X_("codec_name")) {
+                                               if (!as.name.empty()) as.name += " ";
+                                               as.name += value;
+                                       } else if (key == X_("sample_fmt")) {
+                                               if (!as.name.empty()) as.name += " ";
+                                               as.name += "FMT:" + value;
+                                       } else if (key == X_("sample_rate")) {
+                                               if (!as.name.empty()) as.name += " ";
+                                               as.name += "SR:" + value;
+                                       }
 
-                               m_width = atoi(i->at(9).c_str());
-                               m_height = atoi(i->at(10).c_str());
-                               m_codec = i->at(3) + " -- " + i->at(2);
-                               m_fps = atof(i->at(18).c_str());
-
-                               pos = i->at(18).find_first_of('/');
-                               if (pos != std::string::npos) {
-                                       m_fps = atof(i->at(18).substr(0, pos).c_str()) / atof(i->at(18).substr(pos+1).c_str());
-                               }
-
-                               pos = i->at(13).find_first_of(':');
-                               m_aspect = 0;
-                               if (pos != std::string::npos && atof(i->at(13).substr(pos+1).c_str()) != 0) {
-                                       m_aspect = atof(i->at(13).substr(0, pos).c_str()) / atof(i->at(13).substr(pos+1).c_str());
-                               }
-                               if (m_aspect == 0) {
-                                       m_aspect = (double)m_width / (double)m_height;
                                }
-
-                               int h,m,s; char f[7];
-                               if (sscanf(i->at(17).c_str(), "%d:%d:%d:%s",&h,&m,&s,f) == 4) {
-                                       m_duration = (ARDOUR::framecnt_t) floor(m_fps * (
-                                                       h * 3600.0
-                                               + m * 60.0
-                                               + s * 1.0
-                                               + atoi(f) / pow(10, strlen(f))
-                                       ));
-                               } else if (atof(i->at(23).c_str()) != 0) {
-                                       m_duration = atof(i->at(23).c_str());
-                               } else {
-                                       m_duration = atof(i->at(24).c_str()) * m_fps;
-                               }
-
-                       } else if (i->at(5) == X_("audio")) { /* new ffprobe */
-                               AudioStream as;
-                               as.name = i->at(3) + " " + i->at(2) + " " + i->at(9) + " " + i->at(10);
-                               as.stream_id  = i->at(1);
-                               as.channels   = atoi(i->at(11).c_str());
                                m_audio.push_back(as);
                        }
                }
@@ -228,7 +228,7 @@ TranscodeFfmpeg::probe ()
        while (ffcmd && --timeout) usleep (1000); // wait until 'ffprobe' terminated.
        if (timeout == 0) return false;
 
-#if 0 /* DEBUG */
+#if 1 /* DEBUG */
        printf("FPS: %f\n", m_fps);
        printf("Duration: %lu frames\n",(unsigned long)m_duration);
        printf("W/H: %ix%i\n",m_width, m_height);
index a4d02873995d1246a00a1e404a241312b7bde06a..8c68b5bca809de2287792b74e630adc057d255ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2010 Paul Davis
+    Copyright (C) 2010,2013 Paul Davis
     Author: Robin Gareus <robin@gareus.org>
 
     This program is free software; you can redistribute it and/or modify
@@ -45,7 +45,6 @@
 #include "utils.h"
 #include "opts.h"
 #include "transcode_video_dialog.h"
-#include "video_copy_dialog.h"
 #include "utils_videotl.h"
 #include "i18n.h"
 
@@ -59,16 +58,14 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
        , infn (infile)
        , path_label (_("Output File:"), Gtk::ALIGN_LEFT)
        , browse_button (_("Browse"))
-       , transcode_button (_("Transcode Video\n And Import"))
-       , copy_button (_("Copy Video\nFile Only"))
-       , audio_button (_("Extract and\nImport Audio Only"))
+       , transcode_button (_("OK"))
        , abort_button (_("Abort"))
        , progress_label ()
        , aspect_checkbox (_("Height = "))
        , height_adjustment (128, 0, 1920, 1, 16, 0)
        , height_spinner (height_adjustment)
        , bitrate_checkbox (_("Manual Override"))
-       , bitrate_adjustment (2000, 100, 10000, 10, 100, 0)
+       , bitrate_adjustment (2000, 500, 10000, 10, 100, 0)
        , bitrate_spinner (bitrate_adjustment)
 #if 1 /* tentative debug mode */
        , debug_checkbox (_("Debug Mode: Print ffmpeg Command and Output to stdout."))
@@ -79,7 +76,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
        transcoder = new TranscodeFfmpeg(infile);
        audiofile = "";
        pending_audio_extract = false;
-       pending_copy_file = false;
+       aborted = false;
 
        set_name ("TranscodeVideoDialog");
        set_position (Gtk::WIN_POS_MOUSE);
@@ -105,7 +102,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
        height_spinner.set_sensitive(false);
        bitrate_spinner.set_sensitive(false);
 
-       std::string dstdir = video_dest_dir(_session->session_directory().video_path(), Config->get_video_server_docroot());
+       std::string dstdir = video_dest_dir(_session->session_directory().video_path(), video_get_docroot(Config));
        std::string dstfn  = video_dest_file(dstdir, infile);
        path_entry.set_text (dstfn);
 
@@ -114,21 +111,21 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
        options_box->pack_start (*l, false, true, 4);
 
 
+       bool ffok = false;
        if (!transcoder->ffexec_ok()) {
-               l = manage (new Label (_("No ffprobe or ffmpeg executables could be found on this system. Transcoding is not possible until you install those tools."), 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 widow for more information."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
                l->set_line_wrap();
                options_box->pack_start (*l, false, true, 4);
-               transcode_button.set_sensitive(false);
                aspect_checkbox.set_sensitive(false);
                bitrate_checkbox.set_sensitive(false);
        }
        else if (!transcoder->probe_ok()) {
-               l = manage (new Label (string_compose(_("Video file-info could not be read. Most likely '%1' is not a valid video-file. It could also be a rare unsupported video codec or format."), infn), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+               l = manage (new Label (string_compose(_("File-info can not be read. Most likely '%1' is not a valid video-file or an unsupported video codec or format."), infn), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
                options_box->pack_start (*l, false, true, 4);
-               transcode_button.set_sensitive(false);
                aspect_checkbox.set_sensitive(false);
                bitrate_checkbox.set_sensitive(false);
        } else {
+               ffok = true;
                w = transcoder->get_width();
                h = transcoder->get_height();
                as = transcoder->get_audio();
@@ -179,10 +176,24 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
                t->attach (*l, 1, 2, 1, 2);
        }
 
-       l = manage (new Label (_("<b>Options</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+       l = manage (new Label (_("<b>Video</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
        l->set_use_markup ();
        options_box->pack_start (*l, false, true, 4);
 
+       video_combo.set_name ("PaddedButton");
+       video_combo.append_text(_("Do Not Import Video"));
+       video_combo.append_text(_("Reference From Current Location"));
+       if (ffok)  {
+               video_combo.append_text(_("Import/Transcode Video to Session"));
+               video_combo.set_active(2);
+       } else {
+               video_combo.set_active(1);
+               video_combo.set_sensitive(false);
+               audio_combo.set_sensitive(false);
+       }
+
+       options_box->pack_start (video_combo, false, false, 4);
+
        Table* t = manage (new Table (4, 3));
        t->set_spacings (4);
        options_box->pack_start (*t, true, true, 4);
@@ -243,11 +254,10 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
        get_vbox()->pack_start (*progress_box, false, false);
 
        browse_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::open_browse_dialog));
-       copy_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::prepare_copy));
-       audio_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::launch_audioonly));
        transcode_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::launch_transcode));
        abort_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::abort_clicked));
 
+       video_combo.signal_changed().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::video_combo_changed));
        audio_combo.signal_changed().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::audio_combo_changed));
        scale_combo.signal_changed().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::scale_combo_changed));
        aspect_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::aspect_checkbox_toggled));
@@ -256,11 +266,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
 
        update_bitrate();
 
-       audio_button.set_sensitive(false);
-
        cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
-       get_action_area()->pack_start (audio_button, false, false);
-       get_action_area()->pack_start (copy_button, false, false);
        get_action_area()->pack_start (transcode_button, false, false);
        show_all_children ();
        progress_box->hide();
@@ -305,7 +311,7 @@ TranscodeVideoDialog::finished ()
                }
                Gtk::Dialog::response(RESPONSE_CANCEL);
        } else {
-               if (pending_audio_extract || pending_copy_file) {
+               if (pending_audio_extract) {
                        StartNextStage();
                } else {
                  Gtk::Dialog::response(RESPONSE_ACCEPT);
@@ -314,65 +320,27 @@ TranscodeVideoDialog::finished ()
 }
 
 void
-TranscodeVideoDialog::prepare_copy ()
+TranscodeVideoDialog::launch_audioonly ()
 {
-       dialog_progress_mode();
-#if 1 /* tentative debug mode */
-       if (debug_checkbox.get_active()) {
-               transcoder->set_debug(true);
-       }
-#endif
-
        if (audio_combo.get_active_row_number() == 0) {
-               launch_copy();
-       } else {
-               aborted = false;
-               pending_copy_file = true;
-               StartNextStage.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::launch_copy , this), gui_context());
-               transcoder->Progress.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress , this, _1, _2), gui_context());
-               transcoder->Finished.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this), gui_context());
-               launch_extract();
+               finished();
+               return;
        }
-}
-
-void
-TranscodeVideoDialog::launch_audioonly ()
-{
        dialog_progress_mode();
-       path_entry.set_text("");
 #if 1 /* tentative debug mode */
        if (debug_checkbox.get_active()) {
                transcoder->set_debug(true);
        }
 #endif
-       if (audio_combo.get_active_row_number() == 0) {
-               return;
-       }
        transcoder->Progress.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress , this, _1, _2), gui_context());
        transcoder->Finished.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this), gui_context());
        launch_extract();
 }
 
-void
-TranscodeVideoDialog::launch_copy ()
-{
-       hide();
-       VideoCopyDialog *video_copy_dialog;
-       video_copy_dialog = new VideoCopyDialog(_session, infn);
-       video_copy_dialog->setup_non_interactive_copy(path_entry.get_text());
-       ResponseType r = (ResponseType) video_copy_dialog->run ();
-       video_copy_dialog->hide();
-       delete video_copy_dialog;
-       Gtk::Dialog::response(r);
-}
-
 void
 TranscodeVideoDialog::launch_extract ()
 {
-       audiofile= path_entry.get_text() + ".wav"; /* TODO: mktemp & check if file exists in audiofiles */
-       /* think: do_embed() vs do_import() - editor_videotimeline.cc
-        * directly use _session->session_directory().sound_path() ?!
-        */
+       audiofile= path_entry.get_text() + ".wav"; /* TODO: mktemp */
        int audio_stream;
        pending_audio_extract = false;
        aborted = false;
@@ -392,7 +360,6 @@ TranscodeVideoDialog::dialog_progress_mode ()
 {
        vbox->hide();
        cancel_button->hide();
-       copy_button.hide();
        transcode_button.hide();
        pbar.set_size_request(300,-1);
        progress_box->show();
@@ -401,8 +368,12 @@ TranscodeVideoDialog::dialog_progress_mode ()
 void
 TranscodeVideoDialog::launch_transcode ()
 {
+       if (video_combo.get_active_row_number() != 2) {
+               launch_audioonly();
+               return;
+       }
        std::string outfn = path_entry.get_text();
-       if (!confirm_video_outfn(outfn, Config->get_video_server_docroot())) return;
+       if (!confirm_video_outfn(outfn, video_get_docroot(Config))) return;
        progress_label.set_text (_("Transcoding Video.."));
        dialog_progress_mode();
 #if 1 /* tentative debug mode */
@@ -444,21 +415,33 @@ TranscodeVideoDialog::launch_transcode ()
 }
 
 void
-TranscodeVideoDialog::audio_combo_changed ()
+TranscodeVideoDialog::video_combo_changed ()
 {
-       bool use_audio = audio_combo.get_active_row_number() != 0;
-       audio_button.set_sensitive(use_audio);
-       if (use_audio) {
-               copy_button.set_label(_("Copy File And\nExtract Audio"));
+       int i = video_combo.get_active_row_number();
+       if (i != 2) {
+               scale_combo.set_sensitive(false);
+               aspect_checkbox.set_sensitive(false);
+               height_spinner.set_sensitive(false);
+               bitrate_checkbox.set_sensitive(false);
+               bitrate_spinner.set_sensitive(false);
        } else {
-               copy_button.set_label(_("Copy Video\nFile Only"));
+               scale_combo.set_sensitive(true);
+               aspect_checkbox.set_sensitive(true);
+               height_spinner.set_sensitive(true);
+               bitrate_checkbox.set_sensitive(true);
+               bitrate_spinner.set_sensitive(true);
        }
 }
 
+void
+TranscodeVideoDialog::audio_combo_changed ()
+{
+       ;
+}
+
 void
 TranscodeVideoDialog::scale_combo_changed ()
 {
-       update_bitrate();
        if (!aspect_checkbox.get_active()) {
                int h;
                if (scale_combo.get_active_row_number() == 0 ) {
@@ -468,6 +451,7 @@ TranscodeVideoDialog::scale_combo_changed ()
                }
                height_spinner.set_value(h);
        }
+       update_bitrate();
 }
 
 void
@@ -493,12 +477,15 @@ TranscodeVideoDialog::update_bitrate ()
        if (bitrate_checkbox.get_active() || !transcoder->probe_ok()) { return; }
        br *= transcoder->get_fps();
        br *= height_spinner.get_value();
+
        if (scale_combo.get_active_row_number() == 0 ) {
-               br *= transcoder->get_height();
+               br *= transcoder->get_width();
        } else {
                br *= atof(scale_combo.get_active_text().c_str());
        }
-       bitrate_spinner.set_value(floor(br/10000.0)*10);
+       if (br != 0) {
+               bitrate_spinner.set_value(floor(br/10000.0)*10);
+       }
 }
 
 void
@@ -521,4 +508,10 @@ TranscodeVideoDialog::open_browse_dialog ()
        }
 }
 
+enum VtlTranscodeOption
+TranscodeVideoDialog::import_option() {
+       int i = video_combo.get_active_row_number();
+       return static_cast<VtlTranscodeOption>(i);
+}
+
 #endif /* WITH_VIDEOTIMELINE */
index 9d334cf0d23e83867bbbff5645c457f3e8b85703..981079b3a84b615afbeced04a534bbc68755749a 100644 (file)
 
 #include "transcode_ffmpeg.h"
 
+enum VtlTranscodeOption {
+ VTL_IMPORT_NO_VIDEO = 0,
+ VTL_IMPORT_REFERENCE = 1,
+ VTL_IMPORT_TRANSCODED = 2
+};
+
 /** @class TranscodeVideoDialog
  *  @brief dialog-box and controller for importing video-files
  */
@@ -43,6 +49,7 @@ class TranscodeVideoDialog : public ArdourDialog , public PBD::ScopedConnectionL
 
        std::string get_filename () { return path_entry.get_text(); }
        std::string get_audiofile () { return audiofile; }
+       VtlTranscodeOption import_option ();
 
   private:
        void on_show ();
@@ -50,18 +57,16 @@ class TranscodeVideoDialog : public ArdourDialog , public PBD::ScopedConnectionL
        void abort_clicked ();
        void scale_combo_changed ();
        void audio_combo_changed ();
+       void video_combo_changed ();
        void aspect_checkbox_toggled ();
        void bitrate_checkbox_toggled ();
        void update_bitrate ();
        void launch_audioonly ();
        void launch_transcode ();
   void launch_extract ();
-       void prepare_copy ();
-       void launch_copy ();
        void dialog_progress_mode ();
        bool aborted;
        bool pending_audio_extract;
-       bool pending_copy_file;
        std::string audiofile;
        std::string infn;
        double m_aspect;
@@ -76,8 +81,6 @@ class TranscodeVideoDialog : public ArdourDialog , public PBD::ScopedConnectionL
        Gtk::Entry        path_entry;
        Gtk::Button       browse_button;
        Gtk::Button       transcode_button;
-       Gtk::Button       copy_button;
-       Gtk::Button       audio_button;
 
        Gtk::VBox* vbox;
        Gtk::Button *cancel_button;
@@ -87,6 +90,7 @@ class TranscodeVideoDialog : public ArdourDialog , public PBD::ScopedConnectionL
        Gtk::Label  progress_label;
        Gtk::ProgressBar pbar;
 
+       Gtk::ComboBoxText video_combo;
        Gtk::ComboBoxText scale_combo;
        Gtk::CheckButton  aspect_checkbox;
        Gtk::Adjustment   height_adjustment;
index adf7d25640682414e45a2c87cff0e9f15fe07374..93d54449020378f82adb9a6d52b1db4ecb03ac02 100644 (file)
@@ -28,8 +28,8 @@
 #include "pbd/error.h"
 #include "ardour/ardour.h"
 #include "ardour/session_directory.h"
-#include "ardour_dialog.h"
 #include "video_image_frame.h"
+#include "utils_videotl.h"
 
 #include "i18n.h"
 
@@ -93,6 +93,25 @@ video_dest_dir (const std::string sessiondir, const std::string docroot)
        return dir;
 }
 
+std::string
+video_get_docroot (ARDOUR::RCConfiguration* config)
+{
+       if (config->get_video_advanced_setup()) {
+               return config->get_video_server_docroot();
+       }
+       return X_("/");
+}
+
+std::string
+video_get_server_url (ARDOUR::RCConfiguration* config)
+{
+       if (config->get_video_advanced_setup()) {
+               return config->get_video_server_url();
+       }
+       return X_("http://localhost:1554");
+}
+
+
 std::string
 strip_file_extension (const std::string infile)
 {
index d4633be91a112ed3b935d3fd0efa4e76d1351c68..08ab429e4cd4b178928194cc84598c11737890cb 100644 (file)
@@ -28,6 +28,7 @@
 #include <string>
 #include <gtkmm.h>
 
+#include "ardour/rc_configuration.h"
 #include "ardour/types.h"
 #include "ardour/template_utils.h"
 #include "ardour_dialog.h"
@@ -41,6 +42,8 @@ std::string get_file_extension (const std::string infile);
 void ParseCSV(const std::string &csv, std::vector<std::vector<std::string> > &lines);
 std::string video_map_path (std::string server_docroot, std::string filepath);
 void video_draw_cross (Glib::RefPtr<Gdk::Pixbuf> img);
+std::string video_get_server_url (ARDOUR::RCConfiguration* config);
+std::string video_get_docroot (ARDOUR::RCConfiguration* config);
 
 bool video_query_info (
                std::string video_server_url,
diff --git a/gtk2_ardour/video_copy_dialog.cc b/gtk2_ardour/video_copy_dialog.cc
deleted file mode 100644 (file)
index 30d9383..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
-    Copyright (C) 2010 Paul Davis
-    Author: Robin Gareus <robin@gareus.org>
-
-    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.
-
-*/
-#ifdef WITH_VIDEOTIMELINE
-
-#include <cstdio>
-#include <string>
-#include <sstream>
-#include <iomanip>
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <sigc++/bind.h>
-#include <libgen.h>
-
-#include "pbd/error.h"
-#include "pbd/convert.h"
-#include "gtkmm2ext/utils.h"
-#include "ardour/session_directory.h"
-#include "ardour/profile.h"
-#include "ardour/template_utils.h"
-#include "ardour/session.h"
-#include "ardour_ui.h"
-#include "gui_thread.h"
-
-#include "utils_videotl.h"
-#include "utils.h"
-#include "opts.h"
-#include "video_copy_dialog.h"
-#include "i18n.h"
-
-using namespace Gtk;
-using namespace std;
-using namespace PBD;
-using namespace ARDOUR;
-
-VideoCopyDialog::VideoCopyDialog (Session* s, std::string infile)
-       : ArdourDialog (_("Import Video File "))
-       , infn (infile)
-       , path_label (_("Output File:"), Gtk::ALIGN_LEFT)
-       , browse_button (_("Browse"))
-       , copy_button (_("Copy/Embed"))
-       , abort_button (_("Abort"))
-       , progress_label ()
-{
-       set_session (s);
-       autostart = false;
-
-       set_name ("VideoCopyDialog");
-       set_position (Gtk::WIN_POS_MOUSE);
-       set_modal (true);
-       set_skip_taskbar_hint (true);
-       set_resizable (false);
-       p_connection = sigc::connection();
-
-       std::string dstdir = video_dest_dir(_session->session_directory().video_path(), Config->get_video_server_docroot());
-       std::string dstfn  = dstdir + G_DIR_SEPARATOR + Glib::path_get_basename(infile);
-       path_entry.set_text (dstfn);
-
-       path_hbox = manage (new HBox);
-       path_hbox->pack_start (path_label, false, false, 3);
-       path_hbox->pack_start (path_entry, true, true, 3);
-       path_hbox->pack_start (browse_button, false, false, 3);
-       browse_button.set_name ("PaddedButton");
-       path_entry.set_width_chars(38);
-
-       browse_button.signal_clicked().connect (sigc::mem_fun (*this, &VideoCopyDialog::open_browse_dialog));
-       copy_button.signal_clicked().connect (sigc::mem_fun (*this, &VideoCopyDialog::launch_copy));
-       abort_button.signal_clicked().connect (sigc::mem_fun (*this, &VideoCopyDialog::abort_clicked));
-
-       progress_box = manage (new VBox);
-       progress_box->pack_start (progress_label, false, false);
-       progress_box->pack_start (pbar, false, false);
-       progress_box->pack_start (abort_button, false, false);
-
-       get_vbox()->pack_start (*path_hbox, false, false);
-       get_vbox()->pack_start (*progress_box, false, false);
-
-
-       cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
-       get_action_area()->pack_start (copy_button, false, false);
-       show_all_children ();
-       progress_box->hide();
-}
-
-VideoCopyDialog::~VideoCopyDialog ()
-{
-}
-
-void
-VideoCopyDialog::setup_non_interactive_copy (std::string destfn)
-{
-       if (destfn.empty()) {
-               std::string dstdir = video_dest_dir(_session->session_directory().video_path(), Config->get_video_server_docroot());
-               outfn= dstdir + G_DIR_SEPARATOR + Glib::path_get_basename(infn);
-       } else {
-               outfn=destfn;
-       }
-       autostart=true;
-}
-
-void
-VideoCopyDialog::on_show ()
-{
-       if (autostart) {
-         Glib::signal_timeout().connect_once (sigc::mem_fun(*this, &VideoCopyDialog::launch_copy), 200);
-       }
-       Dialog::on_show ();
-}
-
-void
-VideoCopyDialog::abort_clicked ()
-{
-       aborted = true;
-}
-
-gint
-VideoCopyDialog::progress_timeout ()
-{
-       if (p_tot == 0) {
-               pbar.set_pulse_step(.5);
-               pbar.pulse();
-               return 1;
-       }
-       pbar.set_fraction ((double)p_cur / (double) p_tot);
-       return 1;
-}
-
-void*
-video_copy_thread (void *arg)
-{
-       VideoCopyDialog *cvd = static_cast<VideoCopyDialog*>(arg);
-       cvd->do_copy();
-       return 0;
-}
-
-
-void
-VideoCopyDialog::launch_copy ()
-{
-       if (!autostart) {
-               outfn = path_entry.get_text();
-       }
-       if (!confirm_video_outfn(outfn)) { return; }
-       p_cur = 0; p_tot = 0;
-
-       p_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &VideoCopyDialog::progress_timeout), 80);
-
-       pbar.set_size_request(300,-1);
-       progress_box->show();
-       path_hbox->hide();
-       cancel_button->hide();
-       copy_button.hide();
-       aborted = false;
-       finished = false;
-
-       pthread_create(&thread, NULL, video_copy_thread ,this);
-       while (!finished) {
-               if (gtk_events_pending()) {
-                       gtk_main_iteration ();
-               } else {
-                       usleep (10000);
-               }
-       }
-       pthread_join(thread, NULL);
-
-       p_connection.disconnect();
-
-       if (aborted) {
-               Gtk::Dialog::response(RESPONSE_CANCEL);
-       } else {
-               Gtk::Dialog::response(RESPONSE_ACCEPT);
-       }
-}
-
-void
-VideoCopyDialog::do_copy ()
-{
-       progress_label.set_text (_("Linking File."));
-
-       unlink (outfn.c_str());
-
-       bool try_hardlink = false; // Config->get_try_link_for_embed(); /* XXX */
-       struct stat sb;
-       if (lstat (infn.c_str(), &sb) == 0) {
-               p_tot = sb.st_size;
-               /* don't hardlink a symlink */
-               if ((sb.st_mode&S_IFMT) == S_IFLNK) {
-                       try_hardlink = false;
-                       if (stat (infn.c_str(), &sb) == 0) {
-                               p_tot = sb.st_size;
-                       }
-               }
-       } else {
-               /* Can not stat() input file */
-               warning << _("Can not read input file.") << endmsg;
-               aborted=true;
-               finished=true;
-               return;
-       }
-
-       if ( !try_hardlink || link(infn.c_str(), outfn.c_str()) ) {
-               /* hard-link failed , try copy */
-               progress_label.set_text (_("Copying File."));
-               int infd = open (infn.c_str(), O_RDONLY);
-               int outfd = open (outfn.c_str(), O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-               if (infd <0 || outfd <0) {
-                       if (infd != -1) close(infd);
-                       warning << _("Can not open files for copy.") << endmsg;
-                       aborted=true;
-                       finished=true;
-                       return;
-               }
-               char buffer[BUFSIZ];
-               ssize_t nrb, ret;
-               while ((nrb = read(infd, buffer, BUFSIZ)) > 0  && nrb != -1 ) {
-                       ret = write(outfd, buffer, nrb);
-                       if(ret != nrb || aborted) {
-                               warning << _("File copy failed.") << endmsg;
-                               unlink(outfn.c_str());
-                               aborted=true;
-                               finished=true;
-                               return;
-                       }
-                       p_cur+=ret;
-               }
-       }
-       finished=true;
-       return;
-}
-
-void
-VideoCopyDialog::open_browse_dialog ()
-{
-       Gtk::FileChooserDialog dialog(_("Video File Copy Destination"), Gtk::FILE_CHOOSER_ACTION_SAVE);
-       dialog.set_filename (path_entry.get_text());
-
-       dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
-       dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
-
-       int result = dialog.run();
-
-       if (result == Gtk::RESPONSE_OK) {
-               std::string filename = dialog.get_filename();
-
-               if (filename.length()) {
-                       path_entry.set_text (filename);
-               }
-       }
-}
-#endif /* WITH_VIDEOTIMELINE */
diff --git a/gtk2_ardour/video_copy_dialog.h b/gtk2_ardour/video_copy_dialog.h
deleted file mode 100644 (file)
index 400cb3e..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-    Copyright (C) 2010 Paul Davis
-    Author: Robin Gareus <robin@gareus.org>
-
-    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.
-
-*/
-#ifdef WITH_VIDEOTIMELINE
-
-#ifndef __gtk_ardour_video_copy_dialog_h__
-#define __gtk_ardour_video_copy_dialog_h__
-
-#include <string>
-
-#include <gtkmm.h>
-
-#include "ardour/types.h"
-#include "ardour/template_utils.h"
-#include "ardour_dialog.h"
-
-/** @class ExportVideoDialog
- *  @brief dialog box and progress report for linking and copying video-files to the session.
- */
-class VideoCopyDialog : public ArdourDialog , public PBD::ScopedConnectionList
-{
-  public:
-       /** @param infile absolute-path to the file to copy or link */
-       VideoCopyDialog (ARDOUR::Session*, std::string infile);
-       ~VideoCopyDialog ();
-       /** if set to true before calling dialog->show()
-        * the dialog will only show the progres report and
-        * start copying or linking immediatly
-        * @param destfn destination path to copy or link the infile to.
-        */
-       void setup_non_interactive_copy(std::string destfn ="");
-       std::string get_filename () { return outfn; }
-
-       /*
-        * Note: it's actually 'private' function but used
-        * by the internal pthread, which only has a pointer
-        * to this instance and thus can only access public fn.
-        */
-       void do_copy ();
-
-  private:
-       void on_show ();
-       void abort_clicked ();
-       bool aborted;
-       bool autostart;
-       bool finished;
-       pthread_t thread;
-
-       void launch_copy ();
-       std::string infn;
-       std::string outfn;
-
-       gint progress_timeout ();
-       sigc::connection p_connection;
-       ssize_t p_cur;
-       off_t  p_tot;
-
-       void open_browse_dialog ();
-       Gtk::Label        path_label;
-       Gtk::Entry        path_entry;
-       Gtk::Button       browse_button;
-       Gtk::Button      *cancel_button;
-       Gtk::Button       copy_button;
-
-       Gtk::HBox*  path_hbox;
-       Gtk::VBox*  progress_box;
-       Gtk::Button abort_button;
-       Gtk::Label  progress_label;
-       Gtk::ProgressBar pbar;
-};
-
-#endif /* __gtk_ardour_video_copy_dialog_h__ */
-
-#endif /* WITH_VIDEOTIMELINE */
index 30fe487f5165bdd9598eb3881995fecfd009cf54..cc964c7e43e0cc8231c517ed671757a8900418f6 100644 (file)
@@ -195,13 +195,17 @@ http_get_thread (void *arg) {
          vif->get_video_filename().c_str()
        );
        int status = 0;
-       int timeout = 400; // * 5ms -> 2sec
+       int timeout = 1000; // * 5ms -> 5sec
        char *res = NULL;
        do {
                res=curl_http_get(url, &status);
                if (status == 503) usleep(5000); // try-again
        } while (status == 503 && --timeout > 0);
 
+       if (status != 200 || !res) {
+               printf("no-video frame: video-server returned http-status: %d\n", status);
+       }
+
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        vif->http_download_done(res);
        pthread_exit(0);
index 3abc11be28610d162ac6d6a724f9109313a8a469..f29712e326a570bd9a9ba6d570a80b1ec87c5c26 100644 (file)
@@ -41,7 +41,7 @@ VideoMonitor::VideoMonitor (PublicEditor *ed, std::string xjadeo_bin_path)
        clock_connection = sigc::connection();
        debug_enable = false;
 
-       process = new SystemExec(xjadeo_bin_path);
+       process = new SystemExec(xjadeo_bin_path, X_("-R"));
        process->ReadStdout.connect (*this, invalidator (*this), boost::bind (&VideoMonitor::parse_output, this, _1 ,_2), gui_context());
        process->Terminated.connect (*this, invalidator (*this), boost::bind (&VideoMonitor::terminated, this), gui_context());
 }
index f6236a2aee528f0ecf7a5f1a6d4637fdaabf7add..ca70c11a0f7d05877c9f160b07438f7d6f3048c8 100644 (file)
@@ -32,6 +32,7 @@
 #include "ardour/session.h"
 
 #include "video_server_dialog.h"
+#include "utils_videotl.h"
 #include "i18n.h"
 
 using namespace Gtk;
@@ -84,14 +85,13 @@ VideoServerDialog::VideoServerDialog (Session* s)
        if (find_file_in_search_path (PBD::SearchPath(Glib::getenv("PATH")), X_("harvid"), icsd_file_path)) {
                path_entry.set_text(icsd_file_path);
        }
-       else if (find_file_in_search_path (PBD::SearchPath(Glib::getenv("PATH")), X_("icsd"), icsd_file_path)) {
-               path_entry.set_text(icsd_file_path);
-       }
        else if (Glib::file_test(X_("C:\\Program Files\\harvid\\harvid.exe"), Glib::FILE_TEST_EXISTS)) {
                path_entry.set_text(X_("C:\\Program Files\\harvid\\harvid.exe"));
        }
        else {
-               PBD::warning << _("The external video server 'harvid' can not be found, see https://github.com/x42/harvid") << endmsg;
+               PBD::warning <<
+                       _("The external video server 'harvid' can not be found. The tool is included with the Ardour releases from ardour.org, "
+                         "alternatively you can download it from http://x42.github.com/harvid/ or acquire it from your distribution.") << endmsg;
        }
 
 
@@ -132,17 +132,23 @@ VideoServerDialog::VideoServerDialog (Session* s)
        t->attach (*l, 0, 1, 2, 3, FILL);
        t->attach (cachesize_spinner, 1, 2, 2, 3);
 
-       l = manage (new Label (_("Ardour relies on an external Video Server for the videotimeline. The server configured in Edit -> Prefereces -> Video is not reachable. Do you want ardour to launch 'harvid' on this machine?"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+       l = manage (new Label (_("Ardour relies on an external Video Server for the videotimeline.\nThe server configured in Edit -> Prefereces -> Video is not reachable.\nDo you want ardour to launch 'harvid' on this machine?"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+       l->set_max_width_chars(80);
        l->set_line_wrap();
-       vbox->pack_start (*l, false, true, 4);
+       vbox->pack_start (*l, true, true, 4);
        vbox->pack_start (*path_hbox, false, false);
-       vbox->pack_start (*docroot_hbox, false, false);
+       if (Config->get_video_advanced_setup()){
+               vbox->pack_start (*docroot_hbox, false, false);
+       } else {
+               docroot_entry.set_text(X_("/"));
+               listenport_spinner.set_sensitive(false);
+       }
        vbox->pack_start (*options_box, false, true);
 
        get_vbox()->set_spacing (4);
        get_vbox()->pack_start (*vbox, false, false);
        get_vbox()->pack_start (showagain_checkbox, false, false);
-       showagain_checkbox.set_active(false);
+       showagain_checkbox.set_active(!Config->get_show_video_server_dialog());
 
        path_browse_button.signal_clicked().connect (sigc::mem_fun (*this, &VideoServerDialog::open_path_dialog));
        docroot_browse_button.signal_clicked().connect (sigc::mem_fun (*this, &VideoServerDialog::open_docroot_dialog));
@@ -196,10 +202,19 @@ VideoServerDialog::open_docroot_dialog ()
        if (result == Gtk::RESPONSE_OK) {
                std::string dirname = dialog.get_filename();
 
+               if (dirname.empty() || dirname.at(dirname.length()-1) != G_DIR_SEPARATOR) {
+                       dirname += "/";
+               }
+
                if (dirname.length()) {
                        docroot_entry.set_text (dirname);
                }
        }
 }
 
+std::string
+VideoServerDialog::get_docroot () {
+       return docroot_entry.get_text();
+}
+
 #endif /* WITH_VIDEOTIMELINE */
index e6216cfed790b4ba78b2685506a70285a1e1e12e..fae0f06390dfb5da7c9bdfc8b2ea6d53f093ae13 100644 (file)
@@ -40,7 +40,7 @@ class VideoServerDialog : public ArdourDialog
        ~VideoServerDialog ();
 
        std::string get_exec_path () { return path_entry.get_text(); }
-       std::string get_docroot () { return docroot_entry.get_text(); }
+       std::string get_docroot ();
        std::string get_listenaddr () { return listenaddr_combo.get_active_text();}
        int get_listenport () { return listenport_spinner.get_value_as_int();}
        int get_cachesize () { return cachesize_spinner.get_value_as_int();}
index 3bcb397b68c1f906edd842a761595c2bd53bdf96..9460632e6cd751b4d986c148785554b653370a19 100644 (file)
@@ -19,6 +19,7 @@
 */
 #ifdef WITH_VIDEOTIMELINE
 
+#include <algorithm>
 #include <sigc++/bind.h>
 #include "ardour/tempo.h"
 
@@ -46,7 +47,6 @@ using namespace ARDOUR;
 using namespace PBD;
 using namespace Timecode;
 
-
 VideoTimeLine::VideoTimeLine (PublicEditor *ed, ArdourCanvas::Group *vbg, int initial_height)
        : editor (ed)
                , videotl_bar_group(vbg)
@@ -61,8 +61,8 @@ VideoTimeLine::VideoTimeLine (PublicEditor *ed, ArdourCanvas::Group *vbg, int in
        video_aspect_ratio = 4.0/3.0;
        open_video_monitor_dialog = 0;
        Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&VideoTimeLine::parameter_changed, this, _1), gui_context());
-       video_server_url = Config->get_video_server_url();
-       server_docroot   = Config->get_video_server_docroot();
+       video_server_url = video_get_server_url(Config);
+       server_docroot   = video_get_docroot(Config);
        video_filename = "";
        local_file = true;
        video_file_fps = 25.0;
@@ -153,12 +153,16 @@ VideoTimeLine::save_session ()
 void
 VideoTimeLine::close_session ()
 {
+       if (video_duration == 0) {
+               return;
+       }
        close_video_monitor();
        save_session();
 
        remove_frames();
        video_filename = "";
-       video_duration = 0L;
+       video_duration = 0;
+       GuiUpdate("set-xjadeo-sensitive-off");
 }
 
 /** load settings from session */
@@ -171,6 +175,11 @@ VideoTimeLine::set_session (ARDOUR::Session *s)
        LocaleGuard lg (X_("POSIX"));
 
        XMLNode* node = _session->extra_xml (X_("Videotimeline"));
+
+       if (!node || !node->property (X_("Filename"))) {
+               return;
+       }
+
        if (node) {
                ARDOUR_UI::instance()->start_video_server((Gtk::Window*)0, false);
 
@@ -210,7 +219,7 @@ VideoTimeLine::set_session (ARDOUR::Session *s)
        node = _session->extra_xml (X_("Videomonitor"));
        if (node) {
                const XMLProperty* prop = node->property (X_("active"));
-               if (prop->value() == "yes" && found_xjadeo() && !video_filename.empty() && local_file) {
+               if (prop && prop->value() == "yes" && found_xjadeo() && !video_filename.empty() && local_file) {
                        open_video_monitor(false);
                }
        }
@@ -456,6 +465,7 @@ VideoTimeLine::translated_filename ()
 bool
 VideoTimeLine::video_file_info (std::string filename, bool local)
 {
+
        local_file = local;
        if (filename.at(0) == G_DIR_SEPARATOR || !local_file) {
                video_filename = filename;
@@ -514,11 +524,24 @@ VideoTimeLine::video_file_info (std::string filename, bool local)
        }
        flush_local_cache ();
 
+       _session->maybe_update_session_range(
+                       std::max(get_offset(), (ARDOUR::frameoffset_t) 0),
+                       std::max(get_offset() + get_duration(), (ARDOUR::frameoffset_t) 0)
+                       );
+
        if (found_xjadeo() && local_file) {
                GuiUpdate("set-xjadeo-sensitive-on");
                if (vmonitor && vmonitor->is_started()) {
+#if 1
+                       /* xjadeo <= 0.6.4 has a bug where changing the video-file may segfauls
+                        * if the geometry changes to a different line-size alignment
+                        */
+                       reopen_vmonitor = true;
+                       vmonitor->quit();
+#else
                        vmonitor->set_fps(video_file_fps);
                        vmonitor->open(video_filename);
+#endif
                }
        } else if (!local_file) {
 #if 1 /* temp debug/devel message */
@@ -610,9 +633,12 @@ void
 VideoTimeLine::parameter_changed (std::string const & p)
 {
        if (p == "video-server-url") {
-               set_video_server_url (Config->get_video_server_url ());
+               set_video_server_url (video_get_server_url(Config));
        } else if (p == "video-server-docroot") {
-               set_video_server_docroot (Config->get_video_server_docroot ());
+               set_video_server_docroot (video_get_docroot(Config));
+       } else if (p == "video-advanced-setup") {
+               set_video_server_url (video_get_server_url(Config));
+               set_video_server_docroot (video_get_docroot(Config));
        }
        if (p == "use-video-file-fps" || p == "videotimeline-pullup" ) { /* session->config parameter */
                VtlUpdate();
index b043bc96ec83e9e62684c4f4a15a3668e7f10866..5beeebb74d66054f4ac526e8eb5259ff8bbddca8 100644 (file)
@@ -429,7 +429,6 @@ def build(bld):
             'transcode_ffmpeg.cc',
             'transcode_video_dialog.cc',
             'video_server_dialog.cc',
-            'video_copy_dialog.cc',
             'utils_videotl.cc',
             'export_video_dialog.cc',
             'export_video_infobox.cc'
index 5c04a7f43a321276079f63237315b8b8d30501d7..42aba607f94b42d7029747fa61bcd43be08cae58 100644 (file)
@@ -45,6 +45,28 @@ public:
                _written = true;
        }
 
+       /** Read @a len frames @a src starting at @a src_offset into self starting at @ dst_offset*/
+       void read_from (const Sample* src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+               assert(src != 0);
+               assert(_capacity > 0);
+               assert(len <= _capacity);
+               memcpy(_data + dst_offset, src + src_offset, sizeof(Sample) * len);
+               _silent = false;
+               _written = true;
+       }
+
+        void read_from_with_gain (const Sample* src, framecnt_t len, gain_t gain, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+               assert(src != 0);
+               assert(_capacity > 0);
+               assert(len <= _capacity);
+               src += src_offset;
+               for (framecnt_t n = 0; n < len; ++n) {
+                       _data[dst_offset+n] = src[n] * gain;
+               }
+               _silent = false;
+               _written = true;
+       }
+
        /** Read @a len frames @a src starting at @a src_offset into self starting at @ dst_offset*/
        void read_from (const Buffer& src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
                assert(&src != this);
@@ -82,6 +104,20 @@ public:
                _written = true;
        }
 
+       /** Acumulate (add) @a len frames @a src starting at @a src_offset into self starting at @a dst_offset */
+       void accumulate_from (const Sample* src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+               assert(_capacity > 0);
+               assert(len <= _capacity);
+
+               Sample*       const dst_raw = _data + dst_offset;
+               const Sample* const src_raw = src + src_offset;
+
+               mix_buffers_no_gain(dst_raw, src_raw, len);
+               
+               _silent = false;
+               _written = true;
+       }
+
        /** Acumulate (add) @a len frames @a src starting at @a src_offset into self starting at @dst_offset
         * scaling by @a gain_coeff */
        void accumulate_with_gain_from (const AudioBuffer& src, framecnt_t len, gain_t gain_coeff, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
@@ -171,6 +207,8 @@ public:
                return _data + offset;
        }
 
+    bool check_silence (pframes_t, pframes_t&) const;
+
        void prepare () { _written = false; _silent = false; }
        bool written() const { return _written; }
        void set_written(bool w) { _written = w; }
index 455e89392bd6e2e989afb157b7a422ee90363b31..cbc6b93fe0d4b53d86ac5ce80502c9d84ab107e9 100644 (file)
@@ -151,7 +151,7 @@ class AudioDiskstream : public Diskstream
   protected:
        friend class AudioTrack;
 
-       int  process (framepos_t transport_frame, pframes_t nframes, framecnt_t &);
+        int  process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal);
        bool commit  (framecnt_t);
 
   private:
index 81eb588d1acb87ece0b2f49e2144936ba67942d3..85ca03caff7da8e5e179701ba86dd1826702441c 100644 (file)
@@ -49,6 +49,7 @@ class Source;
 class Session;
 class Track;
 class Location;
+class BufferSet;
 
 /** Parent class for classes which can stream data to and from disk.
  *  These are used by Tracks to get playback and put recorded data.
@@ -191,7 +192,7 @@ class Diskstream : public SessionObject, public PublicDiskstream
   protected:
        friend class Track;
 
-       virtual int  process (framepos_t transport_frame, pframes_t nframes, framecnt_t &) = 0;
+    virtual int  process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal) = 0;
        virtual bool commit  (framecnt_t) = 0;
 
        //private:
index 773b04f38650ece90a569d8dd161f3872abe5ba9..eea240f82145e138802960ec9f220ab3e9a832e0 100644 (file)
@@ -44,7 +44,7 @@ class Metering {
  */
 class PeakMeter : public Processor {
 public:
-       PeakMeter(Session& s) : Processor(s, "Meter") {}
+        PeakMeter(Session& s, const std::string& name);
 
        void meter();
        void reset ();
index 183ca7eea99a4192e573a9b0d99226a100e0bddb..5ef5e4c8457a8778447c07fa11a47fe686e805bd 100644 (file)
@@ -55,38 +55,50 @@ public:
        template<typename BufferType, typename EventType>
        class iterator_base {
        public:
-               iterator_base<BufferType, EventType>(BufferType& b, framecnt_t o) : buffer(b), offset(o) {}
+               iterator_base<BufferType, EventType>(BufferType& b, framecnt_t o) 
+                    : buffer(&b), offset(o) {}
+                iterator_base<BufferType, EventType>(const iterator_base<BufferType,EventType>& o) 
+                    : buffer (o.buffer), offset(o.offset) {}
+           
+               inline iterator_base<BufferType,EventType> operator= (const iterator_base<BufferType,EventType>& o) {
+                       if (&o != this) {
+                               buffer = o.buffer;
+                               offset = o.offset;
+                       }
+                       return *this;
+               }
+
                inline EventType operator*() const {
-                       uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+                       uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
                        int event_size = Evoral::midi_event_size(ev_start);
                        assert(event_size >= 0);
                        return EventType(EventTypeMap::instance().midi_event_type(*ev_start),
-                                       *((TimeType*)(buffer._data + offset)),
+                                       *((TimeType*)(buffer->_data + offset)),
                                        event_size, ev_start);
                }
                inline EventType operator*() {
-                       uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+                       uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
                        int event_size = Evoral::midi_event_size(ev_start);
                        assert(event_size >= 0);
                        return EventType(EventTypeMap::instance().midi_event_type(*ev_start),
-                                       *((TimeType*)(buffer._data + offset)),
+                                       *((TimeType*)(buffer->_data + offset)),
                                        event_size, ev_start);
                }
 
                inline iterator_base<BufferType, EventType>& operator++() {
-                       uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+                       uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
                        int event_size = Evoral::midi_event_size(ev_start);
                        assert(event_size >= 0);
                        offset += sizeof(TimeType) + event_size;
                        return *this;
                }
                inline bool operator!=(const iterator_base<BufferType, EventType>& other) const {
-                       return (&buffer != &other.buffer) || (offset != other.offset);
+                       return (buffer != other.buffer) || (offset != other.offset);
                }
                inline bool operator==(const iterator_base<BufferType, EventType>& other) const {
-                       return (&buffer == &other.buffer) && (offset == other.offset);
+                       return (buffer == other.buffer) && (offset == other.offset);
                }
-               BufferType&     buffer;
+               BufferType*     buffer;
                size_t          offset;
        };
 
@@ -99,6 +111,41 @@ public:
        const_iterator begin() const { return const_iterator(*this, 0); }
        const_iterator end()   const { return const_iterator(*this, _size); }
 
+        iterator erase(const iterator& i) {
+               assert (i.buffer == this);
+               uint8_t* ev_start = _data + i.offset + sizeof (TimeType);
+               int event_size = Evoral::midi_event_size (ev_start);
+
+               if (event_size < 0) {
+                       /* unknown size, sysex: return end() */
+                       return end();
+               }
+
+               size_t total_data_deleted = sizeof(TimeType) + event_size;
+
+               if (i.offset + total_data_deleted >= _size) {
+                       _size = 0;
+                       return end();
+               }
+
+               /* we need to avoid the temporary malloc that memmove would do,
+                  so copy by hand. remember: this is small amounts of data ...
+               */
+               size_t a, b;
+               for (a = i.offset, b = i.offset + total_data_deleted; b < _size; ++b, ++a) {
+                       _data[a] = _data[b];
+               }
+
+               _size -= total_data_deleted;
+
+               /* all subsequent iterators are now invalid, and the one we
+                * return should refer to the event we copied, which was after
+                * the one we just erased.
+                */
+
+               return iterator (*this, i.offset);
+       }
+
        uint8_t* data() const { return _data; }
 
        /**
index 309c275434b9304689bf7320d895a34538235ca5..d6ad71863ab15e594a0a74450d6b7e141977fb5f 100644 (file)
@@ -89,29 +89,6 @@ class MidiDiskstream : public Diskstream
 
        void set_note_mode (NoteMode m);
 
-       uint16_t get_channel_mask() {
-               uint16_t playback_mask = _playback_buf->get_channel_mask();
-#ifndef NDEBUG
-               uint16_t capture_mask  = _capture_buf->get_channel_mask();
-               assert(playback_mask == capture_mask);
-#endif
-               return playback_mask;
-       }
-
-       void set_channel_mode(ChannelMode mode, uint16_t mask) {
-               _playback_buf->set_channel_mode(mode, mask);
-               _capture_buf->set_channel_mode(mode, mask);
-       }
-
-       ChannelMode get_channel_mode() {
-               ChannelMode playback_mode = _playback_buf->get_channel_mode();
-#ifndef NDEBUG
-               ChannelMode capture_mode  = _capture_buf->get_channel_mode();
-               assert(playback_mode == capture_mode);
-#endif
-               return playback_mode;
-       }
-
        /** Emitted when some MIDI data has been received for recording.
         *  Parameter is the source that it is destined for.
         *  A caller can get a copy of the data with get_gui_feed_buffer ()
@@ -147,7 +124,7 @@ class MidiDiskstream : public Diskstream
   protected:
        friend class MidiTrack;
 
-       int  process (framepos_t transport_frame, pframes_t nframes, framecnt_t &);
+        int  process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_diskstream);
        bool commit  (framecnt_t nframes);
        static framecnt_t midi_readahead;
 
index 0d11f940b9ddf6d219ddab6abe10ced11ff293a8..3ecfca7d1c94d59a257b72998d07da1e9213cbd9 100644 (file)
@@ -114,6 +114,8 @@ public:
                struct NoteChange {
                        NoteDiffCommand::Property property;
                        NotePtr note;
+                       uint32_t note_id; 
+                   
                        union {
                                uint8_t  old_value;
                                TimeType old_time;
@@ -161,6 +163,7 @@ public:
        private:
                struct Change {
                        boost::shared_ptr<Evoral::Event<TimeType> > sysex;
+                       gint sysex_id;
                        SysExDiffCommand::Property property;
                        TimeType old_time;
                        TimeType new_time;
@@ -204,6 +207,7 @@ public:
                struct Change {
                        PatchChangePtr patch;
                        Property       property;
+                       gint           patch_id;
                        union {
                                TimeType   old_time;
                                uint8_t    old_channel;
index b3e532bdbe90f5743d0fa66dac567d629ca01a06..d5c9947b9ae8d028b83f402cd28c5d18ab4596f3 100644 (file)
@@ -45,38 +45,16 @@ public:
        /** @param size Size in bytes.
         */
        MidiRingBuffer(size_t size)
-               : Evoral::EventRingBuffer<T>(size)
-               , _channel_mask(0x0000FFFF)
-       {}
+               : Evoral::EventRingBuffer<T>(size) {}
 
        inline bool read_prefix(T* time, Evoral::EventType* type, uint32_t* size);
        inline bool read_contents(uint32_t size, uint8_t* buf);
 
        size_t read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset=0, bool stop_on_overflow_in_destination=false);
-       inline uint32_t write(T  time, Evoral::EventType  type, uint32_t  size, const uint8_t* buf);
 
        void dump(std::ostream& dst);
        void flush (framepos_t start, framepos_t end);
 
-       /** Set the channel filtering mode.
-        * @param mask If mode is FilterChannels, each bit represents a midi channel:
-        *     bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only
-        *     process events whose channel bit is 1.
-        *     If mode is ForceChannel, mask is simply a channel number which all events will
-        *     be forced to while reading.
-        */
-       void set_channel_mode(ChannelMode mode, uint16_t mask) {
-               g_atomic_int_set(&_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
-       }
-
-       ChannelMode get_channel_mode() const {
-               return static_cast<ChannelMode>((g_atomic_int_get(&_channel_mask) & 0xFFFF0000) >> 16);
-       }
-
-       uint16_t get_channel_mask() const {
-               return g_atomic_int_get(&_channel_mask) & 0x0000FFFF;
-       }
-
        void reset_tracker ();
         void loop_resolve (MidiBuffer& dst, framepos_t);
 
@@ -99,7 +77,6 @@ protected:
        }
 
 private:
-       volatile uint32_t _channel_mask; // 16 bits mode, 16 bits mask
        MidiStateTracker _tracker;
 };
 
@@ -137,38 +114,6 @@ MidiRingBuffer<T>::read_contents(uint32_t size, uint8_t* buf)
        return PBD::RingBufferNPT<uint8_t>::read(buf, size) == size;
 }
 
-template<typename T>
-inline uint32_t
-MidiRingBuffer<T>::write(T time, Evoral::EventType type, uint32_t size, const uint8_t* buf)
-{
-       assert(size > 0);
-       uint8_t status = buf[0];
-
-       // Ignore event if it doesn't match channel filter
-       if (is_channel_event(status)) {
-               ChannelMode mode = get_channel_mode();
-               if (mode == FilterChannels) {
-                       const uint8_t channel = status & 0x0F;
-                       if (!(get_channel_mask() & (1L << channel))) {
-                               return 0;
-                       }
-               } else if (mode == ForceChannel) {
-                       uint8_t* tmpbuf = (uint8_t*) malloc(size);
-                       assert(tmpbuf);
-                       memcpy(tmpbuf, buf, size);
-
-                       tmpbuf[0] = (tmpbuf[0] & 0xF0) | (get_channel_mask() & 0x0F);
-
-                       uint32_t bytes_written = Evoral::EventRingBuffer<T>::write(time, type, size, tmpbuf);
-                       free(tmpbuf);
-                       return bytes_written;
-               }
-       }
-
-       return Evoral::EventRingBuffer<T>::write(time, type, size, buf);
-}
-
-
 } // namespace ARDOUR
 
 #endif // __ardour_midi_ring_buffer_h__
index 8134f5312a20e43bdb74d4f7baa5d1f4429b2ec2..3b75c0a51b9c18d232aa15fc5305a2b0c548ee81 100644 (file)
@@ -102,11 +102,39 @@ public:
        PBD::Signal1<void,bool> StepEditStatusChange;
 
        boost::shared_ptr<SMFSource> write_source (uint32_t n = 0);
-       void set_channel_mode (ChannelMode, uint16_t);
-       ChannelMode get_channel_mode ();
-       uint16_t get_channel_mask ();
+
+       /** Channel filtering mode.
+        * @param mask If mode is FilterChannels, each bit represents a midi channel:
+        *     bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only
+        *     process events whose channel bit is 1.
+        *     If mode is ForceChannel, mask is simply a channel number which all events will
+        *     be forced to while reading.
+        */
+        void set_capture_channel_mode (ChannelMode mode, uint16_t mask);
+        void set_playback_channel_mode (ChannelMode mode, uint16_t mask);
+        void set_playback_channel_mask (uint16_t mask);
+        void set_capture_channel_mask (uint16_t mask);
+
+       ChannelMode get_playback_channel_mode() const {
+               return static_cast<ChannelMode>((g_atomic_int_get(&_playback_channel_mask) & 0xffff0000) >> 16);
+       }
+        uint16_t get_playback_channel_mask() const {
+               return g_atomic_int_get(&_playback_channel_mask) & 0x0000ffff;
+       }
+       ChannelMode get_capture_channel_mode() const {
+               return static_cast<ChannelMode>((g_atomic_int_get(&_capture_channel_mask) & 0xffff0000) >> 16);
+       }
+        uint16_t get_capture_channel_mask() const {
+               return g_atomic_int_get(&_capture_channel_mask) & 0x0000ffff;
+       }
+
        boost::shared_ptr<MidiPlaylist> midi_playlist ();
 
+        PBD::Signal0<void> PlaybackChannelMaskChanged;
+        PBD::Signal0<void> PlaybackChannelModeChanged;
+        PBD::Signal0<void> CaptureChannelMaskChanged;
+        PBD::Signal0<void> CaptureChannelModeChanged;
+    
        PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
        boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
 
@@ -123,6 +151,13 @@ protected:
        void act_on_mute ();
 
 private:
+       MidiRingBuffer<framepos_t> _immediate_events;
+       MidiRingBuffer<framepos_t> _step_edit_ring_buffer;
+       NoteMode                   _note_mode;
+       bool                       _step_editing;
+       bool                       _input_active;
+        uint32_t                   _playback_channel_mask; // 16 bits mode, 16 bits mask
+        uint32_t                   _capture_channel_mask; // 16 bits mode, 16 bits mask
 
        virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
        
@@ -133,11 +168,6 @@ private:
        void set_state_part_two ();
        void set_state_part_three ();
 
-       MidiRingBuffer<framepos_t> _immediate_events;
-       MidiRingBuffer<framepos_t> _step_edit_ring_buffer;
-       NoteMode                  _note_mode;
-       bool                      _step_editing;
-       bool                      _input_active;
 
        int no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool state_changing);
        void push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes);
@@ -147,6 +177,32 @@ private:
 
        void track_input_active (IOChange, void*);
        void map_input_active (bool);
+
+        void filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask); 
+
+/* if mode is ForceChannel, force mask to the lowest set channel or 1 if no
+ * channels are set.
+ */
+#define force_mask(mode,mask) (((mode) == ForceChannel) ? (((mask) ? (1<<(ffs((mask))-1)) : 1)) : mask)
+
+       void _set_playback_channel_mode(ChannelMode mode, uint16_t mask) {
+               mask = force_mask (mode, mask);
+               g_atomic_int_set(&_playback_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
+       }
+        void _set_playback_channel_mask (uint16_t mask) {
+               mask = force_mask (get_playback_channel_mode(), mask);
+               g_atomic_int_set(&_playback_channel_mask, (uint32_t(get_playback_channel_mode()) << 16) | uint32_t(mask));
+       }
+       void _set_capture_channel_mode(ChannelMode mode, uint16_t mask) {
+               mask = force_mask (mode, mask);
+               g_atomic_int_set(&_capture_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
+       }
+        void _set_capture_channel_mask (uint16_t mask) {
+               mask = force_mask (get_capture_channel_mode(), mask);
+               g_atomic_int_set(&_capture_channel_mask, (uint32_t(get_capture_channel_mode()) << 16) | uint32_t(mask));
+       }
+
+#undef force_mask
 };
 
 } /* namespace ARDOUR*/
index df73bd53160cfe7187a7c0dc763093be6c4bfbdf..ae616d3008c5bc19f2b360c24fa0e8acf9654e8d 100644 (file)
@@ -217,9 +217,10 @@ CONFIG_VARIABLE (std::string, updates_url, "updates-url", "http://ardour.org/wha
 CONFIG_VARIABLE (std::string, donate_url, "donate-url", "http://ardour.org/donate")
 
 #ifdef WITH_VIDEOTIMELINE
+CONFIG_VARIABLE (bool, video_advanced_setup, "video-advanced-setup", false)
 CONFIG_VARIABLE (std::string, video_server_url, "video-server-url", "http://localhost:1554")
 CONFIG_VARIABLE (std::string, video_server_docroot, "video-server-docroot", "/")
 CONFIG_VARIABLE (bool, video_monitor_setup_dialog, "video-monitor-setup-dialog", false)
 CONFIG_VARIABLE (bool, show_video_export_info, "show-video-export-info", true)
-CONFIG_VARIABLE (bool, show_video_server_dialog, "show-video-server-dialog", true)
+CONFIG_VARIABLE (bool, show_video_server_dialog, "show-video-server-dialog", false)
 #endif
index 1a42999e6b9bffc03352e75b2c8edb968b69cb46..c25b6be950c420a04d86d66fe998047c403a33b7 100644 (file)
@@ -436,6 +436,12 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
 
        bool has_external_redirects() const;
 
+        /* can only be executed by a route for which is_monitor() is true
+          (i.e. the monitor out)
+        */
+        void monitor_run (framepos_t start_frame, framepos_t end_frame,
+                         pframes_t nframes, int declick);
+
   protected:
        friend class Session;
 
@@ -448,11 +454,13 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
   protected:
        virtual framecnt_t check_initial_delay (framecnt_t nframes, framepos_t&) { return nframes; }
 
-       void passthru (framepos_t start_frame, framepos_t end_frame,
+        void fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes);
+
+        void passthru (BufferSet&, framepos_t start_frame, framepos_t end_frame,
                        pframes_t nframes, int declick);
 
        virtual void write_out_of_band_data (BufferSet& /* bufs */, framepos_t /* start_frame */, framepos_t /* end_frame */,
-                       framecnt_t /* nframes */) {}
+                                            framecnt_t /* nframes */) {}
 
        virtual void process_output_buffers (BufferSet& bufs,
                                             framepos_t start_frame, framepos_t end_frame,
index 78c95acb332d25753e1f32a0f9e287772e9e1d61..cb7f0ee0157104ba118ae002ae6050e1438fd3f3 100644 (file)
@@ -732,6 +732,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        void request_play_range (std::list<AudioRange>*, bool leave_rolling = false);
        bool get_play_range () const { return _play_range; }
 
+       void maybe_update_session_range (framepos_t, framepos_t);
+
        /* buffers for gain and pan */
 
        gain_t* gain_automation_buffer () const;
@@ -900,8 +902,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        Slave*                  _slave;
        bool                    _silent;
 
-       void maybe_update_session_range (framepos_t, framepos_t);
-
        // varispeed playback
        double                  _transport_speed;
        double                  _default_transport_speed;
index 8493d5e4ae2753c61bd47543bf1b92b450c11a03..7159261b510dd96db8e3627de768e920de4cb7cd 100644 (file)
@@ -33,6 +33,7 @@ class RouteGroup;
 class Source;
 class Region;
 class Diskstream;
+class IO;
 
 class Track : public Route, public PublicDiskstream
 {
index 8b2d5c744f116310f24d9453ae9da02b2a3f2547..1fd0337dd12c3e8bcba9608e12834918ef4d868c 100644 (file)
@@ -67,4 +67,13 @@ AudioBuffer::resize (size_t size)
        cache_aligned_malloc ((void**) &_data, sizeof (Sample) * _capacity);
 }
 
-
+bool
+AudioBuffer::check_silence (pframes_t nframes, pframes_t& n) const
+{
+       for (n = 0; n < _size && n < nframes; ++n) {
+               if (_data[n] != Sample (0)) {
+                       return false;
+               }
+       }
+       return true;
+}
index dc9f427e87bea04d5f13c081ac657214a5ba4619..24687c766f242fff2e1d8181107c9923ab539f1a 100644 (file)
@@ -408,7 +408,7 @@ AudioDiskstream::prepare_record_status(framepos_t capture_start_frame)
  *      that someone can read playback_distance worth of data from.
  */
 int
-AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance)
+AudioDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance, bool need_disk_signal)
 {
        uint32_t n;
        boost::shared_ptr<ChannelList> c = channels.reader();
@@ -494,9 +494,9 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
                                assert(ap);
                                assert(rec_nframes <= (framecnt_t) ap->get_audio_buffer(nframes).capacity());
 
-                               Sample *buf = ap->get_audio_buffer (nframes).data (rec_offset);
+                               Sample *buf = bufs.get_audio (n).data(rec_offset);
                                memcpy (chaninfo->current_capture_buffer, buf, sizeof (Sample) * rec_nframes);
-
+                               
                        } else {
 
                                framecnt_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1];
@@ -509,7 +509,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
                                boost::shared_ptr<AudioPort> const ap = _io->audio (n);
                                assert(ap);
 
-                               Sample* buf = ap->get_audio_buffer(nframes).data (rec_offset);
+                               Sample *buf = bufs.get_audio (n).data(rec_offset);
                                framecnt_t first = chaninfo->capture_vector.len[0];
 
                                memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first);
@@ -657,6 +657,46 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
                _speed = _target_speed;
        }
 
+       if (need_disk_signal) {
+
+               /* copy data over to buffer set */
+               
+               size_t n_buffers = bufs.count().n_audio();
+               size_t n_chans = c->size();
+               gain_t scaling = 1.0f;
+               
+               if (n_chans > n_buffers) {
+                       scaling = ((float) n_buffers)/n_chans;
+               }
+
+               for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
+                       
+                       AudioBuffer& buf (bufs.get_audio (n%n_buffers));
+                       ChannelInfo* chaninfo (*chan);
+                       
+                       if (n < n_chans) {
+                               if (scaling != 1.0f) {
+                                       buf.read_from_with_gain (chaninfo->current_playback_buffer, nframes, scaling);
+                               } else {
+                                       buf.read_from (chaninfo->current_playback_buffer, nframes);
+                               }
+                       } else {
+                               if (scaling != 1.0f) {
+                                       buf.accumulate_with_gain_from (chaninfo->current_playback_buffer, nframes, scaling);
+                               } else {
+                                       buf.accumulate_from (chaninfo->current_playback_buffer, nframes);
+                               }
+                       }
+               }
+
+               /* leave the MIDI count alone */
+               ChanCount cnt (DataType::AUDIO, n_chans);
+               cnt.set (DataType::MIDI, bufs.count().n_midi());
+               bufs.set_count (cnt);
+       
+               /* extra buffers will already be silent, so leave them alone */
+       }
+
        return 0;
 }
 
index 90439f46e907eadd5ff5e66e1f545ce4ba95cd31..070a7453fb1a7212a76890f7135979ece14533b3 100644 (file)
@@ -316,8 +316,6 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
                return 0;
        }
 
-       Sample* b;
-       Sample* tmpb;
        framepos_t transport_frame;
        boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
 
@@ -342,7 +340,9 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
                   to do nothing.
                */
 
-               dret = diskstream->process (transport_frame, 0, playback_distance);
+               BufferSet bufs; /* empty set, no matter - nothing will happen */
+
+               dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
                need_butler = diskstream->commit (playback_distance);
                return dret;
        }
@@ -350,126 +350,22 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
        _silent = false;
        _amp->apply_gain_automation(false);
 
-       if ((dret = diskstream->process (transport_frame, nframes, playback_distance)) != 0) {
-               need_butler = diskstream->commit (playback_distance);
-               silence (nframes);
-               return dret;
-       }
-
-       /* special condition applies */
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers ());
 
+       fill_buffers_with_input (bufs, _input, nframes);
+       
        if (_meter_point == MeterInput) {
-               _input->process_input (_meter, start_frame, end_frame, nframes);
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
        }
 
-       if (monitoring_state() == MonitoringInput) {
-
-               passthru (start_frame, end_frame, nframes, false);
-
-       } else if ((b = diskstream->playback_buffer(0)) != 0) {
-
-               /*
-                 XXX is it true that the earlier test on n_outputs()
-                 means that we can avoid checking it again here? i think
-                 so, because changing the i/o configuration of an IO
-                 requires holding the AudioEngine lock, which we hold
-                 while in the process() tree.
-               */
-
-
-               /* copy the diskstream data to all output buffers */
-
-               size_t limit = input_streams ().n_audio();
-               BufferSet& bufs = _session.get_scratch_buffers ();
-               const size_t blimit = bufs.count().n_audio();
-
-               uint32_t n;
-               uint32_t i;
-
-               if (limit > blimit) {
-
-                       /* example case: auditioner configured for stereo output,
-                          but loaded with an 8 channel file. there are only
-                          2 passthrough buffers, but n_process_buffers() will
-                          return 8.
-
-                          arbitrary decision: map all channels in the diskstream
-                          to the outputs available.
-                       */
-
-                       float scaling = limit/blimit;
-
-                       for (i = 0, n = 1; i < blimit; ++i, ++n) {
-
-                               /* first time through just copy a channel into
-                                  the output buffer.
-                               */
-
-                               Sample* bb = bufs.get_audio (i).data();
-
-                               for (pframes_t xx = 0; xx < nframes; ++xx) {
-                                       bb[xx] = b[xx] * scaling;
-                               }
-
-                               if (n < diskstream->n_channels().n_audio()) {
-                                       tmpb = diskstream->playback_buffer(n);
-                                       if (tmpb!=0) {
-                                               b = tmpb;
-                                       }
-                               }
-                       }
-
-                       for (;i < limit; ++i, ++n) {
-
-                               /* for all remaining channels, sum with existing
-                                  data in the output buffers
-                               */
-
-                               bufs.get_audio (i%blimit).accumulate_with_gain_from (b, nframes, 0, scaling);
-
-                               if (n < diskstream->n_channels().n_audio()) {
-                                       tmpb = diskstream->playback_buffer(n);
-                                       if (tmpb!=0) {
-                                               b = tmpb;
-                                       }
-                               }
-
-                       }
-
-                       limit = blimit;
-
-               } else {
-                       for (i = 0, n = 1; i < limit; ++i, ++n) {
-                               memcpy (bufs.get_audio (i).data(), b, sizeof (Sample) * nframes);
-                               if (n < diskstream->n_channels().n_audio()) {
-                                       tmpb = diskstream->playback_buffer(n);
-                                       if (tmpb!=0) {
-                                               b = tmpb;
-                                       }
-                               }
-                       }
-
-                       /* try to leave any MIDI buffers alone */
-
-                       ChanCount chn;
-                       chn.set_audio (limit);
-                       chn.set_midi (_input->n_ports().n_midi());
-                       bufs.set_count (chn);
-               }
-
-               /* final argument: don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
-
-               process_output_buffers (
-                       bufs, start_frame, end_frame, nframes,
-                       declick,
-                       (!diskstream->record_enabled() && _session.transport_rolling())
-                       );
-
-       } else {
-               /* problem with the diskstream; just be quiet for a bit */
+       if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
+               need_butler = diskstream->commit (playback_distance);
                silence (nframes);
+               return dret;
        }
 
+       process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!diskstream->record_enabled() && _session.transport_rolling()));
+
        need_butler = diskstream->commit (playback_distance);
 
        return 0;
index 69efa2eeef1135a6fcf7ce020b512b50a26b1dbd..29af02c696221e5b2150ba0a1f2658549d792bc2 100644 (file)
@@ -962,38 +962,38 @@ LV2Plugin::find_presets()
        lilv_node_free(lv2_appliesTo);
 }
 
-bool
-LV2Plugin::load_preset(PresetRecord r)
+static void
+set_port_value(const char* port_symbol,
+               void*       user_data,
+               const void* value,
+               uint32_t    /*size*/,
+               uint32_t    type)
 {
-       std::map<std::string,uint32_t>::iterator it;
-
-       LilvNode* lv2_port   = lilv_new_uri(_world.world, LILV_NS_LV2 "port");
-       LilvNode* lv2_symbol = lilv_new_uri(_world.world, LILV_NS_LV2 "symbol");
-       LilvNode* preset     = lilv_new_uri(_world.world, r.uri.c_str());
-       LilvNode* pset_value = lilv_new_uri(_world.world, LV2_PRESETS__value);
-
-       LilvNodes* ports = lilv_world_find_nodes(_world.world, preset, lv2_port, NULL);
-       LILV_FOREACH(nodes, i, ports) {
-               const LilvNode* port   = lilv_nodes_get(ports, i);
-               const LilvNode* symbol = get_value(_world.world, port, lv2_symbol);
-               const LilvNode* value  = get_value(_world.world, port, pset_value);
-               if (value && lilv_node_is_float(value)) {
-                       it = _port_indices.find(lilv_node_as_string(symbol));
-                       if (it != _port_indices.end()) {
-                               set_parameter(it->second,lilv_node_as_float(value));
-                       }
-               }
+       LV2Plugin* self = (LV2Plugin*)user_data;
+       if (type != 0 && type != self->_uri_map.uri_to_id(LV2_ATOM__Float)) {
+               return;  // TODO: Support non-float ports
        }
-       lilv_nodes_free(ports);
 
-       lilv_node_free(pset_value);
-       lilv_node_free(preset);
-       lilv_node_free(lv2_symbol);
-       lilv_node_free(lv2_port);
+       const uint32_t port_index = self->port_index(port_symbol);
+       if (port_index != (uint32_t)-1) {
+               self->set_parameter(port_index, *(const float*)value);
+       }
+}
 
-       Plugin::load_preset(r);
+bool
+LV2Plugin::load_preset(PresetRecord r)
+{
+       LilvWorld* world = _world.world;
+       LilvNode*  pset  = lilv_new_uri(world, r.uri.c_str());
+       LilvState* state = lilv_state_new_from_world(world, _uri_map.urid_map(), pset);
 
-       return true;
+       if (state) {
+               lilv_state_restore(state, _impl->instance, set_port_value, this, 0, NULL);
+               lilv_state_free(state);
+       }
+
+       lilv_node_free(pset);
+       return state;
 }
 
 const void*
index 3b49c97d270c65c4cb0ea23a02850017d7e174c6..38c5bb63dea76346c4cd9e9edce31a3e4b015ca8 100644 (file)
@@ -19,6 +19,8 @@
 #include <algorithm>
 #include <cmath>
 
+#include "pbd/compose.h"
+
 #include "ardour/audio_buffer.h"
 #include "ardour/buffer_set.h"
 #include "ardour/dB.h"
@@ -33,6 +35,12 @@ using namespace ARDOUR;
 
 PBD::Signal0<void> Metering::Meter;
 
+PeakMeter::PeakMeter (Session& s, const std::string& name)
+    : Processor (s, string_compose ("meter-%1", name)) 
+{
+}
+
+
 /** Get peaks from @a bufs
  * Input acceptance is lenient - the first n buffers from @a bufs will
  * be metered, where n was set by the last call to setup(), excess meters will
@@ -55,7 +63,9 @@ PeakMeter::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_fr
        // Meter MIDI in to the first n_midi peaks
        for (uint32_t i = 0; i < n_midi; ++i, ++n) {
                float val = 0.0f;
-               for (MidiBuffer::iterator e = bufs.get_midi(i).begin(); e != bufs.get_midi(i).end(); ++e) {
+               MidiBuffer& buf (bufs.get_midi(i));
+               
+               for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ++e) {
                        const Evoral::MIDIEvent<framepos_t> ev(*e, false);
                        if (ev.is_note_on()) {
                                const float this_vel = log(ev.buffer()[2] / 127.0 * (M_E*M_E-M_E) + M_E) - 1.0;
index cf54bef82ee2e93115531da724364bca456a2379..9c11e818ace714a3cea21f30c8dda569f93b8039 100644 (file)
@@ -26,6 +26,7 @@
 #include <fcntl.h>
 #include <cstdlib>
 #include <ctime>
+#include <strings.h> // for ffs(3)
 #include <sys/stat.h>
 #include <sys/mman.h>
 
@@ -320,7 +321,7 @@ get_location_times(const Location* location,
 }
 
 int
-MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance)
+MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance, bool need_disk_signal)
 {
        framecnt_t rec_offset = 0;
        framecnt_t rec_nframes = 0;
@@ -389,8 +390,11 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
 
                // Pump entire port buffer into the ring buffer (FIXME: split cycles?)
                MidiBuffer& buf = sp->get_midi_buffer(nframes);
+               ChannelMode mode = AllChannels; // _track->get_capture_channel_mode ();
+               uint32_t mask = 0xffff; // _track->get_capture_channel_mask ();
+
                for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
-                       const Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
+                       Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
 #ifndef NDEBUG
                        if (DEBUG::MidiIO & PBD::debug_bits) {
                                const uint8_t* __data = ev.buffer();
@@ -416,8 +420,31 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
                           probabl be implemented in the source instead of here.
                        */
                        const framecnt_t loop_offset = _num_captured_loops * loop_length;
-                       _capture_buf->write(transport_frame + loop_offset + ev.time(),
-                                           ev.type(), ev.size(), ev.buffer());
+                       
+                       switch (mode) {
+                       case AllChannels:
+                               _capture_buf->write(transport_frame + loop_offset + ev.time(),
+                                                   ev.type(), ev.size(), ev.buffer());
+                               break;
+                       case FilterChannels:
+                               if (ev.is_channel_event()) {
+                                       if ((1<<ev.channel()) & mask) {
+                                               _capture_buf->write(transport_frame + loop_offset + ev.time(),
+                                                                   ev.type(), ev.size(), ev.buffer());
+                                       }
+                               } else {
+                                       _capture_buf->write(transport_frame + loop_offset + ev.time(),
+                                                           ev.type(), ev.size(), ev.buffer());
+                               }
+                               break;
+                       case ForceChannel:
+                               if (ev.is_channel_event()) {
+                                       ev.set_channel (ffs(mask) - 1);
+                               }
+                               _capture_buf->write(transport_frame + loop_offset + ev.time(),
+                                                   ev.type(), ev.size(), ev.buffer());
+                               break;
+                       }
                }
                g_atomic_int_add(&_frames_pending_write, nframes);
 
@@ -475,6 +502,18 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
 
        }
 
+       if (need_disk_signal) {
+               /* copy the diskstream data to all output buffers */
+               
+               MidiBuffer& mbuf (bufs.get_midi (0));
+               get_playback (mbuf, nframes);
+               
+               /* leave the audio count alone */
+               ChanCount cnt (DataType::MIDI, 1);
+               cnt.set (DataType::AUDIO, bufs.count().n_audio());
+               bufs.set_count (cnt);
+       }
+
        return 0;
 }
 
@@ -1078,10 +1117,6 @@ MidiDiskstream::get_state ()
        char buf[64];
        LocaleGuard lg (X_("POSIX"));
 
-       node.add_property("channel-mode", enum_2_string(get_channel_mode()));
-       snprintf (buf, sizeof(buf), "0x%x", get_channel_mask());
-       node.add_property("channel-mask", buf);
-
        if (_write_source && _session.get_record_enabled()) {
 
                XMLNode* cs_child = new XMLNode (X_("CapturingSources"));
@@ -1111,7 +1146,6 @@ MidiDiskstream::get_state ()
 int
 MidiDiskstream::set_state (const XMLNode& node, int version)
 {
-       const XMLProperty* prop;
        XMLNodeList nlist = node.children();
        XMLNodeIterator niter;
        XMLNode* capture_pending_node = 0;
@@ -1131,26 +1165,10 @@ MidiDiskstream::set_state (const XMLNode& node, int version)
                return -1;
        }
 
-       ChannelMode channel_mode = AllChannels;
-       if ((prop = node.property ("channel-mode")) != 0) {
-               channel_mode = ChannelMode (string_2_enum(prop->value(), channel_mode));
-       }
-
-       unsigned int channel_mask = 0xFFFF;
-       if ((prop = node.property ("channel-mask")) != 0) {
-               sscanf (prop->value().c_str(), "0x%x", &channel_mask);
-               if (channel_mask & (~0xFFFF)) {
-                       warning << _("MidiDiskstream: XML property channel-mask out of range") << endmsg;
-               }
-       }
-
-
        if (capture_pending_node) {
                use_pending_capture_data (*capture_pending_node);
        }
 
-       set_channel_mode (channel_mode, channel_mask);
-
        in_set_state = false;
 
        return 0;
index 4c6f6633d5e2a7ec90cd2dc3f3822f198f2d43ac..5c1f65d96b2703aaf15399944976ab1b9bf429dc 100644 (file)
@@ -289,6 +289,15 @@ MidiModel::NoteDiffCommand::operator() ()
 
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                        Property prop = i->property;
+
+                       if (!i->note) {
+                               /* note found during deserialization, so try
+                                  again now that the model state is different.
+                               */
+                               i->note = _model->find_note (i->note_id);
+                               assert (i->note);
+                       }
+
                        switch (prop) {
                        case NoteNumber:
                                if (temporary_removals.find (i->note) == temporary_removals.end()) {
@@ -341,7 +350,7 @@ MidiModel::NoteDiffCommand::operator() ()
                                _removed_notes.push_back (*i);
                        }
                }
-
+               
                if (!side_effect_removals.empty()) {
                        cerr << "SER: \n";
                        for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
@@ -373,15 +382,25 @@ MidiModel::NoteDiffCommand::undo ()
                /* notes we modify in a way that requires remove-then-add to maintain ordering */
                set<NotePtr> temporary_removals;
 
+
+               /* lazily discover any affected notes that were not discovered when
+                * loading the history because of deletions, etc.
+                */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->note) {
+                               i->note = _model->find_note (i->note_id);
+                               assert (i->note);
+                       }
+               }
+                               
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                        Property prop = i->property;
-                       switch (prop) {
 
+                       switch (prop) {
                        case NoteNumber:
-                               if (
-                                       temporary_removals.find (i->note) == temporary_removals.end() &&
-                                       find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()
-                                       ) {
+                               if (temporary_removals.find (i->note) == temporary_removals.end() &&
+                                   find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
 
                                        /* We only need to mark this note for re-add if (a) we haven't
                                           already marked it and (b) it isn't on the _removed_notes
@@ -396,10 +415,8 @@ MidiModel::NoteDiffCommand::undo ()
                                break;
 
                        case StartTime:
-                               if (
-                                       temporary_removals.find (i->note) == temporary_removals.end() &&
-                                       find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()
-                                       ) {
+                               if (temporary_removals.find (i->note) == temporary_removals.end() &&
+                                   find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
 
                                        /* See above ... */
 
@@ -410,10 +427,8 @@ MidiModel::NoteDiffCommand::undo ()
                                break;
 
                        case Channel:
-                               if (
-                                       temporary_removals.find (i->note) == temporary_removals.end() &&
-                                       find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()
-                                       ) {
+                               if (temporary_removals.find (i->note) == temporary_removals.end() &&
+                                   find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
 
                                        /* See above ... */
 
@@ -453,7 +468,7 @@ MidiModel::NoteDiffCommand::undo ()
                        _model->add_note_unlocked (*i);
                }
        }
-
+       
        _model->ContentsChanged(); /* EMIT SIGNAL */
 }
 
@@ -651,15 +666,13 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
        }
 
        /* we must point at the instance of the note that is actually in the model.
-          so go look for it ...
+          so go look for it ... it may not be there (it could have been
+          deleted in a later operation, so store the note id so that we can
+          look it up again later).
        */
 
        change.note = _model->find_note (note_id);
-
-       if (!change.note) {
-               warning << "MIDI note #" << note_id << " not found in model - programmers should investigate this" << endmsg;
-               return change;
-       }
+       change.note_id = note_id;
 
        return change;
 }
@@ -790,6 +803,15 @@ MidiModel::SysExDiffCommand::operator() ()
                        _model->remove_sysex_unlocked (*i);
                }
 
+               /* find any sysex events that were missing when unmarshalling */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->sysex) {
+                               i->sysex = _model->find_sysex (i->sysex_id);
+                               assert (i->sysex);
+                       }
+               }
+
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                        switch (i->property) {
                        case Time:
@@ -811,6 +833,15 @@ MidiModel::SysExDiffCommand::undo ()
                        _model->add_sysex_unlocked (*i);
                }
 
+               /* find any sysex events that were missing when unmarshalling */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->sysex) {
+                               i->sysex = _model->find_sysex (i->sysex_id);
+                               assert (i->sysex);
+                       }
+               }
+
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                        switch (i->property) {
                        case Time:
@@ -899,11 +930,7 @@ MidiModel::SysExDiffCommand::unmarshal_change (XMLNode *xml_change)
        */
 
        change.sysex = _model->find_sysex (sysex_id);
-
-       if (!change.sysex) {
-               warning << "Sys-ex #" << sysex_id << " not found in model - programmers should investigate this" << endmsg;
-               return change;
-       }
+       change.sysex_id = sysex_id;
 
        return change;
 }
@@ -1033,6 +1060,15 @@ MidiModel::PatchChangeDiffCommand::operator() ()
                        _model->remove_patch_change_unlocked (*i);
                }
 
+               /* find any patch change events that were missing when unmarshalling */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->patch) {
+                               i->patch = _model->find_patch_change (i->patch_id);
+                               assert (i->patch);
+                       }
+               }
+
                set<PatchChangePtr> temporary_removals;
 
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
@@ -1081,6 +1117,15 @@ MidiModel::PatchChangeDiffCommand::undo ()
                        _model->add_patch_change_unlocked (*i);
                }
 
+               /* find any patch change events that were missing when unmarshalling */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->patch) {
+                               i->patch = _model->find_patch_change (i->patch_id);
+                               assert (i->patch);
+                       }
+               }
+
                set<PatchChangePtr> temporary_removals;
 
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
@@ -1207,10 +1252,10 @@ MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
        XMLProperty* prop;
        Evoral::event_id_t id;
        Evoral::MusicalTime time = 0;
-       uint8_t channel = 0;
-       uint8_t program = 0;
+       int channel = 0;
+       int program = 0;
        int bank = 0;
-
+       
        if ((prop = n->property ("id")) != 0) {
                istringstream s (prop->value());
                s >> id;
@@ -1246,6 +1291,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
 {
        XMLProperty* prop;
        Change c;
+       int an_int;
 
        prop = n->property ("property");
        assert (prop);
@@ -1255,6 +1301,10 @@ MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
        assert (prop);
        Evoral::event_id_t const id = atoi (prop->value().c_str());
 
+       /* we need to load via an int intermediate for all properties that are 
+          actually uint8_t (char/byte).
+       */
+
        prop = n->property ("old");
        assert (prop);
        {
@@ -1262,11 +1312,14 @@ MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
                if (c.property == Time) {
                        s >> c.old_time;
                } else if (c.property == Channel) {
-                       s >> c.old_channel;
+                       s >> an_int;
+                       c.old_channel = an_int;
                } else if (c.property == Program) {
-                       s >> c.old_program;
+                       s >> an_int;
+                       c.old_program = an_int;
                } else if (c.property == Bank) {
-                       s >> c.old_bank;
+                       s >> an_int;
+                       c.old_bank = an_int;
                }
        }
 
@@ -1274,19 +1327,23 @@ MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
        assert (prop);
        {
                istringstream s (prop->value ());
+
                if (c.property == Time) {
                        s >> c.new_time;
                } else if (c.property == Channel) {
-                       s >> c.new_channel;
+                       s >> an_int;
+                       c.new_channel = an_int;
                } else if (c.property == Program) {
-                       s >> c.new_program;
+                       s >> an_int;
+                       c.new_program = an_int;
                } else if (c.property == Bank) {
-                       s >> c.new_bank;
+                       s >> an_int;
+                       c.new_bank = an_int;
                }
        }
 
        c.patch = _model->find_patch_change (id);
-       assert (c.patch);
+       c.patch_id = id;
 
        return c;
 }
@@ -1584,7 +1641,7 @@ MidiModel::write_lock()
        assert (ms);
 
        assert (!ms->mutex().trylock ());
-       return WriteLock(new WriteLockImpl(NULL, _lock, _control_lock));
+       return WriteLock(new WriteLockImpl(0, _lock, _control_lock));
 }
 
 int
index 51d364a3d9d706851e5406954a6ea92ef0680777..72150f8cfc852f17471556be65c9131fa5d7eb7d 100644 (file)
@@ -108,7 +108,6 @@ MidiPort::get_midi_buffer (pframes_t nframes)
        return *_buffer;
 }
 
-
 void
 MidiPort::cycle_end (pframes_t /*nframes*/)
 {
index db3a4cb1090f8c414503d9a673d7c1e4643aee13..e4ae3f3ffe5e9b210f0df544d34b0c6f1e8a66d9 100644 (file)
@@ -17,6 +17,7 @@
 */
 
 #include "pbd/compose.h"
+#include "pbd/enumwriter.h"
 #include "pbd/error.h"
 
 #include "ardour/debug.h"
@@ -81,17 +82,6 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
                bool r = this->peek (&status, sizeof(uint8_t)); 
                assert (r); // If this failed, buffer is corrupt, all hope is lost
 
-               // Ignore event if it doesn't match channel filter
-               if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
-                       const uint8_t channel = status & 0x0F;
-                       if (!(get_channel_mask() & (1L << channel))) {
-                               DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB skipping event (%3 bytes) due to channel mask (mask = %1 chn = %2)\n",
-                                                                                     get_channel_mask(), (int) channel, ev_size));
-                               this->increment_read_ptr (ev_size); // Advance read pointer to next event
-                               continue;
-                       }
-               }
-
                /* lets see if we are going to be able to write this event into dst.
                 */
                uint8_t* write_loc = dst.reserve (ev_time, ev_size);
@@ -130,10 +120,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
                        } else if (is_note_off(write_loc[0])) {
                                _tracker.remove (write_loc[1], write_loc[0] & 0xf);
                        }
-                       
-                       if (is_channel_event(status) && get_channel_mode() == ForceChannel) {
-                               write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
-                       }
+
                        ++count;
                } else {
                        cerr << "WARNING: error reading event contents from MIDI ring" << endl;
index 65a42836a35b57d981579431e9eb0eb499fcb049..1a618a01ddcb1709ba138fb9d22cd6b7f35a1e2f 100644 (file)
@@ -17,6 +17,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <strings.h> // for ffs(3)
+
 #include "pbd/enumwriter.h"
 #include "pbd/convert.h"
 #include "evoral/midi_util.h"
@@ -55,6 +57,8 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
        , _note_mode(Sustained)
        , _step_editing (false)
        , _input_active (true)
+       , _playback_channel_mask(0x0000ffff)
+       , _capture_channel_mask(0x0000ffff)
 {
 }
 
@@ -158,6 +162,38 @@ MidiTrack::set_state (const XMLNode& node, int version)
                set_input_active (string_is_affirmative (prop->value()));
        }
 
+       ChannelMode playback_channel_mode = AllChannels;
+       ChannelMode capture_channel_mode = AllChannels;
+
+       if ((prop = node.property ("playback-channel-mode")) != 0) {
+               playback_channel_mode = ChannelMode (string_2_enum(prop->value(), playback_channel_mode));
+       }
+       if ((prop = node.property ("capture-channel-mode")) != 0) {
+               capture_channel_mode = ChannelMode (string_2_enum(prop->value(), capture_channel_mode));
+       }
+       if ((prop = node.property ("channel-mode")) != 0) {
+               /* 3.0 behaviour where capture and playback modes were not separated */
+               playback_channel_mode = ChannelMode (string_2_enum(prop->value(), playback_channel_mode));
+               capture_channel_mode = playback_channel_mode;
+       }
+
+       unsigned int playback_channel_mask = 0xffff;
+       unsigned int capture_channel_mask = 0xffff;
+
+       if ((prop = node.property ("playback-channel-mask")) != 0) {
+               sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask);
+       }
+       if ((prop = node.property ("capture-channel-mask")) != 0) {
+               sscanf (prop->value().c_str(), "0x%x", &capture_channel_mask);
+       }
+       if ((prop = node.property ("channel-mask")) != 0) {
+               sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask);
+               capture_channel_mask = playback_channel_mask;
+       }
+
+       set_playback_channel_mode (playback_channel_mode, playback_channel_mask);
+       set_capture_channel_mode (capture_channel_mode, capture_channel_mask);
+
        pending_state = const_cast<XMLNode*> (&node);
 
        if (_session.state_of_the_state() & Session::Loading) {
@@ -196,6 +232,13 @@ MidiTrack::state(bool full_state)
                root.add_child_nocopy (*freeze_node);
        }
 
+       root.add_property("playback_channel-mode", enum_2_string(get_playback_channel_mode()));
+       root.add_property("capture_channel-mode", enum_2_string(get_capture_channel_mode()));
+       snprintf (buf, sizeof(buf), "0x%x", get_playback_channel_mask());
+       root.add_property("playback-channel-mask", buf);
+       snprintf (buf, sizeof(buf), "0x%x", get_capture_channel_mask());
+       root.add_property("capture-channel-mask", buf);
+
        root.add_property ("note-mode", enum_2_string (_note_mode));
        root.add_property ("step-editing", (_step_editing ? "yes" : "no"));
        root.add_property ("input-active", (_input_active ? "yes" : "no"));
@@ -300,25 +343,36 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
                   playback distance to zero, thus causing diskstream::commit
                   to do nothing.
                   */
-               dret = diskstream->process (transport_frame, 0, playback_distance);
+               BufferSet bufs; /* empty set - is OK, since nothing will happen */
+
+               dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
                need_butler = diskstream->commit (playback_distance);
                return dret;
        }
 
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+       fill_buffers_with_input (bufs, _input, nframes);
+
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
+       }
+
+       /* filter captured data before the diskstream sees it */
+
+       filter_channels (bufs, get_capture_channel_mode(), get_capture_channel_mask());
 
        _silent = false;
 
-       if ((dret = diskstream->process (transport_frame, nframes, playback_distance)) != 0) {
+       if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
                need_butler = diskstream->commit (playback_distance);
                silence (nframes);
                return dret;
        }
 
-       /* special condition applies */
-
-       if (_meter_point == MeterInput) {
-               _input->process_input (_meter, start_frame, end_frame, nframes);
-       }
+       /* filter playback data before we do anything else */
+       
+       filter_channels (bufs, get_playback_channel_mode(), get_playback_channel_mask ());
 
        if (monitoring_state() == MonitoringInput) {
 
@@ -334,47 +388,17 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
 
                diskstream->flush_playback (start_frame, end_frame);
 
-               passthru (start_frame, end_frame, nframes, 0);
-
-       } else {
-
-               /*
-                  XXX is it true that the earlier test on n_outputs()
-                  means that we can avoid checking it again here? i think
-                  so, because changing the i/o configuration of an IO
-                  requires holding the AudioEngine lock, which we hold
-                  while in the process() tree.
-                  */
-
-
-               /* copy the diskstream data to all output buffers */
-
-               BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
-               MidiBuffer& mbuf (bufs.get_midi (0));
-
-               /* we are a MIDI track, so we always start the chain with a
-                * single-MIDI-channel diskstream 
-                */
-               ChanCount c;
-               c.set_audio (0);
-               c.set_midi (1);
-               bufs.set_count (c);
-
-               assert (nframes > 0);
-
-               diskstream->get_playback (mbuf, nframes);
-
-               /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
-
-               write_out_of_band_data (bufs, start_frame, end_frame, nframes);
-
-               /* final argument: don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
+       } 
 
-               process_output_buffers (
-                       bufs, start_frame, end_frame, nframes,
-                       declick, (!diskstream->record_enabled() && !_session.transport_stopped())
-                       );
-       }
+       
+       /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
+       
+       write_out_of_band_data (bufs, start_frame, end_frame, nframes);
+       
+       /* final argument: don't waste time with automation if we're not recording or rolling */
+       
+       process_output_buffers (bufs, start_frame, end_frame, nframes,
+                               declick, (!diskstream->record_enabled() && !_session.transport_stopped()));
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
@@ -457,6 +481,43 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes)
        }
 }
 
+void 
+MidiTrack::filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask)
+{
+       if (mode == AllChannels) {
+               return;
+       }
+
+       MidiBuffer& buf (bufs.get_midi (0));
+       
+       for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) {
+               
+               Evoral::MIDIEvent<framepos_t> ev(*e, false);
+
+               if (ev.is_channel_event()) {
+                       switch (mode) {
+                       case FilterChannels:
+                               if (0 == ((1<<ev.channel()) & mask)) {
+                                       e = buf.erase (e);
+                               } else {
+                                       ++e;
+                               }
+                               break;
+                       case ForceChannel:
+                               ev.set_channel (ffs (mask) - 1);
+                               ++e;
+                               break;
+                       case AllChannels:
+                               /* handled by the opening if() */
+                               ++e;
+                               break;
+                       }
+               } else {
+                       ++e;
+               }
+       }
+}
+
 void
 MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes)
 {
@@ -637,21 +698,53 @@ MidiTrack::write_source (uint32_t)
 }
 
 void
-MidiTrack::set_channel_mode (ChannelMode mode, uint16_t mask)
+MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask) 
 {
-       midi_diskstream()->set_channel_mode (mode, mask);
+       ChannelMode old = get_playback_channel_mode ();
+       uint16_t old_mask = get_playback_channel_mask ();
+
+       if (old != mode || mask != old_mask) {
+               _set_playback_channel_mode (mode, mask);
+               PlaybackChannelModeChanged ();
+               _session.set_dirty ();
+       }
 }
 
-ChannelMode
-MidiTrack::get_channel_mode ()
+void
+MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask) 
 {
-       return midi_diskstream()->get_channel_mode ();
+       ChannelMode old = get_capture_channel_mode ();
+       uint16_t old_mask = get_capture_channel_mask ();
+
+       if (old != mode || mask != old_mask) {
+               _set_capture_channel_mode (mode, mask);
+               CaptureChannelModeChanged ();
+               _session.set_dirty ();
+       }
 }
 
-uint16_t
-MidiTrack::get_channel_mask ()
+void
+MidiTrack::set_playback_channel_mask (uint16_t mask)
 {
-       return midi_diskstream()->get_channel_mask ();
+       uint16_t old = get_playback_channel_mask();
+
+       if (old != mask) {
+               _set_playback_channel_mask (mask);
+               PlaybackChannelMaskChanged ();
+               _session.set_dirty ();
+       }
+}
+
+void
+MidiTrack::set_capture_channel_mask (uint16_t mask)
+{
+       uint16_t old = get_capture_channel_mask();
+
+       if (old != mask) {
+               _set_capture_channel_mask (mask);
+               CaptureChannelMaskChanged ();
+               _session.set_dirty ();
+       }
 }
 
 boost::shared_ptr<MidiPlaylist>
@@ -739,7 +832,7 @@ MidiTrack::act_on_mute ()
        if (muted()) {
                /* only send messages for channels we are using */
 
-               uint16_t mask = get_channel_mask();
+               uint16_t mask = get_playback_channel_mask();
 
                for (uint8_t channel = 0; channel <= 0xF; channel++) {
 
@@ -792,3 +885,4 @@ MidiTrack::monitoring_state () const
        } 
        return ms;
 }
+
index c4bd6d77e849df19d1ae54b174a0cf20c6fbfb65..90522a7e06b2ca76efea55d2bff2b49e7f5b355f 100644 (file)
@@ -699,6 +699,8 @@ PluginManager::lxvst_discover (string path)
        VSTInfo* finfo;
        char buf[32];
 
+       DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
+
        if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
                return -1;
        }
index 519f3ca494d1c9b7c45b495ca70e10943a296184..921be6a53a69d02f4303e1269d434ec70100c0fa 100644 (file)
@@ -50,7 +50,7 @@ Return::Return (Session& s, bool internal)
        /* never muted */
 
        _amp.reset (new Amp (_session));
-       _meter.reset (new PeakMeter (_session));
+       _meter.reset (new PeakMeter (_session, name()));
 }
 
 Return::~Return ()
index 1a90553be2f80ebd4089597968beb515b595bf6b..9f933e0a4aa93c3bf00679d77078e4e09b307d8a 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "ardour/amp.h"
 #include "ardour/audio_buffer.h"
+#include "ardour/audio_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/buffer.h"
 #include "ardour/buffer_set.h"
@@ -46,6 +47,8 @@
 #include "ardour/internal_return.h"
 #include "ardour/internal_send.h"
 #include "ardour/meter.h"
+#include "ardour/midi_buffer.h"
+#include "ardour/midi_port.h"
 #include "ardour/monitor_processor.h"
 #include "ardour/pannable.h"
 #include "ardour/panner_shell.h"
@@ -139,7 +142,7 @@ Route::init ()
           they will be added to _processors by setup_invisible_processors ()
        */
 
-       _meter.reset (new PeakMeter (_session));
+       _meter.reset (new PeakMeter (_session, _name));
        _meter->set_display_to_user (false);
        _meter->activate ();
 
@@ -454,8 +457,8 @@ Route::process_output_buffers (BufferSet& bufs,
           on a transition between monitoring states we get a de-clicking gain
           change in the _main_outs delivery.
        */
-       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
 
+       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
 
        /* -------------------------------------------------------------------------------------------
           GLOBAL DECLICK (for transport changes etc.)
@@ -561,39 +564,26 @@ Route::n_process_buffers ()
 }
 
 void
-Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
 {
-       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+       assert (is_monitor());
+       BufferSet& bufs (_session.get_scratch_buffers (n_process_buffers()));
+       passthru (bufs, start_frame, end_frame, nframes, declick);
+}
 
+void
+Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+{
        _silent = false;
 
-       assert (bufs.available() >= input_streams());
-
-       if (_input->n_ports() == ChanCount::ZERO) {
-               silence_unlocked (nframes);
-       }
-
-       bufs.set_count (input_streams());
-
        if (is_monitor() && _session.listening() && !_session.is_auditioning()) {
 
                /* control/monitor bus ignores input ports when something is
                   feeding the listen "stream". data will "arrive" into the
                   route from the intreturn processor element.
                */
-               bufs.silence (nframes, 0);
-
-       } else {
-
-               for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
 
-                       BufferSet::iterator o = bufs.begin(*t);
-                       PortSet& ports (_input->ports());
-
-                       for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
-                               o->read_from (i->get_buffer(nframes), nframes);
-                       }
-               }
+               bufs.silence (nframes, 0);
        }
 
        write_out_of_band_data (bufs, start_frame, end_frame, nframes);
@@ -2985,6 +2975,7 @@ int
 Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
 {
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
        if (!lm.locked()) {
                return 0;
        }
@@ -2997,6 +2988,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                silence_unlocked (nframes);
                return 0;
        }
+
        if (session_state_changing) {
                if (_session.transport_speed() != 0.0f) {
                        /* we're rolling but some state is changing (e.g. our diskstream contents)
@@ -3012,8 +3004,16 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                */
        }
 
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+       fill_buffers_with_input (bufs, _input, nframes);
+
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
+       }
+
        _amp->apply_gain_automation (false);
-       passthru (start_frame, end_frame, nframes, 0);
+       passthru (bufs, start_frame, end_frame, nframes, 0);
 
        return 0;
 }
@@ -3043,7 +3043,15 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
 
        _silent = false;
 
-       passthru (start_frame, end_frame, nframes, declick);
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+       fill_buffers_with_input (bufs, _input, nframes);
+
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
+       }
+
+       passthru (bufs, start_frame, end_frame, nframes, declick);
 
        return 0;
 }
@@ -4148,3 +4156,90 @@ Route::non_realtime_locate (framepos_t pos)
                }
        }
 }
+
+void
+Route::fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes)
+{
+       size_t n_buffers;
+       size_t i;
+       
+       /* MIDI 
+        *  
+        * We don't currently mix MIDI input together, so we don't need the
+        * complex logic of the audio case.
+        */
+
+       n_buffers = bufs.count().n_midi ();
+
+       for (i = 0; i < n_buffers; ++i) {
+
+               boost::shared_ptr<MidiPort> source_port = io->midi (i);
+               MidiBuffer& buf (bufs.get_midi (i));
+               
+               if (source_port) {
+                       buf.copy (source_port->get_midi_buffer(nframes));
+               } else {
+                       buf.silence (nframes);
+               }
+       }
+
+       /* AUDIO */
+
+       n_buffers = bufs.count().n_audio();
+
+       size_t n_ports = io->n_ports().n_audio();
+       float scaling = 1.0f;
+
+       if (n_ports > n_buffers) {
+               scaling = ((float) n_buffers) / n_ports;
+       }
+       
+       for (i = 0; i < n_ports; ++i) {
+               
+               /* if there are more ports than buffers, map them onto buffers
+                * in a round-robin fashion
+                */
+
+               boost::shared_ptr<AudioPort> source_port = io->audio (i);
+               AudioBuffer& buf (bufs.get_audio (i%n_buffers));
+                       
+
+               if (i < n_buffers) {
+                       
+                       /* first time through just copy a channel into
+                          the output buffer.
+                       */
+
+                       buf.read_from (source_port->get_audio_buffer (nframes), nframes);
+
+                       if (scaling != 1.0f) {
+                               buf.apply_gain (scaling, nframes);
+                       }
+                       
+               } else {
+                       
+                       /* on subsequent times around, merge data from
+                        * the port with what is already there 
+                        */
+
+                       if (scaling != 1.0f) {
+                               buf.accumulate_with_gain_from (source_port->get_audio_buffer (nframes), nframes, 0, scaling);
+                       } else {
+                               buf.accumulate_from (source_port->get_audio_buffer (nframes), nframes);
+                       }
+               }
+       }
+
+       /* silence any remaining buffers */
+
+       for (; i < n_buffers; ++i) {
+               AudioBuffer& buf (bufs.get_audio (i));
+               buf.silence (nframes);
+       }
+
+       /* establish the initial setup of the buffer set, reflecting what was
+          copied into it.
+       */
+
+       bufs.set_count (io->n_ports());
+}
index fb5c6b7b0c13265e850edffc666ac8b5762df764..107cf9862b1fb0c4c1aabc4a9ce68991bc9fd136 100644 (file)
@@ -83,7 +83,7 @@ Send::Send (Session& s, boost::shared_ptr<Pannable> p, boost::shared_ptr<MuteMas
        boost_debug_shared_ptr_mark_interesting (this, "send");
 
        _amp.reset (new Amp (_session));
-       _meter.reset (new PeakMeter (_session));
+       _meter.reset (new PeakMeter (_session, name()));
 
        add_control (_amp->gain_control ());
 }
index 9a4fabeb6489d0f90c97a5e33d40c2a08b405521..cd7daaf185f8df9975b759951fee7718dd1f565f 100644 (file)
@@ -873,7 +873,7 @@ Session::process_audition (pframes_t nframes)
        /* if using a monitor section, run it because otherwise we don't hear anything */
 
        if (auditioner->needs_monitor()) {
-               _monitor_out->passthru (_transport_frame, _transport_frame + nframes, nframes, false);
+               _monitor_out->monitor_run (_transport_frame, _transport_frame + nframes, nframes, false);
        }
 
        /* handle pending events */
index 52a960fce697350faaaf6710455507b1d944f49e..1effaa45b81c7c1aa921cc01ca6f71cf234eaa2d 100644 (file)
@@ -330,16 +330,21 @@ int
 Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
 {
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
        if (!lm.locked()) {
                return 0;
        }
 
        bool can_record = _session.actively_recording ();
 
+       /* no outputs? nothing to do ... what happens if we have sends etc. ? */
+
        if (n_outputs().n_total() == 0) {
                return 0;
        }
 
+       /* not active ... do the minimum possible by just outputting silence */
+
        if (!_active) {
                silence (nframes);
                return 0;
@@ -393,14 +398,9 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                }
        }
 
-       if (!_have_internal_generator && metering_state() == MeteringInput) {
-               _input->process_input (_meter, start_frame, end_frame, nframes);
-       }
-
        _amp->apply_gain_automation (false);
 
        /* if have_internal_generator, or .. */
-       //_input->process_input (_meter, start_frame, end_frame, nframes);
 
        if (be_silent) {
 
@@ -408,10 +408,15 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
 
        } else {
 
-               /* we're sending signal, but we may still want to meter the input.
-                */
+               BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+               
+               fill_buffers_with_input (bufs, _input, nframes);
 
-               passthru (start_frame, end_frame, nframes, false);
+               if (_meter_point == MeterInput) {
+                       _meter->run (bufs, start_frame, end_frame, nframes, true);
+               }
+
+               passthru (bufs, start_frame, end_frame, nframes, false);
        }
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -447,7 +452,10 @@ Track::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*
        silence (nframes);
 
        framecnt_t playback_distance;
-       int const dret = _diskstream->process (_session.transport_frame(), nframes, playback_distance);
+
+       BufferSet& bufs (_session.get_silent_buffers (n_process_buffers()));
+
+       int const dret = _diskstream->process (bufs, _session.transport_frame(), nframes, playback_distance, false);
        need_butler = _diskstream->commit (playback_distance);
        return dret;
 }
@@ -934,3 +942,4 @@ Track::metering_state () const
 {
        return _diskstream->record_enabled() ? MeteringInput : MeteringRoute;
 }
+
index 431885112b1d6c6ac22f82822751c0d88e26ef3b..716d199fecc458bde73fb2b2c7e0d18dc4e0aff8 100644 (file)
@@ -65,7 +65,7 @@ public:
 
        void what_has_data(std::set<Parameter>&) const;
 
-       Glib::Threads::Mutex& control_lock() const { return _control_lock; }
+        Glib::Threads::Mutex& control_lock() const { return _control_lock; }
 
 protected:
        virtual void control_list_marked_dirty () {}
index 82e20239417d6cb094f38911168d63d388fb8a55..b1a42c6f2e7560025b9041e6a75d9815775b7cd2 100644 (file)
@@ -119,7 +119,7 @@ public:
        uint8_t channel () const { return _program_change.buffer()[0] & 0xf; }
 
        inline bool operator< (const PatchChange<Time>& o) const {
-               if (time() != o.time()) {
+               if (!musical_time_equal (time(), o.time())) {
                        return time() < o.time();
                }
 
@@ -131,7 +131,7 @@ public:
        }
 
        inline bool operator== (const PatchChange<Time>& o) const {
-               return (time() == o.time() && program() == o.program() && bank() == o.bank());
+               return (musical_time_equal (time(), o.time()) && program() == o.program() && bank() == o.bank());
        }
 
        /** The PatchChange is made up of messages() MIDI messages; this method returns them by index.
@@ -165,4 +165,10 @@ private:
 
 }
 
+template<typename Time>
+std::ostream& operator<< (std::ostream& o, const Evoral::PatchChange<Time>& p) {
+       o << "Patch Change " << p.id() << " @ " << p.time() << " bank " << (int) p.bank() << " program " << (int) p.program();
+       return o;
+}
+
 #endif
index 815d02f980ebb716d4adf4b80b35504e852d1b62..26bef20232a04a1ce5af757d8c9c312c887a0861 100644 (file)
@@ -69,8 +69,7 @@ protected:
        struct WriteLockImpl {
                WriteLockImpl(Glib::Threads::RWLock& s, Glib::Threads::Mutex& c)
                        : sequence_lock(new Glib::Threads::RWLock::WriterLock(s))
-                       , control_lock(new Glib::Threads::Mutex::Lock(c))
-               { }
+                       , control_lock(new Glib::Threads::Mutex::Lock(c)) { }
                ~WriteLockImpl() {
                        delete sequence_lock;
                        delete control_lock;
@@ -88,7 +87,7 @@ public:
        typedef boost::shared_ptr<WriteLockImpl>            WriteLock;
 
        virtual ReadLock  read_lock() const { return ReadLock(new Glib::Threads::RWLock::ReaderLock(_lock)); }
-       virtual WriteLock write_lock()      { return WriteLock(new WriteLockImpl(_lock, _control_lock)); }
+        virtual WriteLock write_lock()      { return WriteLock(new WriteLockImpl(_lock, _control_lock)); }
 
        void clear();
 
@@ -126,7 +125,7 @@ public:
        struct EarlierNoteComparator {
                inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
                                       const boost::shared_ptr< const Note<Time> > b) const {
-                       return a->time() < b->time();
+                       return musical_time_less_than (a->time(), b->time());
                }
        };
 
@@ -134,6 +133,7 @@ public:
                typedef const Note<Time>* value_type;
                inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
                                       const boost::shared_ptr< const Note<Time> > b) const {
+                       return musical_time_greater_than (a->time(), b->time());
                        return a->time() > b->time();
                }
        };
@@ -142,7 +142,7 @@ public:
                typedef const Note<Time>* value_type;
                inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
                                       const boost::shared_ptr< const Note<Time> > b) const {
-                       return a->end_time() > b->end_time();
+                       return musical_time_less_than (a->end_time(), b->end_time());
                }
        };
 
@@ -186,7 +186,7 @@ public:
 
        struct EarlierSysExComparator {
                inline bool operator() (constSysExPtr a, constSysExPtr b) const {
-                       return a->time() < b->time();
+                       return musical_time_less_than (a->time(), b->time());
                }
        };
 
@@ -199,7 +199,7 @@ public:
 
        struct EarlierPatchChangeComparator {
                inline bool operator() (constPatchChangePtr a, constPatchChangePtr b) const {
-                       return a->time() < b->time();
+                       return musical_time_less_than (a->time(), b->time());
                }
        };
 
index 7bdbdc7a2e15b95bfb8885d1fa53b226f8ea4889..000b79bb94c621b58046e2054cf8c7cf822c583e 100644 (file)
@@ -43,6 +43,33 @@ static inline bool musical_time_equal (MusicalTime a, MusicalTime b) {
        return fabs (a - b) <= (1.0/1920.0);
 }
 
+static inline bool musical_time_less_than (MusicalTime a, MusicalTime b) {
+       /* acceptable tolerance is 1 tick. Nice if there was no magic number here */
+       if (fabs (a - b) <= (1.0/1920.0)) {
+               return false; /* effectively identical */
+       } else {
+               return a < b;
+       }
+}
+
+static inline bool musical_time_greater_than (MusicalTime a, MusicalTime b) {
+       /* acceptable tolerance is 1 tick. Nice if there was no magic number here */
+       if (fabs (a - b) <= (1.0/1920.0)) {
+               return false; /* effectively identical */
+       } else {
+               return a > b;
+       }
+}
+
+static inline bool musical_time_greater_or_equal_to (MusicalTime a, MusicalTime b) {
+       /* acceptable tolerance is 1 tick. Nice if there was no magic number here */
+       if (fabs (a - b) <= (1.0/1920.0)) {
+               return true; /* effectively identical, note the "or_equal_to" */
+       } else {
+               return a >= b;
+       }
+}
+
 /** Type of an event (opaque, mapped by application) */
 typedef uint32_t EventType;
 
index 71bdcb7c03a7857d7fa05fe2594c4a8b0e76cf78..738d5a19c9183562f563d7c930867721c2b37cf0 100644 (file)
@@ -720,25 +720,27 @@ void
 Sequence<Time>::remove_note_unlocked(const constNotePtr note)
 {
        bool erased = false;
+       bool id_matched = false;
 
-       _edited = true;
-
-       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 remove note %2 @ %3\n", this, (int)note->note(), note->time()));
+       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 remove note #%2 %3 @ %4\n", this, note->id(), (int)note->note(), note->time()));
 
-       typename Sequence<Time>::Notes::iterator i = note_lower_bound(note->time());
-       while (i != _notes.end() && (*i)->time() == note->time()) {
+       /* first try searching for the note using the time index, which is
+        * faster since the container is "indexed" by time. (technically, this
+        * means that lower_bound() can do a binary search rather than linear)
+        *
+        * this may not work, for reasons explained below.
+        */
 
-               typename Sequence<Time>::Notes::iterator tmp = i;
-               ++tmp;
+       typename Sequence<Time>::Notes::iterator i;
+               
+       for (i = note_lower_bound(note->time()); i != _notes.end() && musical_time_equal ((*i)->time(), note->time()); ++i) {
 
                if (*i == note) {
 
-                       NotePtr n = *i;
-
-                       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing note %2 @ %3\n", this, (int)(*i)->note(), (*i)->time()));
+                       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing note #%2 %3 @ %4\n", this, (*i)->id(), (int)(*i)->note(), (*i)->time()));
                        _notes.erase (i);
 
-                       if (n->note() == _lowest_note || n->note() == _highest_note) {
+                       if (note->note() == _lowest_note || note->note() == _highest_note) {
 
                                _lowest_note = 127;
                                _highest_note = 0;
@@ -752,30 +754,100 @@ Sequence<Time>::remove_note_unlocked(const constNotePtr note)
                        }
 
                        erased = true;
+                       break;
                }
+       }
 
-               i = tmp;
+       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\ttime-based lookup did not find note #%2 %3 @ %4\n", this, note->id(), (int)note->note(), note->time()));
+
+       if (!erased) {
+
+               /* if the note's time property was changed in tandem with some
+                * other property as the next operation after it was added to
+                * the sequence, then at the point where we call this to undo
+                * the add, the note we are targetting currently has a
+                * different time property than the one we we passed via
+                * the argument.
+                *
+                * in this scenario, we have no choice other than to linear
+                * search the list of notes and find the note by ID.
+                */
+               
+               for (i = _notes.begin(); i != _notes.end(); ++i) {
+
+                       if ((*i)->id() == note->id()) {
+                               
+                               DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\tID-based pass, erasing note #%2 %3 @ %4\n", this, (*i)->id(), (int)(*i)->note(), (*i)->time()));
+                               _notes.erase (i);
+                               
+                               if (note->note() == _lowest_note || note->note() == _highest_note) {
+                                       
+                                       _lowest_note = 127;
+                                       _highest_note = 0;
+                                       
+                                       for (typename Sequence<Time>::Notes::iterator ii = _notes.begin(); ii != _notes.end(); ++ii) {
+                                               if ((*ii)->note() < _lowest_note)
+                                                       _lowest_note = (*ii)->note();
+                                               if ((*ii)->note() > _highest_note)
+                                                       _highest_note = (*ii)->note();
+                                       }
+                               }
+                               
+                               erased = true;
+                               id_matched = true;
+                               break;
+                       }
+               }
        }
+       
+       if (erased) {
 
-       Pitches& p (pitches (note->channel()));
+               Pitches& p (pitches (note->channel()));
+               
+               typename Pitches::iterator j;
 
-       NotePtr search_note(new Note<Time>(0, 0, 0, note->note(), 0));
+               /* if we had to ID-match above, we can't expect to find it in
+                * pitches via note comparison either. so do another linear
+                * search to locate it. otherwise, we can use the note index
+                * to potentially speed things up.
+                */
 
-       typename Pitches::iterator j = p.lower_bound (search_note);
-       while (j != p.end() && (*j)->note() == note->note()) {
-               typename Pitches::iterator tmp = j;
-               ++tmp;
+               if (id_matched) {
+
+                       for (j = p.begin(); j != p.end(); ++j) {
+                               if ((*j)->id() == note->id()) {
+                                       p.erase (j);
+                                       break;
+                               }
+                       }
+
+               } else {
 
-               if (*j == note) {
-                       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing pitch %2 @ %3\n", this, (int)(*j)->note(), (*j)->time()));
-                       p.erase (j);
+                       /* Now find the same note in the "pitches" list (which indexes
+                        * notes by channel+time. We care only about its note number
+                        * so the search_note has all other properties unset.
+                        */
+                       
+                       NotePtr search_note (new Note<Time>(0, 0, 0, note->note(), 0));
+
+                       for (j = p.lower_bound (search_note); j != p.end() && (*j)->note() == note->note(); ++j) {
+                               
+                               if ((*j) == note) {
+                                       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing pitch %2 @ %3\n", this, (int)(*j)->note(), (*j)->time()));
+                                       p.erase (j);
+                                       break;
+                               }
+                       }
                }
 
-               j = tmp;
-       }
+               if (j == p.end()) {
+                       warning << string_compose ("erased note %1 not found in pitches for channel %2", *note, (int) note->channel()) << endmsg;
+               }
 
-       if (!erased) {
-               cerr << "Unable to find note to erase matching " << *note.get() << endl;
+               _edited = true;
+       
+       } else {
+               cerr << "Unable to find note to erase matching " << *note.get() << endmsg;
        }
 }
 
@@ -784,12 +856,13 @@ void
 Sequence<Time>::remove_patch_change_unlocked (const constPatchChangePtr p)
 {
        typename Sequence<Time>::PatchChanges::iterator i = patch_change_lower_bound (p->time ());
-       while (i != _patch_changes.end() && (*i)->time() == p->time()) {
+
+       while (i != _patch_changes.end() && (musical_time_equal ((*i)->time(), p->time()))) {
 
                typename Sequence<Time>::PatchChanges::iterator tmp = i;
                ++tmp;
 
-               if (*i == p) {
+               if (**i == *p) {
                        _patch_changes.erase (i);
                }
 
@@ -1148,7 +1221,7 @@ Sequence<Time>::patch_change_lower_bound (Time t) const
 {
        PatchChangePtr search (new PatchChange<Time> (t, 0, 0, 0));
        typename Sequence<Time>::PatchChanges::const_iterator i = _patch_changes.lower_bound (search);
-       assert (i == _patch_changes.end() || (*i)->time() >= t);
+       assert (i == _patch_changes.end() || musical_time_greater_or_equal_to ((*i)->time(), t));
        return i;
 }
 
diff --git a/libs/gtkmm2ext/gtkmm2ext/visibility_tracker.h b/libs/gtkmm2ext/gtkmm2ext/visibility_tracker.h
new file mode 100644 (file)
index 0000000..6415dd6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    Copyright (C) 2013 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 __libgtkmm2ext_visibility_tracker__
+#define __libgtkmm2ext_visibility_tracker__
+
+#include <gdk/gdkevents.h>
+
+namespace GTK {
+       class Window;
+}
+
+namespace Gtkmm2ext {
+
+class VisibilityTracker {
+  public:
+    VisibilityTracker (Gtk::Window&);
+    virtual ~VisibilityTracker() {}
+    
+    void cycle_visibility ();
+
+  private:
+    Gtk::Window& window;
+    GdkVisibilityState _visibility;
+    bool handle_visibility_notify_event (GdkEventVisibility*);
+};
+
+}
+
+#endif /* __libgtkmm2ext_visibility_tracker__ */ 
diff --git a/libs/gtkmm2ext/visibility_tracker.cc b/libs/gtkmm2ext/visibility_tracker.cc
new file mode 100644 (file)
index 0000000..c0aabdf
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+    Copyright (C) 2013 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 <gtkmm/window.h>
+
+#include "gtkmm2ext/visibility_tracker.h"
+
+using namespace Gtkmm2ext;
+
+VisibilityTracker::VisibilityTracker (Gtk::Window& win)
+       : window (win)
+       , _visibility (GdkVisibilityState (0))
+{
+       window.add_events (Gdk::VISIBILITY_NOTIFY_MASK);
+       window.signal_visibility_notify_event().connect (sigc::mem_fun (*this, &VisibilityTracker::handle_visibility_notify_event));
+}
+
+bool
+VisibilityTracker::handle_visibility_notify_event (GdkEventVisibility* ev)
+{
+       _visibility = ev->state;
+       return false;
+}
+
+void
+VisibilityTracker::cycle_visibility ()
+{
+       if (window.is_mapped() && (_visibility == GDK_VISIBILITY_UNOBSCURED)) {
+               window.hide ();
+       } else {
+               window.present ();
+       }
+}
+
index f2d53117ad1453ff5d72aeab12e763be0206546a..494ec8b225a60aef5e2908fda499f2f0c863e5d0 100644 (file)
@@ -61,6 +61,7 @@ gtkmm2ext_sources = [
         'treeutils.cc',
         'utils.cc',
         'version.cc',
+        'visibility_tracker.cc',
         'window_title.cc'
 ]
 
index 98d0fc5091e77265380b36044954db437d40e3ab..c86afbe87e723b74205f1cef1483d3c060b9b7b7 100644 (file)
@@ -34,7 +34,11 @@ static uint64_t _debug_bit = 1;
 typedef std::map<const char*,uint64_t> DebugMap;
 
 namespace PBD {
-       DebugMap _debug_bit_map;
+       DebugMap & _debug_bit_map()
+       {
+               static DebugMap map;
+               return map;
+       }
 }
 
 uint64_t PBD::DEBUG::Stateful = PBD::new_debug_bit ("stateful");
@@ -50,7 +54,7 @@ uint64_t
 PBD::new_debug_bit (const char* name)
 {
         uint64_t ret;
-        _debug_bit_map.insert (make_pair (name, _debug_bit));
+        _debug_bit_map().insert (make_pair (name, _debug_bit));
         ret = _debug_bit;
         _debug_bit <<= 1;
         return ret;
@@ -91,7 +95,7 @@ PBD::parse_debug_options (const char* str)
                        return 0;
                }
 
-                for (map<const char*,uint64_t>::iterator i = _debug_bit_map.begin(); i != _debug_bit_map.end(); ++i) {
+               for (map<const char*,uint64_t>::iterator i = _debug_bit_map().begin(); i != _debug_bit_map().end(); ++i) {
                         if (strncasecmp (p, i->first, strlen (p)) == 0) {
                                 bits |= i->second;
                         }
@@ -113,7 +117,7 @@ PBD::list_debug_options ()
 
        vector<string> options;
 
-        for (map<const char*,uint64_t>::iterator i = _debug_bit_map.begin(); i != _debug_bit_map.end(); ++i) {
+       for (map<const char*,uint64_t>::iterator i = _debug_bit_map().begin(); i != _debug_bit_map().end(); ++i) {
                options.push_back (i->first);
         }
 
index 4cb4a20f3ea3346f4f013e8d73adbf6eac3d30e4..aa5431e705959ea3164739af8250ec90ed6142aa 100644 (file)
@@ -112,10 +112,10 @@ def build(bld):
 
     # Library
     if bld.is_defined ('INTERNAL_SHARED_LIBS'):
-        print 'BUILD SHARED LIB'
+        print('BUILD SHARED LIB')
         obj              = bld.shlib(features = 'cxx cxxshlib', source=libpbd_sources)
     else:
-        print 'BUILD STATIC LIB'
+        print('BUILD STATIC LIB')
         obj              = bld.stlib(features = 'cxx cxxstlib', source=libpbd_sources)
         obj.cxxflags     = [ '-fPIC' ]
 
index 6545e80b405c35d54069a17f9ba2a3480f73a64a..33dfc45515985fa6336c39fc9f7be59e858a96cd 100644 (file)
@@ -31,6 +31,9 @@ if [ ! -d $USER_ARDOUR_DIR ] ; then
     mkdir -p $USER_ARDOUR_DIR || exit 1
 fi
 
+PATH="${BIN_DIR}:${PATH}"
+export PATH
+
 # this triggers code in main() that will reset runtime environment variables
 # to point to directories inside the ardour package
 
index 8b692de74ec5189bb811f94033ca39c9d0936c60..3962ce65cd278fa51e72e3d539585c41a3fd99af 100755 (executable)
@@ -16,6 +16,7 @@ BUILD_ROOT=../../build
 
 MIXBUS=
 WITH_LADSPA=0
+WITH_HARVID=0
 STRIP=all
 PRINT_SYSDEPS=
 WITH_NLS=
@@ -70,6 +71,7 @@ while [ $# -gt 0 ] ; do
        --strip) STRIP=$2 ; shift ; shift ;;
        --sysdeps) PRINT_SYSDEPS=1; shift ;;
        --nls) WITH_NLS=1 ; shift ;;
+       --harvid) WITH_HARVID=1 ; shift ;;
 
        *)
                #catch all for unknown arguments
@@ -87,10 +89,10 @@ if test x$STRIP != xall -a x$STRIP != xnone -a x$STRIP != xsome ; then
     exit 1
 fi
 
-release_version=`grep -m 1 '[^A-Za-z_]LINUX_VERSION = ' ../../wscript | awk '{ print $3 }' | sed "s/'//g"`
-revision=`grep -m 1 'revision =' ../../libs/ardour/revision.cc | cut -d'"' -f 2`
-echo "Version is $release_version / $revision"
-info_string="$release_version/$revision built on `hostname` by `whoami` on `date`"
+. ./define_versions.sh
+
+echo "Version is $version / $commit"
+info_string="$version ($commit) built on `hostname` by `whoami` on `date`"
 echo "Info string is $info_string"
 
 # Figure out our CPU type
@@ -99,11 +101,13 @@ case `uname -m` in
                echo "Architecture is x86"
                ARCH='x86'
                ARCH_BITS='32-bit'
+               MULTIARCH='i386-linux-gnu'
                ;;
        x86_64|amd64|AMD64)
                echo "Architecture is x86_64"
                ARCH='x86_64'
                ARCH_BITS='64-bit'
+               MULTIARCH='x86_64-linux-gnu'
                ;;
        *)
                echo ""
@@ -113,13 +117,6 @@ case `uname -m` in
                ;;
 esac
 
-# Figure out the Build Type
-if grep -q "DEBUG = True" ../../build/c4che/default.cache.py; then
-       DEBUG="T"
-else
-       DEBUG="F"
-fi
-
 if [ x$DEBUG = xT ]; then
     BUILDTYPE="dbg"
     if [ x$STRIP = xall ] ; then
@@ -131,11 +128,11 @@ fi
 # setup directory structure
 
 if [ -z "${BUILDTYPE}" ]; then
-       APPDIR=${APPNAME}_${ARCH}-${release_version}_${revision}
-       APP_VER_NAME=${APPNAME}-${release_version}_${revision}
+       APPDIR=${APPNAME}_${ARCH}-${version}
+       APP_VER_NAME=${APPNAME}-${version}
 else
-       APPDIR=${APPNAME}_${ARCH}-${release_version}_${revision}-${BUILDTYPE}
-       APP_VER_NAME=${APPNAME}-${release_version}_${revision}-${BUILDTYPE}
+       APPDIR=${APPNAME}_${ARCH}-${version}-${BUILDTYPE}
+       APP_VER_NAME=${APPNAME}-${version}-${BUILDTYPE}
 fi
 
 APPBIN=$APPDIR/bin
@@ -532,10 +529,18 @@ for svndir in `find $APPDIR -name .svn -type d`; do
        rm -rf $svndir
 done
 
+if test x$WITH_HARVID != x ; then
+       cd $APPBIN
+       HARVID_VERSION="v0.7.0" # todo make 'latest' symlink on github work somehow.
+       curl http://x42.github.com/harvid/releases/harvid-${MULTIARCH}-${HARVID_VERSION}.tgz \
+               | tar -x -z --exclude=README --exclude=harvid.1 --strip-components=1 || exit 1
+       cd -
+fi
+
 #
 # Add the uninstaller
 #
-sed -e "s/%REPLACE_PGM%/${APPNAME}/" -e "s/%REPLACE_VENDOR%/${VENDOR}/" -e "s/%REPLACE_VERSION%/${release_version}/" -e "s/%REPLACE_BUILD%/${revision}/" -e "s/%REPLACE_TYPE%/${BUILDTYPE}/" < uninstall.sh.in > $APPBIN/${APP_VER_NAME}.uninstall.sh
+sed -e "s/%REPLACE_PGM%/${APPNAME}/" -e "s/%REPLACE_VENDOR%/${VENDOR}/" -e "s/%REPLACE_VERSION%/${version}/" -e "s/%REPLACE_TYPE%/${BUILDTYPE}/" < uninstall.sh.in > $APPBIN/${APP_VER_NAME}.uninstall.sh
 chmod a+x $APPBIN/${APP_VER_NAME}.uninstall.sh
 
 #Sanity Check file
diff --git a/tools/linux_packaging/define_versions.sh b/tools/linux_packaging/define_versions.sh
new file mode 100644 (file)
index 0000000..611df80
--- /dev/null
@@ -0,0 +1,21 @@
+# 
+# this is sourced by build and package, and executed from within build/linux_packaging
+#
+
+release_version=`grep -m 1 '[^A-Za-z_]LINUX_VERSION = ' ../../wscript | awk '{print $3}' | sed "s/'//g"`
+r=`cut -d'"' -f2 < ../../libs/ardour/revision.cc | sed -e 1d -e "s/$release_version-//"`
+revcount=`echo $r | cut -d- -f1`
+commit=`echo $r | cut -d- -f2`
+version=${release_version}.${revcount}
+
+#
+# Figure out the Build Type
+#
+# Note that the name of the cache file may vary from to time
+#
+
+if grep -q "DEBUG = True" ../../build/c4che/_cache.py; then
+       DEBUG="T"
+else
+       DEBUG="F"
+fi
index 85cac2ed9807a8333a8deb383bb2784f1c89e2c5..ea50ce4b981d6b6c76fa052387801117aa8aa599 100755 (executable)
@@ -50,30 +50,20 @@ while [ $# -gt 0 ] ; do
        esac
 done
 
-
-# Figure out the Build Type
-if grep -q "DEBUG = True" ../../build/c4che/default.cache.py; then
-       DEBUG="T"
-else
-       DEBUG="F"
-fi
+. ./define_versions.sh
 
 if [ x$DEBUG = xT ]; then
        BUILDTYPE="dbg"
 fi
 
-release_version=`grep -m 1 '[^A-Za-z_]LINUX_VERSION = ' ../../wscript | awk '{print $3}' | sed "s/'//g"`
-revision=`grep -m 1 'revision =' ../../libs/ardour/revision.cc | cut -d'"' -f 2`
-
-X86_BUNDLE="${APPNAME}_x86-${release_version}_${revision}"
-X86_64_BUNDLE="${APPNAME}_x86_64-${release_version}_${revision}"
+X86_BUNDLE="${APPNAME}_x86-${version}"
+X86_64_BUNDLE="${APPNAME}_x86_64-${version}"
 
 if [ ! -z ${BUILDTYPE} ]; then
        X86_BUNDLE="${X86_BUNDLE}-${BUILDTYPE}"
        X86_64_BUNDLE="${X86_64_BUNDLE}-${BUILDTYPE}"
 fi 
 
-
 if [ ! -e ${X86_BUNDLE}.tar.bz2 ] ; then
        echo ""
        echo "Can't locate x86 bundle file ${X86_BUNDLE}.tar.bz2"
@@ -122,22 +112,22 @@ fi
 if [ -z ${BUILDTYPE} ]; then
        if [ "${SINGLE_ARCH}" = "T" ]; then
                if [ "${X86_BUNDLE_OK}" = "T" ]; then
-                       PACKAGE="${APPNAME}_32bit-${release_version}_${revision}"
+                       PACKAGE="${APPNAME}_32bit-${version}"
                else
-                       PACKAGE="${APPNAME}_64bit-${release_version}_${revision}"
+                       PACKAGE="${APPNAME}_64bit-${version}"
                fi
        else
-               PACKAGE="${APPNAME}-${release_version}_${revision}"
+               PACKAGE="${APPNAME}-${version}"
        fi
 else
        if [ "${SINGLE_ARCH}" = "T" ]; then
                if [ "${X86_BUNDLE_OK}" = "T" ]; then
-                       PACKAGE="${APPNAME}_32bit-${release_version}_${revision}-${BUILDTYPE}"
+                       PACKAGE="${APPNAME}_32bit-${version}-${BUILDTYPE}"
                else
-                       PACKAGE="${APPNAME}_64bit-${release_version}_${revision}-${BUILDTYPE}"
+                       PACKAGE="${APPNAME}_64bit-${version}-${BUILDTYPE}"
                fi
        else
-               PACKAGE="${APPNAME}-${release_version}_${revision}-${BUILDTYPE}"
+               PACKAGE="${APPNAME}-${version}-${BUILDTYPE}"
        fi
 fi 
 
index 2bed7fa5fbcde894091fb4ecde0b44ad4c3e0b91..4f92ac5f4c0dcce1d0c054fd46b6ebfd281c6a81 100755 (executable)
@@ -371,18 +371,17 @@ 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_BUILDTYPE=$(echo ${BUNDLE_DIR} | awk 'BEGIN { FS = "-" } ; { print $3 }')
+PGM_VERSION=$(echo ${BUNDLE_DIR} | cut -d- -f2)
+PGM_BUILDTYPE=$(echo ${BUNDLE_DIR} | cut -d- -f3)
 
 if [ -z ${PGM_BUILDTYPE} ];
 then
-       PGM_FULL_NAME="${PGM_NAME}-${PGM_VERSION}_${PGM_BUILD}"
+       PGM_FULL_NAME="${PGM_NAME}-${PGM_VERSION}"
        ICON_NAME="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}"                    #no dash between name and version since dash seperates vendor from program
        MENU_FILE="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}.desktop"    #no dash between name and version since dash seperates vendor from program
        DESKTOP_LINK_FILE="${PGM_NAME}_${PGM_VERSION}.desktop"
 else
-       PGM_FULL_NAME="${PGM_NAME}-${PGM_VERSION}_${PGM_BUILD}-${PGM_BUILDTYPE}"
+       PGM_FULL_NAME="${PGM_NAME}-${PGM_VERSION}-${PGM_BUILDTYPE}"
        ICON_NAME="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}_${PGM_BUILDTYPE}"                   #no dash between name and version since dash seperates vendor from program
        MENU_FILE="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}_${PGM_BUILDTYPE}.desktop"   #no dash between name and version since dash seperates vendor from program
        DESKTOP_LINK_FILE="${PGM_NAME}_${PGM_VERSION}_${PGM_BUILDTYPE}.desktop"
@@ -421,7 +420,7 @@ fi
 # install 
 
 echo ""
-echo "Installing ${PGM_NAME} ${PGM_VERSION} built from ${PGM_BUILD} in ${INSTALL_DEST_BASE}"
+echo "Installing ${PGM_NAME} ${PGM_VERSION} in ${INSTALL_DEST_BASE}"
 echo ""
 
 # Copy the new version in the install directory
index b1e4f3cec3391e13b18d9a201c2ecf107e1804dc..795c5d317db03c10baaf94687a67534951545999 100644 (file)
@@ -11,7 +11,6 @@
 PGM_NAME="%REPLACE_PGM%"
 PGM_VENDOR="%REPLACE_VENDOR%"
 PGM_VERSION="%REPLACE_VERSION%"
-PGM_BUILD="%REPLACE_BUILD%"
 PGM_BUILDTYPE="%REPLACE_TYPE%"
 
 INSTALL_DEST_BASE=/opt
@@ -24,12 +23,12 @@ USER_NAME=$(logname)
 
 #### Derived Variables ####
 if [ -z "${PGM_BUILDTYPE}" ]; then
-       PGM_PATH=${INSTALL_DEST_BASE}/${PGM_NAME}-${PGM_VERSION}_${PGM_BUILD}
+       PGM_PATH=${INSTALL_DEST_BASE}/${PGM_NAME}-${PGM_VERSION}
        ICON_NAME="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}"                    #no dash between name and version since dash seperates vendor from program
        MENU_FILE="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}.desktop"    #no dash between name and version since dash seperates vendor from program
        DESKTOP_LINK_FILE="${PGM_NAME}_${PGM_VERSION}.desktop"
 else
-       PGM_PATH=${INSTALL_DEST_BASE}/${PGM_NAME}-${PGM_VERSION}_${PGM_BUILD}-${PGM_BUILDTYPE}
+       PGM_PATH=${INSTALL_DEST_BASE}/${PGM_NAME}-${PGM_VERSION}-${PGM_BUILDTYPE}
        ICON_NAME="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}_${PGM_BUILDTYPE}"                   #no dash between name and version since dash seperates vendor from program
        MENU_FILE="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}_${PGM_BUILDTYPE}.desktop"   #no dash between name and version since dash seperates vendor from program
        DESKTOP_LINK_FILE="${PGM_NAME}_${PGM_VERSION}_${PGM_BUILDTYPE}.desktop"