diff --git a/gtk2_ardour/actions.cc b/gtk2_ardour/actions.cc index bdb6821f89..4c4117edcb 100644 --- a/gtk2_ardour/actions.cc +++ b/gtk2_ardour/actions.cc @@ -85,15 +85,15 @@ ActionManager::load_menus (const string& menus_file) info << string_compose (_("Loading menus from %1"), ui_file) << endmsg; loaded = true; } catch (Glib::MarkupError& err) { - error << string_compose (_("badly formatted UI definition file: %1"), err.what()) << endmsg; - cerr << string_compose (_("badly formatted UI definition file: %1"), err.what()) << endl; + error << string_compose (_("badly formatted menu definition file: %1"), err.what()) << endmsg; + cerr << string_compose (_("badly formatted menu definition file: %1"), err.what()) << endl; } catch (...) { error << string_compose (_("%1 menu definition file not found"), PROGRAM_NAME) << endmsg; } if (!loaded) { - cerr << string_compose (_("%1 will not work without a valid ardour.menus file"), PROGRAM_NAME) << endl; - error << string_compose (_("%1 will not work without a valid ardour.menus file"), PROGRAM_NAME) << endmsg; + cerr << string_compose (_("%1 will not work without a valid menu definition file"), PROGRAM_NAME) << endl; + error << string_compose (_("%1 will not work without a valid menu definition file"), PROGRAM_NAME) << endmsg; exit(1); } } diff --git a/gtk2_ardour/analysis_window.cc b/gtk2_ardour/analysis_window.cc index 998ab8ab12..f653490345 100644 --- a/gtk2_ardour/analysis_window.cc +++ b/gtk2_ardour/analysis_window.cc @@ -374,6 +374,7 @@ AnalysisWindow::analyze_data (Gtk::Button * /*button*/) free(buf); free(mixbuf); + free(gain); track_list_ready = true; } /* end lock */ diff --git a/gtk2_ardour/ardour_button.cc b/gtk2_ardour/ardour_button.cc index 6cf220596f..826a1e5a06 100644 --- a/gtk2_ardour/ardour_button.cc +++ b/gtk2_ardour/ardour_button.cc @@ -267,7 +267,7 @@ ArdourButton::render (cairo_t* cr) } } - if ( ((_elements & FlatFace)==FlatFace) && (active_state() != Gtkmm2ext::ExplicitActive) ) { + if ( ((_elements & Inset)==Inset) && (active_state() != Gtkmm2ext::ExplicitActive) ) { if ( !_flat_buttons ) { float rheight = get_height()*0.5-REFLECTION_HEIGHT; diff --git a/gtk2_ardour/ardour_button.h b/gtk2_ardour/ardour_button.h index cf47fd1d30..c179a24718 100644 --- a/gtk2_ardour/ardour_button.h +++ b/gtk2_ardour/ardour_button.h @@ -37,7 +37,7 @@ class ArdourButton : public CairoWidget , public Gtkmm2ext::Activatable Body = 0x2, Text = 0x4, Indicator = 0x8, - FlatFace = 0x10, + Inset = 0x10, }; static Element default_elements; diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 0619923e24..e881a6f2b7 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1659,10 +1659,10 @@ ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& out catch (...) { MessageDialog msg (*editor, - string_compose (_("There are insufficient JACK ports available\n\ + string_compose (_("There are insufficient ports available\n\ to create a new track or bus.\n\ You should save %1, exit and\n\ -restart JACK with more ports."), PROGRAM_NAME)); +restart with more ports."), PROGRAM_NAME)); msg.run (); } } @@ -1720,10 +1720,10 @@ ARDOUR_UI::session_add_audio_route ( catch (...) { MessageDialog msg (*editor, - string_compose (_("There are insufficient JACK ports available\n\ + string_compose (_("There are insufficient ports available\n\ to create a new track or bus.\n\ You should save %1, exit and\n\ -restart JACK with more ports."), PROGRAM_NAME)); +restart with more ports."), PROGRAM_NAME)); pop_back_splash (msg); msg.run (); } @@ -1885,12 +1885,25 @@ ARDOUR_UI::transport_roll () bool rolling = _session->transport_rolling(); if (_session->get_play_loop()) { - /* XXX it is not possible to just leave seamless loop and keep - playing at present (nov 4th 2009) + + /* If loop playback is not a mode, then we should cancel + it when this action is requested. If it is a mode + we just leave it in place. */ - if (!Config->get_seamless_loop()) { - _session->request_play_loop (false, true); - } + + if (!Config->get_loop_is_mode()) { + /* XXX it is not possible to just leave seamless loop and keep + playing at present (nov 4th 2009) + */ + if (!Config->get_seamless_loop()) { + /* stop loop playback and stop rolling */ + _session->request_play_loop (false, true); + } else if (rolling) { + /* stop loop playback but keep rolling */ + _session->request_play_loop (false, false); + } + } + } else if (_session->get_play_range () && !Config->get_always_play_range()) { /* stop playing a range if we currently are */ _session->request_play_range (0, true); @@ -1947,7 +1960,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) /* disk buffers are normal, so we can keep playing */ affect_transport = false; } - _session->request_play_loop (false, true); + _session->request_play_loop (false, affect_transport); } else if (_session->get_play_range ()) { affect_transport = false; _session->request_play_range (0, true); @@ -1978,16 +1991,23 @@ ARDOUR_UI::toggle_session_auto_loop () if (_session->get_play_loop()) { - if (_session->transport_rolling()) { + /* looping enabled, our job is to disable it */ - _session->request_locate (looploc->start(), true); - _session->request_play_loop (false); + _session->request_play_loop (false); - } else { - _session->request_play_loop (false); - } } else { - _session->request_play_loop (true); + + /* looping not enabled, our job is to enable it. + + loop-is-NOT-mode: this action always starts the transport rolling. + loop-IS-mode: this action simply sets the loop play mechanism, but + does not start transport. + */ + if (Config->get_loop_is_mode()) { + _session->request_play_loop (true, false); + } else { + _session->request_play_loop (true, true); + } } //show the loop markers @@ -2115,7 +2135,11 @@ ARDOUR_UI::map_transport_state () auto_loop_button.set_active (true); play_selection_button.set_active (false); - roll_button.set_active (false); + if (Config->get_loop_is_mode()) { + roll_button.set_active (true); + } else { + roll_button.set_active (false); + } } else { @@ -2137,7 +2161,11 @@ ARDOUR_UI::map_transport_state () stop_button.set_active (true); roll_button.set_active (false); play_selection_button.set_active (false); - auto_loop_button.set_active (false); + if (Config->get_loop_is_mode ()) { + auto_loop_button.set_active (_session->get_play_loop()); + } else { + auto_loop_button.set_active (false); + } update_disk_space (); } } diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 3da0b03a15..6a30231d42 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -175,6 +175,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr void new_midi_tracer_window (); void toggle_editing_space(); + void toggle_mixer_space(); void toggle_keep_tearoffs(); Gtk::Tooltips& tooltips() { return _tooltips; } diff --git a/gtk2_ardour/ardour_ui2.cc b/gtk2_ardour/ardour_ui2.cc index 2a794827e0..e9efb1d03a 100644 --- a/gtk2_ardour/ardour_ui2.cc +++ b/gtk2_ardour/ardour_ui2.cc @@ -387,20 +387,29 @@ ARDOUR_UI::setup_transport () HBox* clock_box = manage (new HBox); clock_box->pack_start (*primary_clock, false, false); - if (!ARDOUR::Profile->get_small_screen()) { + if (!ARDOUR::Profile->get_small_screen() && !ARDOUR::Profile->get_trx()) { clock_box->pack_start (*secondary_clock, false, false); } clock_box->set_spacing (3); shuttle_box = new ShuttleControl; shuttle_box->show (); - + VBox* transport_vbox = manage (new VBox); transport_vbox->set_name ("TransportBase"); transport_vbox->set_border_width (0); transport_vbox->set_spacing (3); transport_vbox->pack_start (*tbox, true, true, 0); - transport_vbox->pack_start (*shuttle_box, false, false, 0); + + if (!Profile->get_trx()) { + transport_vbox->pack_start (*shuttle_box, false, false, 0); + } + + time_info_box = manage (new TimeInfoBox); + + if (ARDOUR::Profile->get_trx()) { + transport_tearoff_hbox.pack_start (*time_info_box, false, false); + } transport_tearoff_hbox.pack_start (*transport_vbox, false, false); @@ -410,21 +419,33 @@ ARDOUR_UI::setup_transport () auto_box->set_homogeneous (true); auto_box->set_spacing (2); auto_box->pack_start (sync_button, false, false); - auto_box->pack_start (follow_edits_button, false, false); - auto_box->pack_start (auto_return_button, false, false); + if (!ARDOUR::Profile->get_trx()) { + auto_box->pack_start (follow_edits_button, false, false); + auto_box->pack_start (auto_return_button, false, false); + } - transport_tearoff_hbox.pack_start (*auto_box, false, false); + if (!ARDOUR::Profile->get_trx()) { + transport_tearoff_hbox.pack_start (*auto_box, false, false); + } transport_tearoff_hbox.pack_start (*clock_box, true, true); - time_info_box = manage (new TimeInfoBox); - transport_tearoff_hbox.pack_start (*time_info_box, false, false); + if (ARDOUR::Profile->get_trx()) { + transport_tearoff_hbox.pack_start (*auto_box, false, false); + } - if (Profile->get_small_screen()) { + if (!ARDOUR::Profile->get_trx()) { + transport_tearoff_hbox.pack_start (*time_info_box, false, false); + } + + if (ARDOUR::Profile->get_small_screen()) { transport_tearoff_hbox.pack_start (_editor_transport_box, false, false); } - transport_tearoff_hbox.pack_start (alert_box, false, false); - transport_tearoff_hbox.pack_start (meter_box, false, false); - transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false); + + if (!ARDOUR::Profile->get_trx()) { + transport_tearoff_hbox.pack_start (alert_box, false, false); + transport_tearoff_hbox.pack_start (meter_box, false, false); + transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false); + } if (Profile->get_sae()) { Image* img = manage (new Image ((::get_icon (X_("sae"))))); diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc index 2cfa27cbb2..35dbe3cfc9 100644 --- a/gtk2_ardour/ardour_ui_dialogs.cc +++ b/gtk2_ardour/ardour_ui_dialogs.cc @@ -23,9 +23,10 @@ This is to cut down on the compile times. It also helps with my sanity. */ -#include "ardour/session.h" #include "ardour/audioengine.h" #include "ardour/automation_watch.h" +#include "ardour/profile.h" +#include "ardour/session.h" #ifdef interface #undef interface @@ -210,13 +211,15 @@ ARDOUR_UI::set_session (Session *s) _session->master_out() && _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) { - editor_meter = new LevelMeterHBox(_session); - editor_meter->set_meter (_session->master_out()->shared_peak_meter().get()); - editor_meter->clear_meters(); - editor_meter->set_type (_session->master_out()->meter_type()); - editor_meter->setup_meters (30, 12, 6); - editor_meter->show(); - meter_box.pack_start(*editor_meter); + if (!ARDOUR::Profile->get_trx()) { + editor_meter = new LevelMeterHBox(_session); + editor_meter->set_meter (_session->master_out()->shared_peak_meter().get()); + editor_meter->clear_meters(); + editor_meter->set_type (_session->master_out()->meter_type()); + editor_meter->setup_meters (30, 12, 6); + editor_meter->show(); + meter_box.pack_start(*editor_meter); + } ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display)); ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display)); @@ -231,7 +234,7 @@ ARDOUR_UI::set_session (Session *s) editor_meter_max_peak = -INFINITY; editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false); - if (Config->get_show_editor_meter()) { + if (Config->get_show_editor_meter() && !ARDOUR::Profile->get_trx()) { transport_tearoff_hbox.pack_start (meter_box, false, false); transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false); meter_box.show(); @@ -574,3 +577,18 @@ ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev) } return true; } + +void +ARDOUR_UI::toggle_mixer_space() +{ + Glib::RefPtr act = ActionManager::get_action ("Common", "ToggleMaximalMixer"); + + if (act) { + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + if (tact->get_active()) { + mixer->maximise_mixer_space (); + } else { + mixer->restore_mixer_space (); + } + } +} diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index 9aaca19f35..784ca3943b 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -191,6 +191,7 @@ ARDOUR_UI::install_actions () /* windows visibility actions */ ActionManager::register_toggle_action (common_actions, X_("ToggleMaximalEditor"), _("Maximise Editor Space"), sigc::mem_fun (*this, &ARDOUR_UI::toggle_editing_space)); + ActionManager::register_toggle_action (common_actions, X_("ToggleMaximalMixer"), _("Maximise Mixer Space"), sigc::mem_fun (*this, &ARDOUR_UI::toggle_mixer_space)); act = ActionManager::register_toggle_action (common_actions, X_("KeepTearoffs"), _("Show Toolbars"), mem_fun (*this, &ARDOUR_UI::toggle_keep_tearoffs)); ActionManager::session_sensitive_actions.push_back (act); diff --git a/gtk2_ardour/bundle_env_msvc.cc b/gtk2_ardour/bundle_env_msvc.cc new file mode 100644 index 0000000000..bde3ed050a --- /dev/null +++ b/gtk2_ardour/bundle_env_msvc.cc @@ -0,0 +1,497 @@ +/* + Copyright (C) 2014 John Emmas + + 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 "bundle_env.h" +#include "i18n.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "ardour/ardour.h" +#include "ardour/search_paths.h" +#include "ardour/filesystem_paths.h" + +#include "pbd/file_utils.h" +#include "pbd/epa.h" + +using namespace std; +using namespace PBD; +using namespace ARDOUR; + +std::string +get_windows_drive_volume_letter() +{ +static std::string ret; +char path[PATH_MAX+1]; +LPITEMIDLIST pidl = 0; + + if (!ret.length()) { + if (S_OK == SHGetSpecialFolderLocation (0, CSIDL_WINDOWS, &pidl)) + { + if (SHGetPathFromIDListA (pidl, path)) { + path[2] = '\0'; // Gives us just the drive letter and colon + ret = path; + } + + CoTaskMemFree (pidl); + } + // The above should never fail - but just in case... + else if (char *env_path = getenv ("windir")) + { + strcpy (path, env_path); + path[2] = '\0'; // Gives us just the drive letter and colon + ret = path; + } + } + + return ret; +} + +const string +get_module_folder () +{ +std::string ret; + + // Gives the top-level Ardour installation folder (on Windows) + // Typically, this will be somehwere like "C:\Program Files" + + gchar* pExeRoot = g_win32_get_package_installation_directory_of_module (0); + + if (0 == pExeRoot) { + pExeRoot = g_build_filename("C:\\", "Program Files", PROGRAM_NAME, 0); + } + + if (pExeRoot) { + gchar tmp[PATH_MAX+1]; + gchar* p; + + strcpy(tmp, pExeRoot); + if (0 != (p = strrchr (tmp, G_DIR_SEPARATOR))) { + *p = '\0'; + + if (0 != (p = g_build_filename(tmp, 0))) { + ret = p; + g_free (p); + } + } + + g_free (pExeRoot); + } + + return (ret); +} + +bool +fixup_config_file (Glib::ustring str_file_to_fix) +{ +FILE* fd; +char buf[4096]; +bool conversion_needed = false; +bool succeeded = false; + + fstream file_to_fix (fd = g_fopen(str_file_to_fix.c_str(), "r+b")); + + if (file_to_fix.is_open()) { + vector lines; + std::string line; + + file_to_fix.seekg (0, std::ios::beg); + file_to_fix.seekp (0, std::ios::beg); + + try { + while (!file_to_fix.eof() && file_to_fix.getline (buf, sizeof(buf))) { + line = buf; + + if (!conversion_needed && (std::string::npos != line.find("$("))) + conversion_needed = true; + lines.push_back(line); + } + + if (conversion_needed) { + bool error = false; + std::string::size_type token_begin, token_end; + vector::iterator i; + + for (i = lines.begin(); i != lines.end(); ++i) { + if (string::npos != (token_begin = i->find("$("))) { + if (string::npos != (token_end = i->find(")", token_begin))) { + std::string str_replace_with; + std::string str_to_replace = i->substr(token_begin, ((token_end+1)-token_begin)); + + if (0 == str_to_replace.compare("$(CWD)")) { + // Replace our token with the current working directory + if (getcwd(buf, sizeof(buf))) { + if (buf[strlen(buf)-1] == G_DIR_SEPARATOR) + buf[strlen(buf)-1] = '\0'; + str_replace_with = buf; + + // Replace the first occurrence of our token with the required string + i->erase(token_begin, ((token_end+1)-token_begin)); + i->insert(token_begin, str_replace_with); + } else { + error = true; + } + } else if (0 == str_to_replace.compare("$(WINDRIVE)")){ + // Replace our token with the drive letter (and colon) for the user's Windows volume + str_replace_with = get_windows_drive_volume_letter(); + + // Replace the first occurrence of our token with the required string + i->erase(token_begin, ((token_end+1)-token_begin)); + i->insert(token_begin, str_replace_with); + } else { + // Assume that our token represents an environment variable + std::string envvar_name = str_to_replace.substr(2, str_to_replace.length()-3); + + if (const char *envvar_value = getenv(envvar_name.c_str())) { + strcpy(buf, envvar_value); + if (buf[strlen(buf)-1] == G_DIR_SEPARATOR) + buf[strlen(buf)-1] = '\0'; + str_replace_with = buf; + + // Replace the first occurrence of our token with the required string + i->erase(token_begin, ((token_end+1)-token_begin)); + i->insert(token_begin, str_replace_with); + } else { + error = true; + cerr << _("ERROR: unknown environment variable") << endl; + } + } + } + } + } + + if (!error) { + file_to_fix.clear (); // Clear the EOF flag etc + file_to_fix.seekg (0, std::ios::beg); // Seek our 'get' ptr to the file start pos + // (our 'put' ptr shouldn't have moved yet). + chsize(fileno (fd), 0); // Truncate the file, ready for re-writing + + for (i = lines.begin(); i != lines.end(); ++i) { + + // Write the converted contents to our file + file_to_fix << (*i).c_str() << endl; + } + + try { + file_to_fix.close(); + succeeded = true; + } catch (...) {} + } + } else { + file_to_fix.close(); + succeeded = true; + } + } catch (...) { + file_to_fix.close(); + succeeded = false; + } + } else { + cerr << _("ERROR: Could not open config file '") << str_file_to_fix << "'" << endl; + } + + return succeeded; +} + +void +fixup_fonts_config () +{ +string fonts_conf_file; + +#ifdef DEBUG + fonts_conf_file = get_module_folder(); + + if (!fonts_conf_file.empty()) { + fonts_conf_file += "\\"; + fonts_conf_file += PROGRAM_NAME; + fonts_conf_file += FONTS_CONF_LOCATION; +#else + if (PBD::find_file_in_search_path (ARDOUR::ardour_config_search_path(), "fonts.conf", fonts_conf_file)) { +#endif + Glib::setenv ("FONTCONFIG_FILE", fonts_conf_file, true); + + if (0 == fixup_config_file (fonts_conf_file)) + cerr << _("ERROR: processing error for 'fonts.conf' file") << endl; + } else { + cerr << _("ERROR: Malformed module folder (fonts.conf)") << endl; + } +} + +void +fixup_pango_config () +{ +string pango_modules_file; + +#if defined(DEBUG) || defined(RDC_BUILD) + // Make sure we pick up the debuggable DLLs !!! + pango_modules_file = get_module_folder(); + + if (!pango_modules_file.empty()) { + pango_modules_file += "\\"; + pango_modules_file += PROGRAM_NAME; + pango_modules_file += PANGO_CONF_LOCATION; +#if 0 +// JE - handy for non-English locale testing (Greek, in this case) + Glib::ustring pango_modules_path = Glib::locale_to_utf8("C:\\Program Files\\Mixbus3\\etc\\ΔΗΜΗΤΡΗΣ\\pango.modules"); +/**/ +#else + Glib::ustring pango_modules_path = pango_modules_file; +#endif + pango_modules_path.resize (pango_modules_path.size()-14); // Remove "/pango.modules" from the end +#else + if (PBD::find_file_in_search_path (ARDOUR::ardour_config_search_path(), "pango.modules", pango_modules_file)) { + + Glib::ustring pango_modules_path = pango_modules_file; + pango_modules_path.resize (pango_modules_path.size()-14); // Remove "/pango.modules" from the end +#endif + // Set an environment variable so we can find our pango modules. Note + // that this requires a modified version of libpango (pango-utils.c) + Glib::setenv ("PANGO_MODULE_PATH", Glib::filename_from_utf8(pango_modules_path), true); + + if (0 == fixup_config_file (pango_modules_file)) + cerr << _("ERROR: processing error for 'pango.modules' file") << endl; + } else { + cerr << _("ERROR: Malformed module folder (pango.modules)") << endl; + } +} + +void +fixup_pixbuf_loaders_config () +{ +string gdk_pixbuf_loaders_file; + +#if defined(DEBUG) || defined(RDC_BUILD) + // Make sure we pick up the debuggable DLLs !!! + gdk_pixbuf_loaders_file = get_module_folder(); + + if (!gdk_pixbuf_loaders_file.empty()) { + gdk_pixbuf_loaders_file += "\\"; + gdk_pixbuf_loaders_file += PROGRAM_NAME; + gdk_pixbuf_loaders_file += PIXBUFLOADERS_CONF_LOCATION; +#else + if (PBD::find_file_in_search_path (ARDOUR::ardour_config_search_path(), "gdk-pixbuf.loaders", gdk_pixbuf_loaders_file)) { +#endif + // Set an environment variable so we can find our pixbuf modules. + Glib::setenv ("GDK_PIXBUF_MODULE_FILE", Glib::filename_from_utf8(gdk_pixbuf_loaders_file), true); + + if (0 == fixup_config_file (gdk_pixbuf_loaders_file)) + cerr << _("ERROR: processing error for 'gdk-pixbuf.loaders' file") << endl; + } else { + cerr << _("ERROR: Malformed module folder (gdk-pixbuf.loaders)") << endl; + } +} + +void +fixup_clearlooks_config () +{ +string clearlooks_la_file; + +#if defined(DEBUG) || defined(RDC_BUILD) + // Make sure we pick up the debuggable DLLs !!! + clearlooks_la_file = get_module_folder(); + + if (!clearlooks_la_file.empty()) { + clearlooks_la_file += "\\"; + clearlooks_la_file += PROGRAM_NAME; + clearlooks_la_file += CLEARLOOKS_CONF_LOCATION; +#else + if (PBD::find_file_in_search_path (ARDOUR::ardour_config_search_path(), "libclearlooks.la", clearlooks_la_file)) { +#endif + // Set an environment variable so we can find our clearlooks engine. + // Note that this requires a modified version of libgtk (gtkthemes.c) + Glib::setenv ("GTK_THEME_ENGINE_FILE", Glib::filename_from_utf8(clearlooks_la_file).c_str(), true); + + if (0 == fixup_config_file (clearlooks_la_file)) + cerr << _("ERROR: processing error for 'clearlooks.la' file") << endl; + } else { + cerr << _("ERROR: Malformed module folder (clearlooks.la)") << endl; + } +} + +void +fixup_bundle_environment (int argc, char* argv[], const char** localedir) +{ + std::string exec_path = argv[0]; + std::string dir_path = Glib::path_get_dirname (exec_path); + + // Make sure that our runtime CWD is set to Mixbus's install + // folder, regardless of where the caller's CWD was set to. + g_chdir (dir_path.c_str()); + + EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true)); + + // Now set 'dir_path' so we can append some relative paths + dir_path = Glib::path_get_dirname (dir_path); + + std::string path; + const char *cstr; + + // First, set up 'ARDOUR_DLL_PATH' + path = dir_path; + path += "\\lib\\ardour3\\surfaces;"; + path += dir_path; + path += "\\lib\\ardour3\\panners;"; + path += dir_path; + path += "\\lib\\ardour3\\backends;"; + path += dir_path; + path += "\\bin"; + Glib::setenv ("ARDOUR_DLL_PATH", path, true); + + + // Next, set up 'ARDOUR_DATA_PATH' + path = get_module_folder() + "\\"; + path += PROGRAM_NAME; + path += "\\share"; + Glib::setenv ("ARDOUR_DATA_PATH", path, true); + + + // Next, set up 'ARDOUR_CONFIG_PATH' +#ifdef _WIN64 + path = user_config_directory() + "\\win64;"; +#else + path = user_config_directory() + "\\win32;"; +#endif + Glib::setenv ("ARDOUR_CONFIG_PATH", path, true); + + + // Next, set up 'ARDOUR_PATH' + path = user_config_directory(); + path = Glib::path_get_dirname (path); + path += G_SEARCHPATH_SEPARATOR; + path += windows_search_path().to_string(); + path += "\\icons;"; + path += windows_search_path().to_string(); + path += "\\pixmaps;"; + path += ardour_data_search_path().to_string(); // In fact, adds both the 'data' search + path += G_SEARCHPATH_SEPARATOR; // path and our 'config' search path + path += dir_path; + path += "\\etc"; + Glib::setenv ("ARDOUR_PATH", path, true); + + + // Next, set up 'ARDOUR_INSTANT_XML_PATH' + path = user_config_directory(); + Glib::setenv ("ARDOUR_INSTANT_XML_PATH", path, true); + + + // Next, set up 'LADSPA_PATH' + path = ladspa_search_path().to_string(); + Glib::setenv ("LADSPA_PATH", path, true); + + + // Next, set up 'VAMP_PATH' + cstr = getenv ("VAMP_PATH"); + if (cstr) { + path = cstr; + path += G_SEARCHPATH_SEPARATOR; + } else { + path = ""; + } + path += get_module_folder() + "\\"; + path += PROGRAM_NAME; + path += "\\bin\\vamp"; + path += G_SEARCHPATH_SEPARATOR; + path += "%ProgramFiles%\\Vamp Plugins"; + Glib::setenv ("VAMP_PATH", path, true); + + + // Next, set up 'ARDOUR_CONTROL_SURFACE_PATH' + cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH"); + if (cstr) { + path = cstr; + path += G_SEARCHPATH_SEPARATOR; + } else { + path = ""; + } + path += control_protocol_search_path().to_string(); + Glib::setenv ("ARDOUR_CONTROL_SURFACE_PATH", path, true); + + + // Next, set up 'GTK_LOCALEDIR' + if (ARDOUR::translations_are_enabled ()) { + path = windows_search_path().to_string(); + path += "\\locale"; + Glib::setenv ("GTK_LOCALEDIR", path, true); + + // and return the same path to our caller + (*localedir) = strdup (path.c_str()); + } + + + // Next, set up 'GTK_PATH' + cstr = getenv ("GTK_PATH"); + if (cstr) { + path = cstr; + path += G_SEARCHPATH_SEPARATOR; + } else { + path = ""; + } + path += user_config_directory(); + path += "\\.gtk-2.0"; + Glib::setenv ("GTK_PATH", path, true); + + + // Unset GTK_RC_FILES so that we only load the RC files that we define + Glib::unsetenv ("GTK_RC_FILES"); + + + // and set a '$HOME' environment variable. This variable changes the value returned + // by 'g_get_home_dir()' so to prevent that function from unexpectedly changing its + // mind, we'll set '$HOME' to whatever 'g_get_home_dir()' is already returning!! + if (NULL == getenv("HOME")) { + Glib::setenv ("HOME", Glib::locale_from_utf8(g_get_home_dir()), true); + } + + fixup_fonts_config(); + fixup_pango_config(); + fixup_clearlooks_config(); + fixup_pixbuf_loaders_config(); +} + + +void load_custom_fonts() +{ + std::string ardour_mono_file; + + if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) { + cerr << _("Cannot find ArdourMono TrueType font") << endl; + } + + FcConfig *config = FcInitLoadConfigAndFonts(); + FcBool ret = FcConfigAppFontAddFile(config, reinterpret_cast(ardour_mono_file.c_str())); + + if (ret == FcFalse) { + cerr << _("Cannot load ArdourMono TrueType font.") << endl; + } + + ret = FcConfigSetCurrent(config); + + if (ret == FcFalse) { + cerr << _("Failed to set fontconfig configuration.") << endl; + } +} diff --git a/gtk2_ardour/editor.bindings b/gtk2_ardour/editor.bindings index 0e63a91780..afef5d8da6 100644 --- a/gtk2_ardour/editor.bindings +++ b/gtk2_ardour/editor.bindings @@ -167,6 +167,7 @@ + diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 6ee72a884e..88f69ff68e 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -259,10 +259,11 @@ Editor::Editor () /* tool bar related */ , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true)) - , toolbar_selection_clock_table (2,3) - + , _mouse_mode_tearoff (0) , automation_mode_button (_("mode")) + , _zoom_tearoff (0) + , _tools_tearoff (0) , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10))) @@ -309,14 +310,19 @@ Editor::Editor () rb_current_opt = 4; #endif + build_edit_mode_menu(); + build_zoom_focus_menu(); + build_track_count_menu(); + build_snap_mode_menu(); + build_snap_type_menu(); + build_edit_point_menu(); + snap_threshold = 5.0; bbt_beat_subdivision = 4; _visible_canvas_width = 0; _visible_canvas_height = 0; - last_autoscroll_x = 0; - last_autoscroll_y = 0; - autoscroll_active = false; - autoscroll_timeout_tag = -1; + autoscroll_horizontal_allowed = false; + autoscroll_vertical_allowed = false; logo_item = 0; analysis_window = 0; @@ -374,6 +380,7 @@ Editor::Editor () _edit_point = EditAtMouse; _internal_editing = false; current_canvas_cursor = 0; + _visible_track_count = 16; samples_per_pixel = 2048; /* too early to use reset_zoom () */ @@ -475,7 +482,9 @@ Editor::Editor () HBox* h = manage (new HBox); _group_tabs = new EditorGroupTabs (this); - h->pack_start (*_group_tabs, PACK_SHRINK); + if (!ARDOUR::Profile->get_trx()) { + h->pack_start (*_group_tabs, PACK_SHRINK); + } h->pack_start (edit_controls_vbox); controls_layout.add (*h); @@ -594,10 +603,14 @@ Editor::Editor () _summary_hbox.pack_start (*summary_frame, true, true); _summary_hbox.pack_start (*summary_arrows_right, false, false); - editor_summary_pane.pack2 (_summary_hbox); + if (!ARDOUR::Profile->get_trx()) { + editor_summary_pane.pack2 (_summary_hbox); + } edit_pane.pack1 (editor_summary_pane, true, true); - edit_pane.pack2 (_the_notebook, false, true); + if (!ARDOUR::Profile->get_trx()) { + edit_pane.pack2 (_the_notebook, false, true); + } editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast (&editor_summary_pane))); @@ -637,6 +650,7 @@ Editor::Editor () setup_toolbar (); set_zoom_focus (zoom_focus); + set_visible_track_count (_visible_track_count); _snap_type = SnapToBeat; set_snap_to (_snap_type); _snap_mode = SnapOff; @@ -656,12 +670,12 @@ Editor::Editor () /* nudge stuff */ - nudge_forward_button.set_name ("zoom button"); - nudge_forward_button.add_elements (ArdourButton::FlatFace); + nudge_forward_button.set_name ("nudge button"); + nudge_forward_button.add_elements (ArdourButton::Inset); nudge_forward_button.set_image(::get_icon("nudge_right")); - nudge_backward_button.set_name ("zoom button"); - nudge_backward_button.add_elements (ArdourButton::FlatFace); + nudge_backward_button.set_name ("nudge button"); + nudge_backward_button.add_elements (ArdourButton::Inset); nudge_backward_button.set_image(::get_icon("nudge_left")); fade_context_menu.set_name ("ArdourContextMenu"); @@ -2255,6 +2269,10 @@ Editor::set_state (const XMLNode& node, int /*version*/) reset_zoom (samples_per_pixel); } + if ((prop = node.property ("visible-track-count"))) { + set_visible_track_count (PBD::atoi (prop->value())); + } + if ((prop = node.property ("snap-to"))) { set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type)); } @@ -2482,6 +2500,8 @@ Editor::get_state () node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type)); node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode)); node->add_property ("edit-point", enum_2_string (_edit_point)); + snprintf (buf, sizeof(buf), "%d", _visible_track_count); + node->add_property ("visible-track-count", buf); snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ()); node->add_property ("playhead", buf); @@ -2851,15 +2871,21 @@ Editor::setup_toolbar () mouse_mode_hbox->set_spacing (2); - mouse_mode_hbox->pack_start (smart_mode_button, false, false); + if (!ARDOUR::Profile->get_trx()) { + mouse_mode_hbox->pack_start (smart_mode_button, false, false); + } + mouse_mode_hbox->pack_start (mouse_move_button, false, false); mouse_mode_hbox->pack_start (mouse_select_button, false, false); mouse_mode_hbox->pack_start (mouse_zoom_button, false, false); - mouse_mode_hbox->pack_start (mouse_gain_button, false, false); - mouse_mode_hbox->pack_start (mouse_timefx_button, false, false); - mouse_mode_hbox->pack_start (mouse_audition_button, false, false); - mouse_mode_hbox->pack_start (mouse_draw_button, false, false); - mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8); + + if (!ARDOUR::Profile->get_trx()) { + mouse_mode_hbox->pack_start (mouse_gain_button, false, false); + mouse_mode_hbox->pack_start (mouse_timefx_button, false, false); + mouse_mode_hbox->pack_start (mouse_audition_button, false, false); + mouse_mode_hbox->pack_start (mouse_draw_button, false, false); + mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8); + } mouse_mode_vbox->pack_start (*mouse_mode_hbox); @@ -2878,7 +2904,9 @@ Editor::setup_toolbar () set_popdown_strings (edit_mode_selector, edit_mode_strings); edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done)); - mode_box->pack_start (edit_mode_selector, false, false); + if (!ARDOUR::Profile->get_trx()) { + mode_box->pack_start (edit_mode_selector, false, false); + } mode_box->pack_start (*mouse_mode_box, false, false); _mouse_mode_tearoff = manage (new TearOff (*mode_box)); @@ -2906,21 +2934,21 @@ Editor::setup_toolbar () RefPtr act; zoom_in_button.set_name ("zoom button"); - zoom_in_button.add_elements ( ArdourButton::FlatFace ); + zoom_in_button.add_elements ( ArdourButton::Inset ); zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); zoom_in_button.set_image(::get_icon ("zoom_in")); act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in")); zoom_in_button.set_related_action (act); zoom_out_button.set_name ("zoom button"); - zoom_out_button.add_elements ( ArdourButton::FlatFace ); + zoom_out_button.add_elements ( ArdourButton::Inset ); zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); zoom_out_button.set_image(::get_icon ("zoom_out")); act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out")); zoom_out_button.set_related_action (act); zoom_out_full_button.set_name ("zoom button"); - zoom_out_full_button.add_elements ( ArdourButton::FlatFace ); + zoom_out_full_button.add_elements ( ArdourButton::Inset ); zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); zoom_out_full_button.set_image(::get_icon ("zoom_full")); act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session")); @@ -2930,15 +2958,23 @@ Editor::setup_toolbar () set_popdown_strings (zoom_focus_selector, zoom_focus_strings); zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done)); - _zoom_box.pack_start (zoom_out_button, false, false); - _zoom_box.pack_start (zoom_in_button, false, false); - _zoom_box.pack_start (zoom_out_full_button, false, false); - - _zoom_box.pack_start (zoom_focus_selector, false, false); + if (!ARDOUR::Profile->get_trx()) { + _zoom_box.pack_start (zoom_out_button, false, false); + _zoom_box.pack_start (zoom_in_button, false, false); + _zoom_box.pack_start (zoom_out_full_button, false, false); + _zoom_box.pack_start (zoom_focus_selector, false, false); + } else { + mode_box->pack_start (zoom_out_button, false, false); + mode_box->pack_start (zoom_in_button, false, false); + } /* Track zoom buttons */ + visible_tracks_selector.set_name ("zoom button"); +// visible_tracks_selector.add_elements ( ArdourButton::Inset ); + set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2); + tav_expand_button.set_name ("zoom button"); - tav_expand_button.add_elements ( ArdourButton::FlatFace ); +// tav_expand_button.add_elements ( ArdourButton::Inset ); tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); tav_expand_button.set_size_request (-1, 20); tav_expand_button.set_image(::get_icon ("tav_exp")); @@ -2946,26 +2982,31 @@ Editor::setup_toolbar () tav_expand_button.set_related_action (act); tav_shrink_button.set_name ("zoom button"); - tav_shrink_button.add_elements ( ArdourButton::FlatFace ); +// tav_shrink_button.add_elements ( ArdourButton::Inset ); tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) ); tav_shrink_button.set_size_request (-1, 20); tav_shrink_button.set_image(::get_icon ("tav_shrink")); act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks")); tav_shrink_button.set_related_action (act); + if (!ARDOUR::Profile->get_trx()) { + _zoom_box.pack_start (visible_tracks_selector); + } _zoom_box.pack_start (tav_shrink_button); _zoom_box.pack_start (tav_expand_button); - _zoom_tearoff = manage (new TearOff (_zoom_box)); - - _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), - &_zoom_tearoff->tearoff_window())); - _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), - &_zoom_tearoff->tearoff_window(), 0)); - _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), - &_zoom_tearoff->tearoff_window())); - _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), - &_zoom_tearoff->tearoff_window(), 0)); + if (!ARDOUR::Profile->get_trx()) { + _zoom_tearoff = manage (new TearOff (_zoom_box)); + + _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_zoom_tearoff->tearoff_window())); + _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_zoom_tearoff->tearoff_window(), 0)); + _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), + &_zoom_tearoff->tearoff_window())); + _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), + &_zoom_tearoff->tearoff_window(), 0)); + } snap_box.set_spacing (2); snap_box.set_border_width (2); @@ -3029,15 +3070,19 @@ Editor::setup_toolbar () toolbar_hbox.set_border_width (1); toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false); - toolbar_hbox.pack_start (*_zoom_tearoff, false, false); - toolbar_hbox.pack_start (*_tools_tearoff, false, false); + if (!ARDOUR::Profile->get_trx()) { + toolbar_hbox.pack_start (*_zoom_tearoff, false, false); + toolbar_hbox.pack_start (*_tools_tearoff, false, false); + } - hbox->pack_start (snap_box, false, false); - if (!Profile->get_small_screen()) { - hbox->pack_start (*nudge_box, false, false); - } else { - ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false); - } + if (!ARDOUR::Profile->get_trx()) { + hbox->pack_start (snap_box, false, false); + if (!Profile->get_small_screen()) { + hbox->pack_start (*nudge_box, false, false); + } else { + ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false); + } + } hbox->pack_start (panic_box, false, false); hbox->show_all (); @@ -3054,6 +3099,81 @@ Editor::setup_toolbar () toolbar_frame.add (_toolbar_viewport); } +void +Editor::build_edit_point_menu () +{ +#if 0 + using namespace Menu_Helpers; + + edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead))); + edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker))); + edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse))); +#endif +} + +void +Editor::build_edit_mode_menu () +{ +#if 0 + using namespace Menu_Helpers; + + edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide))); + edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice))); + edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock))); +#endif +} + +void +Editor::build_snap_mode_menu () +{ +#if 0 + using namespace Menu_Helpers; + + snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff))); + snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal))); + snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic))); +#endif +} + +void +Editor::build_snap_type_menu () +{ +#if 0 + using namespace Menu_Helpers; + + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync))); + snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary))); +#endif +} + void Editor::setup_tooltips () { @@ -3075,6 +3195,7 @@ Editor::setup_tooltips () ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus")); ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks")); ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks")); + ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks")); ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units")); ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode")); ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point")); @@ -3472,6 +3593,21 @@ Editor::edit_point_selection_done () } } +void +Editor::build_zoom_focus_menu () +{ +#if 0 + using namespace Menu_Helpers; + + zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft))); + zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight))); + zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter))); + zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead))); + zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse))); + zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit))); +#endif +} + void Editor::zoom_focus_selection_done () { @@ -3499,6 +3635,76 @@ Editor::zoom_focus_selection_done () } } +void +Editor::build_track_count_menu () +{ +#if 0 + using namespace Menu_Helpers; + + visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32))); + visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64))); + visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0))); +#endif +} + +void +Editor::set_visible_track_count (int32_t n) +{ + _visible_track_count = n; + + /* if the canvas hasn't really been allocated any size yet, just + record the desired number of visible tracks and return. when canvas + allocation happens, we will get called again and then we can do the + real work. + */ + + if (_visible_canvas_height <= 1) { + return; + } + + int h; + string str; + + if (_visible_track_count > 0) { + h = _visible_canvas_height / _visible_track_count; + std::ostringstream s; + s << _visible_track_count; + str = s.str(); + } else if (_visible_track_count == 0) { + h = _visible_canvas_height / track_views.size(); + str = _("all"); + } else { + /* negative value means that the visible track count has + been overridden by explicit track height changes. + */ + visible_tracks_selector.set_active_text (X_("*")); + return; + } + + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + (*i)->set_height (h); + } + + if (str != visible_tracks_selector.get_active_text()) { + visible_tracks_selector.set_active_text (str); + } +} + +void +Editor::override_visible_track_count () +{ + _visible_track_count = -_visible_track_count; +} + bool Editor::edit_controls_button_release (GdkEventButton* ev) { @@ -3642,7 +3848,7 @@ Editor::detach_tearoff (Box* /*b*/, Window* /*w*/) { if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && - (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) { + (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) { top_hbox.remove (toolbar_frame); } } @@ -3952,7 +4158,9 @@ Editor::update_tearoff_visibility() bool visible = Config->get_keep_tearoffs(); _mouse_mode_tearoff->set_visible (visible); _tools_tearoff->set_visible (visible); - _zoom_tearoff->set_visible (visible); + if (_zoom_tearoff) { + _zoom_tearoff->set_visible (visible); + } } void @@ -4291,35 +4499,45 @@ Editor::idle_visual_changer () pending_visual_change.idle_handler_id = -1; pending_visual_change.being_handled = true; - VisualChange::Type p = pending_visual_change.pending; + VisualChange vc = pending_visual_change; + pending_visual_change.pending = (VisualChange::Type) 0; + visual_changer (vc); + + pending_visual_change.being_handled = false; + + return 0; /* this is always a one-shot call */ +} + +void +Editor::visual_changer (const VisualChange& vc) +{ double const last_time_origin = horizontal_position (); - - if (p & VisualChange::ZoomLevel) { - set_samples_per_pixel (pending_visual_change.samples_per_pixel); + if (vc.pending & VisualChange::ZoomLevel) { + set_samples_per_pixel (vc.samples_per_pixel); compute_fixed_ruler_scale (); ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin; ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end; - compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(), + compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(), current_bbt_points_begin, current_bbt_points_end); - compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(), + compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(), current_bbt_points_begin, current_bbt_points_end); update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end); update_video_timeline(); } - if (p & VisualChange::TimeOrigin) { - set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel); + if (vc.pending & VisualChange::TimeOrigin) { + set_horizontal_position (vc.time_origin / samples_per_pixel); } - if (p & VisualChange::YOrigin) { - vertical_adjustment.set_value (pending_visual_change.y_origin); + if (vc.pending & VisualChange::YOrigin) { + vertical_adjustment.set_value (vc.y_origin); } if (last_time_origin == horizontal_position ()) { @@ -4328,14 +4546,11 @@ Editor::idle_visual_changer () redisplay_tempo (true); } - if (!(p & VisualChange::ZoomLevel)) { + if (!(vc.pending & VisualChange::ZoomLevel)) { update_video_timeline(); } _summary->set_overlays_dirty (); - - pending_visual_change.being_handled = false; - return 0; /* this is always a one-shot call */ } struct EditorOrderTimeAxisSorter { diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index b1edb26737..7912050fc4 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -177,6 +177,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void set_internal_edit (bool yn); bool toggle_internal_editing_from_double_click (GdkEvent*); + void _ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top); void foreach_time_axis_view (sigc::slot); void add_to_idle_resize (TimeAxisView*, int32_t); @@ -207,7 +208,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD account any scrolling offsets. */ - framepos_t pixel_to_sample (double pixel) const { + framepos_t pixel_to_sample_from_event (double pixel) const { /* pixel can be less than zero when motion events are processed. since we've already run the world->canvas @@ -222,6 +223,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD } } + framepos_t pixel_to_sample (double pixel) const { + return pixel * samples_per_pixel; + } + double sample_to_pixel (framepos_t sample) const { return sample / samples_per_pixel; } @@ -345,9 +350,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void show_window (); - void ensure_time_axis_view_is_visible (const TimeAxisView& tav); void scroll_tracks_down_line (); void scroll_tracks_up_line (); + bool scroll_up_one_track (); + bool scroll_down_one_track (); void prepare_for_cleanup (); void finish_cleanup (); @@ -408,7 +414,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD return _drags; } - void maybe_autoscroll (bool, bool, bool, bool); + void maybe_autoscroll (bool, bool, bool); + bool autoscroll_active() const; Gdk::Cursor* get_canvas_cursor () const { return current_canvas_cursor; } void set_canvas_cursor (Gdk::Cursor*, bool save=false); @@ -442,6 +449,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD ArdourCanvas::GtkCanvasViewport* get_time_bars_canvas () const; ArdourCanvas::GtkCanvasViewport* get_track_canvas () const; + void override_visible_track_count (); protected: void map_transport_state (); @@ -728,6 +736,12 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD /* The group used for region motion. Sits on top of _trackview_group */ ArdourCanvas::Group* _region_motion_group; + /* a rect that sits at the bottom of all tracks to act as a drag-no-drop/clickable + * target area. + */ + ArdourCanvas::Rectangle* _canvas_bottom_rect; + bool canvas_bottom_rect_event (GdkEvent* event); + enum RulerType { ruler_metric_timecode = 0, ruler_metric_bbt = 1, @@ -1022,6 +1036,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD static int _idle_visual_changer (void *arg); int idle_visual_changer (); + void visual_changer (const VisualChange&); void ensure_visual_change_idle_handler (); /* track views */ @@ -1440,7 +1455,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Gtk::Allocation _canvas_viewport_allocation; void track_canvas_viewport_allocate (Gtk::Allocation alloc); - bool track_canvas_viewport_size_allocated (); + void track_canvas_viewport_size_allocated (); bool track_canvas_drag_motion (Glib::RefPtr const &, int, int, guint); bool track_canvas_key_press (GdkEventKey *); bool track_canvas_key_release (GdkEventKey *); @@ -1557,6 +1572,11 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD ArdourButton tav_expand_button; ArdourButton tav_shrink_button; + Gtk::ComboBoxText visible_tracks_selector; + + int32_t _visible_track_count; + void build_track_count_menu (); + void set_visible_track_count (int32_t); Gtk::VBox toolbar_clock_vbox; Gtk::VBox toolbar_selection_clock_vbox; @@ -1587,7 +1607,9 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Gtk::VBox automation_box; Gtk::Button automation_mode_button; - Gtk::ComboBoxText edit_mode_selector; + //edit mode menu stuff + Gtk::ComboBoxText edit_mode_selector; + void build_edit_mode_menu (); Gtk::VBox edit_mode_box; std::vector edit_mode_strings; @@ -1596,7 +1618,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void edit_mode_selection_done (); Gtk::ComboBoxText snap_type_selector; + void build_snap_type_menu (); + Gtk::ComboBoxText snap_mode_selector; + void build_snap_mode_menu (); Gtk::HBox snap_box; std::vector snap_type_strings; @@ -1612,7 +1637,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Gtk::ComboBoxText zoom_focus_selector; Gtk::VBox zoom_focus_box; - + void build_zoom_focus_menu (); std::vector zoom_focus_strings; void zoom_focus_selection_done (); @@ -1722,22 +1747,15 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD /* autoscrolling */ - bool autoscroll_active; - int autoscroll_timeout_tag; - int autoscroll_x; - int autoscroll_y; - int last_autoscroll_x; - int last_autoscroll_y; - uint32_t autoscroll_cnt; - framecnt_t autoscroll_x_distance; - double autoscroll_y_distance; + sigc::connection autoscroll_connection; + bool autoscroll_horizontal_allowed; + bool autoscroll_vertical_allowed; + uint32_t autoscroll_cnt; + Gtk::Widget* autoscroll_widget; + ArdourCanvas::Rect autoscroll_boundary; - bool _autoscroll_fudging; - int autoscroll_fudge_threshold () const; - - static gint _autoscroll_canvas (void *); bool autoscroll_canvas (); - void start_canvas_autoscroll (int x, int y); + void start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary); void stop_canvas_autoscroll (); /* trimming */ @@ -1945,6 +1963,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Editing::EditPoint _edit_point; Gtk::ComboBoxText edit_point_selector; + void build_edit_point_menu(); void set_edit_point_preference (Editing::EditPoint ep, bool force = false); void cycle_edit_point (bool with_marker); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 423a9ad1a1..19d240eb1b 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -414,49 +414,49 @@ Editor::register_actions () smart_mode_action = Glib::RefPtr::cast_static (act); smart_mode_button.set_related_action (smart_mode_action); smart_mode_button.set_text (_("Smart")); - smart_mode_button.add_elements ( ArdourButton::FlatFace ); + smart_mode_button.add_elements ( ArdourButton::Inset ); smart_mode_button.set_name ("mouse mode button"); act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-object", _("Object Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject)); mouse_move_button.set_related_action (act); mouse_move_button.set_image (::get_icon("tool_object")); - mouse_move_button.add_elements ( ArdourButton::FlatFace ); + mouse_move_button.add_elements ( ArdourButton::Inset ); mouse_move_button.set_name ("mouse mode button"); act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-range", _("Range Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange)); mouse_select_button.set_related_action (act); mouse_select_button.set_image (::get_icon("tool_range")); - mouse_select_button.add_elements ( ArdourButton::FlatFace ); + mouse_select_button.add_elements ( ArdourButton::Inset ); mouse_select_button.set_name ("mouse mode button"); act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-draw", _("Note Drawing Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseDraw)); mouse_draw_button.set_related_action (act); mouse_draw_button.set_image (::get_icon("midi_tool_pencil")); - mouse_draw_button.add_elements ( ArdourButton::FlatFace ); + mouse_draw_button.add_elements ( ArdourButton::Inset ); mouse_draw_button.set_name ("mouse mode button"); act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-gain", _("Gain Tool"), sigc::bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain)); mouse_gain_button.set_related_action (act); mouse_gain_button.set_image (::get_icon("tool_gain")); - mouse_gain_button.add_elements ( ArdourButton::FlatFace ); + mouse_gain_button.add_elements ( ArdourButton::Inset ); mouse_gain_button.set_name ("mouse mode button"); act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-zoom", _("Zoom Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom)); mouse_zoom_button.set_related_action (act); mouse_zoom_button.set_image (::get_icon("tool_zoom")); - mouse_zoom_button.add_elements ( ArdourButton::FlatFace ); + mouse_zoom_button.add_elements ( ArdourButton::Inset ); mouse_zoom_button.set_name ("mouse mode button"); act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-audition", _("Audition Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition)); mouse_audition_button.set_related_action (act); mouse_audition_button.set_image (::get_icon("tool_audition")); - mouse_audition_button.add_elements ( ArdourButton::FlatFace ); + mouse_audition_button.add_elements ( ArdourButton::Inset ); mouse_audition_button.set_name ("mouse mode button"); act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-timefx", _("Time FX Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX)); mouse_timefx_button.set_related_action (act); mouse_timefx_button.set_image (::get_icon("tool_stretch")); - mouse_timefx_button.add_elements ( ArdourButton::FlatFace ); + mouse_timefx_button.add_elements ( ArdourButton::Inset ); mouse_timefx_button.set_name ("mouse mode button"); ActionManager::register_action (editor_actions, "step-mouse-mode", _("Step Mouse Mode"), sigc::bind (sigc::mem_fun(*this, &Editor::step_mouse_mode), true)); @@ -464,7 +464,7 @@ Editor::register_actions () act = ActionManager::register_toggle_action (mouse_mode_actions, "toggle-internal-edit", _("Edit MIDI"), sigc::mem_fun(*this, &Editor::toggle_internal_editing)); internal_edit_button.set_related_action (act); internal_edit_button.set_image (::get_icon("tool_note")); - internal_edit_button.add_elements ( ArdourButton::FlatFace ); + internal_edit_button.add_elements ( ArdourButton::Inset ); internal_edit_button.set_name ("mouse mode button"); RadioAction::Group edit_point_group; @@ -1650,7 +1650,9 @@ Editor::parameter_changed (std::string p) } else if (p == "timecode-offset" || p == "timecode-offset-negative") { update_just_timecode (); } else if (p == "show-zoom-tools") { - _zoom_tearoff->set_visible (Config->get_show_zoom_tools(), true); + if (_zoom_tearoff) { + _zoom_tearoff->set_visible (Config->get_show_zoom_tools(), true); + } } else if (p == "sound-midi-notes") { Glib::RefPtr act = ActionManager::get_action (X_("Editor"), X_("sound-midi-notes")); diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index 180f88bd88..3b9c5dea37 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -84,7 +84,7 @@ Editor::initialize_canvas () // logo_item->property_width_in_pixels() = true; // logo_item->property_height_set() = true; // logo_item->property_width_set() = true; - logo_item->show (); + // logo_item->show (); } /*a group to hold global rects like punch/loop indicators */ @@ -192,12 +192,10 @@ Editor::initialize_canvas () // used to show zoom mode active zooming zoom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0)); zoom_rect->hide(); - zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0)); // used as rubberband rect rubberband_rect = new ArdourCanvas::Rectangle (_trackview_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0)); - rubberband_rect->hide(); tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar)); @@ -213,7 +211,17 @@ Editor::initialize_canvas () if (logo_item) { logo_item->lower_to_bottom (); } - /* need to handle 4 specific types of events as catch-alls */ + + + _canvas_bottom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, max_canvas_coordinate, 20)); + /* this thing is transparent */ + _canvas_bottom_rect->set_fill (false); + _canvas_bottom_rect->set_outline (false); + _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event)); + + /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level + handlers. + */ _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event)); _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event)); @@ -257,7 +265,7 @@ Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc) track_canvas_viewport_size_allocated (); } -bool +void Editor::track_canvas_viewport_size_allocated () { bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height(); @@ -281,13 +289,13 @@ Editor::track_canvas_viewport_size_allocated () */ vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height); } + + set_visible_track_count (_visible_track_count); } update_fixed_rulers(); redisplay_tempo (false); _summary->set_overlays_dirty (); - - return false; } void @@ -315,12 +323,24 @@ Editor::reset_controls_layout_width () void Editor::reset_controls_layout_height (int32_t h) { + /* ensure that the rect that represents the "bottom" of the canvas + * (the drag-n-drop zone) is, in fact, at the bottom. + */ + + _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h)); + + /* track controls layout must span the full height of "h" (all tracks) + * plus the bottom rect. + */ + + h += _canvas_bottom_rect->height (); + /* set the height of the scrollable area (i.e. the sum of all contained widgets) + * for the controls layout. The size request is set elsewhere. */ controls_layout.property_height() = h; - /* size request is set elsewhere, see ::track_canvas_allocate() */ } bool @@ -448,245 +468,265 @@ Editor::drop_paths (const RefPtr& context, context->drag_finish (true, false, time); } -/** If the editor window is arranged such that the edge of the trackview is right up - * against the edge of the screen, autoscroll will not work very well. In this situation, - * we start autoscrolling some distance in from the right-hand-side of the screen edge; - * this is the distance at which that happens. - */ -int -Editor::autoscroll_fudge_threshold () const -{ - return current_page_samples() / 6; -} - /** @param allow_horiz true to allow horizontal autoscroll, otherwise false. * * @param allow_vert true to allow vertical autoscroll, otherwise false. * - * @param moving_left true if we are moving left, so we only want to autoscroll on the left of the canvas, - * otherwise false, so we only want to autoscroll on the right of the canvas. - * - * @param moving_up true if we are moving up, so we only want to autoscroll at the top of the canvas, - * otherwise false, so we only want to autoscroll at the bottom of the canvas. */ void -Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool moving_left, bool moving_up) +Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers) { if (!Config->get_autoscroll_editor ()) { return; } + + + ArdourCanvas::Rect scrolling_boundary; + Gtk::Allocation alloc; - bool startit = false; - - /* Work out the distance between the right hand edge of the trackview and the edge of - the monitor that it is on. - */ - - Glib::RefPtr gdk_window = get_window (); - Gdk::Rectangle window_rect; - gdk_window->get_frame_extents (window_rect); + if (from_headers) { + alloc = controls_layout.get_allocation (); + } else { + alloc = _track_canvas_viewport->get_allocation (); + + /* the effective width of the autoscroll boundary so + that we start scrolling before we hit the edge. + + this helps when the window is slammed up against the + right edge of the screen, making it hard to scroll + effectively. + */ + + if (alloc.get_width() > 20) { + alloc.set_width (alloc.get_width() - 20); + alloc.set_x (alloc.get_x() + 10); + } + } - Glib::RefPtr screen = get_screen (); - Gdk::Rectangle root_rect; - screen->get_root_window()->get_frame_extents (root_rect); + scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(), + alloc.get_x() + alloc.get_width(), + alloc.get_y() + alloc.get_height()); + + int x, y; + Gdk::ModifierType mask; - Gtk::Allocation editor_list = _the_notebook.get_allocation (); + get_window()->get_pointer (x, y, mask); - framecnt_t distance = pixel_to_sample (root_rect.get_x() + root_rect.get_width() - window_rect.get_x() - window_rect.get_width()); - if (_the_notebook.is_visible ()) { - distance += pixel_to_sample (editor_list.get_width()); + if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) || + (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) { + start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary); } - - /* Note whether we're fudging the autoscroll (see autoscroll_fudge_threshold) */ - _autoscroll_fudging = (distance < autoscroll_fudge_threshold ()); - - /* ty is in canvas-coordinate space */ - - double const ty = _drags->current_pointer_y(); - ArdourCanvas::Rect visible = _track_canvas->visible_area(); - - autoscroll_y = 0; - autoscroll_x = 0; - if (ty < visible.y0 && moving_up && allow_vert) { - autoscroll_y = -1; - startit = true; - } else if (ty > visible.y1 && !moving_up && allow_vert) { - autoscroll_y = 1; - startit = true; - } - - framepos_t rightmost_frame = leftmost_frame + current_page_samples(); - if (_autoscroll_fudging) { - rightmost_frame -= autoscroll_fudge_threshold (); - } - - if (_drags->current_pointer_frame() > rightmost_frame && allow_horiz) { - if (rightmost_frame < max_framepos && !moving_left) { - autoscroll_x = 1; - startit = true; - } - } else if (_drags->current_pointer_frame() < leftmost_frame && allow_horiz) { - if (leftmost_frame > 0 && moving_left) { - autoscroll_x = -1; - startit = true; - } - } - - if (autoscroll_active && ((autoscroll_x != last_autoscroll_x) || (autoscroll_y != last_autoscroll_y) || (autoscroll_x == 0 && autoscroll_y == 0))) { - stop_canvas_autoscroll (); - } - - if (startit && autoscroll_timeout_tag < 0) { - start_canvas_autoscroll (autoscroll_x, autoscroll_y); - } - - last_autoscroll_x = autoscroll_x; - last_autoscroll_y = autoscroll_y; } -gint -Editor::_autoscroll_canvas (void *arg) +bool +Editor::autoscroll_active () const { - return ((Editor *) arg)->autoscroll_canvas (); + return autoscroll_connection.connected (); } bool Editor::autoscroll_canvas () { - framepos_t new_frame; - framepos_t limit = max_framepos - current_page_samples(); - double new_pixel; + int x, y; + Gdk::ModifierType mask; + frameoffset_t dx = 0; + bool no_stop = false; + bool y_motion = false; - if (autoscroll_x_distance != 0) { + get_window()->get_pointer (x, y, mask); - if (autoscroll_x > 0) { - autoscroll_x_distance = (_drags->current_pointer_frame() - (leftmost_frame + current_page_samples())) / 3; - if (_autoscroll_fudging) { - autoscroll_x_distance += autoscroll_fudge_threshold () / 3; + VisualChange vc; + + if (autoscroll_horizontal_allowed) { + + framepos_t new_frame = leftmost_frame; + + /* horizontal */ + + if (x > autoscroll_boundary.x1) { + + /* bring it back into view */ + dx = x - autoscroll_boundary.x1; + dx += 10 + (2 * (autoscroll_cnt/2)); + + dx = pixel_to_sample (dx); + + if (leftmost_frame < max_framepos - dx) { + new_frame = leftmost_frame + dx; + } else { + new_frame = max_framepos; } - } else if (autoscroll_x < 0) { - autoscroll_x_distance = (leftmost_frame - _drags->current_pointer_frame()) / 3; + no_stop = true; + + } else if (x < autoscroll_boundary.x0) { + + dx = autoscroll_boundary.x0 - x; + dx += 10 + (2 * (autoscroll_cnt/2)); + + dx = pixel_to_sample (dx); + + if (leftmost_frame >= dx) { + new_frame = leftmost_frame - dx; + } else { + new_frame = 0; + } + + no_stop = true; + } + + if (new_frame != leftmost_frame) { + vc.time_origin = new_frame; + vc.add (VisualChange::TimeOrigin); } } - if (autoscroll_y_distance != 0) { - if (autoscroll_y > 0) { - autoscroll_y_distance = (_drags->current_pointer_y() - _visible_canvas_height) / 3; - } else if (autoscroll_y < 0) { + if (autoscroll_vertical_allowed) { + + const double vertical_pos = vertical_adjustment.get_value(); + double new_pixel = vertical_pos; + const int speed_factor = 20; - autoscroll_y_distance = (vertical_adjustment.get_value () - _drags->current_pointer_y()) / 3; - } - } - - if (autoscroll_x < 0) { - if (leftmost_frame < autoscroll_x_distance) { - new_frame = 0; - } else { - new_frame = leftmost_frame - autoscroll_x_distance; - } - } else if (autoscroll_x > 0) { - if (leftmost_frame > limit - autoscroll_x_distance) { - new_frame = limit; - } else { - new_frame = leftmost_frame + autoscroll_x_distance; - } - } else { - new_frame = leftmost_frame; - } - - double vertical_pos = vertical_adjustment.get_value(); - - if (autoscroll_y < 0) { - - if (vertical_pos < autoscroll_y_distance) { - new_pixel = 0; - } else { - new_pixel = vertical_pos - autoscroll_y_distance; - } - - } else if (autoscroll_y > 0) { - - new_pixel = min (_full_canvas_height - _visible_canvas_height, min (_full_canvas_height, (vertical_adjustment.get_value() + autoscroll_y_distance))); - - } else { + /* vertical */ + new_pixel = vertical_pos; + + if (y < autoscroll_boundary.y0) { + + /* scroll to make higher tracks visible */ + + if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) { + y_motion = scroll_up_one_track (); + } + + } else if (y > autoscroll_boundary.y1) { + + if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) { + y_motion = scroll_down_one_track (); + + } + } + + no_stop = true; } - if ((new_frame == 0 || new_frame == limit) && (new_pixel == 0 || new_pixel == DBL_MAX)) { - /* we are done */ + if (vc.pending) { + + /* change horizontal first */ + + if (vc.pending) { + visual_changer (vc); + } + + /* now send a motion event to notify anyone who cares + that we have moved to a new location (because we scrolled) + */ + + GdkEventMotion ev; + + ev.type = GDK_MOTION_NOTIFY; + ev.state = Gdk::BUTTON1_MASK; + + /* the motion handler expects events in canvas coordinate space */ + + /* first convert from Editor window coordinates to canvas + * window coordinates + */ + + int cx; + int cy; + + /* clamp x and y to remain within the visible area */ + + x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1); + y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1); + + translate_coordinates (*_track_canvas_viewport, x, y, cx, cy); + + ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy)); + ev.x = d.x; + ev.y = d.y; + + motion_handler (0, (GdkEvent*) &ev, true); + + } else if (no_stop) { + + /* not changing visual state but pointer is outside the scrolling boundary + * so we still need to deliver a fake motion event + */ + + GdkEventMotion ev; + + ev.type = GDK_MOTION_NOTIFY; + ev.state = Gdk::BUTTON1_MASK; + + /* the motion handler expects events in canvas coordinate space */ + + /* first convert from Editor window coordinates to canvas + * window coordinates + */ + + int cx; + int cy; + + /* clamp x and y to remain within the visible area. except + * .. if horizontal scrolling is allowed, always allow us to + * move back to zero + */ + + if (autoscroll_horizontal_allowed) { + x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1); + } else { + x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1); + } + y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1); + + translate_coordinates (*_track_canvas_viewport, x, y, cx, cy); + + ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy)); + ev.x = d.x; + ev.y = d.y; + + motion_handler (0, (GdkEvent*) &ev, true); + + } else { + stop_canvas_autoscroll (); return false; } - if (new_frame != leftmost_frame) { - reset_x_origin (new_frame); - } - - if (new_pixel != vertical_pos) { - vertical_adjustment.set_value (new_pixel); - } - - /* fake an event. */ - - Glib::RefPtr canvas_window = const_cast(this)->_track_canvas->get_window(); - gint x, y; - Gdk::ModifierType mask; - GdkEventMotion ev; - canvas_window->get_pointer (x, y, mask); - ev.type = GDK_MOTION_NOTIFY; - ev.state = Gdk::BUTTON1_MASK; - - /* the motion handler expects events in canvas coordinate space */ - ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (x, y)); - ev.x = d.x; - ev.y = d.y; - - motion_handler (0, (GdkEvent*) &ev, true); - autoscroll_cnt++; - if (autoscroll_cnt == 1) { - - /* connect the timeout so that we get called repeatedly */ - - autoscroll_timeout_tag = g_idle_add ( _autoscroll_canvas, this); - return false; - - } - - return true; -} + return true; /* call me again */ +} void -Editor::start_canvas_autoscroll (int dx, int dy) +Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary) { - if (!_session || autoscroll_active) { + if (!_session) { return; } stop_canvas_autoscroll (); - autoscroll_active = true; - autoscroll_x = dx; - autoscroll_y = dy; - autoscroll_x_distance = (framepos_t) floor (current_page_samples()/50.0); - autoscroll_y_distance = fabs ((double)dy * 5); /* pixels */ autoscroll_cnt = 0; + autoscroll_horizontal_allowed = allow_horiz; + autoscroll_vertical_allowed = allow_vert; + autoscroll_boundary = boundary; - /* do it right now, which will start the repeated callbacks */ + /* do the first scroll right now + */ autoscroll_canvas (); + + /* scroll again at very very roughly 30FPS */ + + autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30); } void Editor::stop_canvas_autoscroll () { - if (autoscroll_timeout_tag >= 0) { - g_source_remove (autoscroll_timeout_tag); - autoscroll_timeout_tag = -1; - } - - autoscroll_active = false; + autoscroll_connection.disconnect (); } bool @@ -709,19 +749,26 @@ Editor::entered_track_canvas (GdkEventCrossing */*ev*/) } void -Editor::ensure_time_axis_view_is_visible (const TimeAxisView& tav) +Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top) { double begin = tav.y_position(); - double v = vertical_adjustment.get_value (); - if (begin < v || begin + tav.current_height() > v + _visible_canvas_height) { + if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) { /* try to put the TimeAxisView roughly central */ if (begin >= _visible_canvas_height/2.0) { begin -= _visible_canvas_height/2.0; } - vertical_adjustment.set_value (begin); } + + /* Clamp the y pos so that we do not extend beyond the canvas full + * height. + */ + if (_full_canvas_height - begin < _visible_canvas_height){ + begin = _full_canvas_height - _visible_canvas_height; + } + + vertical_adjustment.set_value (begin); } /** Called when the main vertical_adjustment has changed */ @@ -748,8 +795,6 @@ Editor::set_horizontal_position (double p) } update_video_timeline(); - - HorizontalPositionChanged (); /* EMIT SIGNAL */ } void diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index c74c6b6e19..287a3bc403 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -1009,6 +1009,13 @@ Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item) return typed_event (item, event, NoteItem); } +bool +Editor::canvas_bottom_rect_event (GdkEvent* event) +{ + cerr << "CBR event, type " << event << endl; + return true; +} + bool Editor::track_canvas_drag_motion (Glib::RefPtr const& context, int x, int y, guint time) { diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 56879fbaa0..d451ef4aa9 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -361,16 +361,16 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll) if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) { if (!from_autoscroll) { - bool const moving_left = _drags->current_pointer_x() < _last_pointer_x; - bool const moving_up = _drags->current_pointer_y() < _last_pointer_y; - _editor->maybe_autoscroll (true, allow_vertical_autoscroll (), moving_left, moving_up); + _editor->maybe_autoscroll (true, allow_vertical_autoscroll (), false); } - motion (event, _move_threshold_passed != old_move_threshold_passed); - - _last_pointer_x = _drags->current_pointer_x (); - _last_pointer_y = _drags->current_pointer_y (); - _last_pointer_frame = adjusted_current_frame (event); + if (!_editor->autoscroll_active() || from_autoscroll) { + motion (event, _move_threshold_passed != old_move_threshold_passed); + + _last_pointer_x = _drags->current_pointer_x (); + _last_pointer_y = _drags->current_pointer_y (); + _last_pointer_frame = adjusted_current_frame (event); + } return true; } @@ -3912,9 +3912,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) break; } - if (event->button.x >= _editor->horizontal_position() + _editor->_visible_canvas_width) { - _editor->start_canvas_autoscroll (1, 0); - } + _editor->maybe_autoscroll (true, false, false); if (start != end) { switch (_operation) { @@ -4103,9 +4101,7 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move) } } - if (event->button.x >= _editor->horizontal_position() + _editor->_visible_canvas_width) { - _editor->start_canvas_autoscroll (1, 0); - } + _editor->maybe_autoscroll (true, false, false); if (start != end) { _editor->temp_location->set (start, end); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 0a8ef4296b..928801d0b2 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -179,12 +179,12 @@ Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) c *pcy = y; } - /* note that pixel_to_sample() never returns less than zero, so even if the pixel + /* note that pixel_to_sample_from_event() never returns less than zero, so even if the pixel position is negative (as can be the case with motion events in particular), the frame location is always positive. */ - return pixel_to_sample (x); + return pixel_to_sample_from_event (x); } Gdk::Cursor* @@ -2914,8 +2914,6 @@ Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv) return; } - assert (rv); - ArdourCanvas::Group* g = rv->get_canvas_group (); ArdourCanvas::Group* p = g->parent (); @@ -2927,21 +2925,28 @@ Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv) assert (item_bbox); ArdourCanvas::Rect parent_bbox = g->item_to_parent (item_bbox.get ()); - /* Halfway across the region */ - double const h = (parent_bbox.x0 + parent_bbox.x1) / 2; + /* First or last 10% of region is used for trimming, if the whole + region is wider than 20 pixels at the current zoom level. + */ - Trimmable::CanTrim ct = rv->region()->can_trim (); - if (x <= h) { - if (ct & Trimmable::FrontTrimEarlier) { - set_canvas_cursor (_cursors->left_side_trim, true); - } else { - set_canvas_cursor (_cursors->left_side_trim_right_only, true); - } - } else { - if (ct & Trimmable::EndTrimLater) { - set_canvas_cursor (_cursors->right_side_trim, true); - } else { - set_canvas_cursor (_cursors->right_side_trim_left_only, true); + double const w = parent_bbox.width(); + + if (w > 20.0 && x >= parent_bbox.x0 && x < parent_bbox.x1) { + + Trimmable::CanTrim ct = rv->region()->can_trim (); + + if (((x - parent_bbox.x0) / w) < 0.10) { + if (ct & Trimmable::FrontTrimEarlier) { + set_canvas_cursor (_cursors->left_side_trim, true); + } else { + set_canvas_cursor (_cursors->left_side_trim_right_only, true); + } + } else if (((parent_bbox.x1 - x) / w) < 0.10) { + if (ct & Trimmable::EndTrimLater) { + set_canvas_cursor (_cursors->right_side_trim, true); + } else { + set_canvas_cursor (_cursors->right_side_trim_left_only, true); + } } } } diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 9f44951bde..a72c95e48e 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -1276,6 +1276,69 @@ Editor::scroll_tracks_up_line () reset_y_origin (vertical_adjustment.get_value() - 60); } +bool +Editor::scroll_down_one_track () +{ + double vertical_pos = vertical_adjustment.get_value () + vertical_adjustment.get_page_size() - 1.0; + + TrackViewList::reverse_iterator next = track_views.rend(); + std::pair res; + + for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) { + if ((*t)->hidden()) { + continue; + } + + res = (*t)->covers_y_position (vertical_pos); + + if (res.first) { + break; + } + + next = t; + } + + /* move to the track below the first one that covers the */ + + if (next != track_views.rend()) { + ensure_track_visible (*next); + return true; + } + + return false; +} + +bool +Editor::scroll_up_one_track () +{ + double vertical_pos = vertical_adjustment.get_value (); + + TrackViewList::iterator prev = track_views.end(); + std::pair res; + + for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) { + + if ((*t)->hidden()) { + continue; + } + + res = (*t)->covers_y_position(vertical_pos); + + if (res.first) { + break; + } + + prev = t; + } + + if (prev != track_views.end()) { + ensure_track_visible (*prev); + return true; + } + + return false; +} + /* ZOOM */ void @@ -4755,12 +4818,17 @@ Editor::fork_region () MidiRegionView* const mrv = dynamic_cast(*r); if (mrv) { - boost::shared_ptr playlist = mrv->region()->playlist(); - boost::shared_ptr newregion = mrv->midi_region()->clone (); - - playlist->clear_changes (); - playlist->replace_region (mrv->region(), newregion, mrv->region()->position()); - _session->add_command(new StatefulDiffCommand (playlist)); + try { + boost::shared_ptr playlist = mrv->region()->playlist(); + boost::shared_ptr new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track()); + boost::shared_ptr newregion = mrv->midi_region()->clone (new_source); + + playlist->clear_changes (); + playlist->replace_region (mrv->region(), newregion, mrv->region()->position()); + _session->add_command(new StatefulDiffCommand (playlist)); + } catch (...) { + error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg; + } } r = tmp; @@ -6432,12 +6500,13 @@ Editor::remove_tracks () for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) { RouteTimeAxisView* rtv = dynamic_cast (*x); - if (rtv) { - if (rtv->is_track()) { - ntracks++; - } else { - nbusses++; - } + if (!rtv) { + continue; + } + if (rtv->is_track()) { + ntracks++; + } else { + nbusses++; } routes.push_back (rtv->_route); diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc index d92c729b75..354797642a 100644 --- a/gtk2_ardour/editor_routes.cc +++ b/gtk2_ardour/editor_routes.cc @@ -222,6 +222,7 @@ EditorRoutes::EditorRoutes (Editor* e) _display.set_headers_visible (true); _display.get_selection()->set_mode (SELECTION_SINGLE); _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter)); + _display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::selection_changed)); _display.set_reorderable (true); _display.set_name (X_("EditGroupList")); _display.set_rules_hint (true); @@ -1292,27 +1293,46 @@ EditorRoutes::button_press (GdkEventButton* ev) //Scroll editor canvas to selected track if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { - // Get the model row. Gtk::TreeModel::Row row = *_model->get_iter (path); - TimeAxisView *tv = row[_columns.tv]; - int y_pos = tv->y_position(); - - //Clamp the y pos so that we do not extend beyond the canvas full height. - if (_editor->_full_canvas_height - y_pos < _editor->_visible_canvas_height){ - y_pos = _editor->_full_canvas_height - _editor->_visible_canvas_height; - } - - //Only scroll to if the track is visible - if(y_pos != -1){ - _editor->reset_y_origin (y_pos); + if (tv) { + _editor->ensure_time_axis_view_is_visible (*tv, true); } } return false; } +void +EditorRoutes::selection_changed () +{ + if (_display.get_selection()->count_selected_rows() > 0) { + + TreeIter iter; + TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows (); + TrackViewList selected; + + _editor->get_selection().clear_regions (); + + for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) { + + if ((iter = _model->get_iter (*i))) { + + TimeAxisView* tv = (*iter)[_columns.tv]; + selected.push_back (tv); + } + + } + + _editor->get_selection().set (selected); + _editor->ensure_time_axis_view_is_visible (*(selected.front()), true); + + } else { + _editor->get_selection().clear_tracks (); + } +} + bool EditorRoutes::selection_filter (Glib::RefPtr const &, TreeModel::Path const&, bool /*selected*/) { diff --git a/gtk2_ardour/editor_routes.h b/gtk2_ardour/editor_routes.h index e07a7787aa..9780307435 100644 --- a/gtk2_ardour/editor_routes.h +++ b/gtk2_ardour/editor_routes.h @@ -98,6 +98,7 @@ private: void show_all_miditracks (); void hide_all_miditracks (); void show_tracks_with_regions_at_playhead (); + void selection_changed (); void display_drag_data_received ( Glib::RefPtr const &, gint, gint, Gtk::SelectionData const &, guint, guint diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index 6955a8e2e6..626a0dd55c 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -1608,7 +1608,7 @@ EngineControl::EngineControl () uint32_t il = (uint32_t) input_latency.get_value (); uint32_t ol = (uint32_t) input_latency.get_value (); - /* reset to zero so that our new test instance of JACK + /* reset to zero so that our new test instance will be clean of any existing latency measures. */ diff --git a/gtk2_ardour/ergonomic-us.bindings.in b/gtk2_ardour/ergonomic-us.bindings.in index c340adbb03..9c7efb9b99 100644 --- a/gtk2_ardour/ergonomic-us.bindings.in +++ b/gtk2_ardour/ergonomic-us.bindings.in @@ -163,6 +163,7 @@ ; (gtk_accel_path "/Snap/snap-to-eighths" "") (gtk_accel_path "/Editor/select-all-after-playhead" "<@TERTIARY@><@PRIMARY@>p") (gtk_accel_path "/Common/ToggleMaximalEditor" "F11") +(gtk_accel_path "/Common/ToggleMaximalMixer" "F12") ; (gtk_accel_path "/RegionList/SortBySourceFileLength" "") ; (gtk_accel_path "/Editor/Timecode" "") ; (gtk_accel_path "/Transport/PlaySelection" "") diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index ee381b96b5..dcb09ba6aa 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -1022,6 +1022,7 @@ GainMeter::get_gm_width () { Gtk::Requisition sz; int min_w = 0; + sz.width = 0; meter_metric_area.size_request (sz); min_w += sz.width; level_meter->size_request (sz); diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc index 7221cc1a89..b7ed024d94 100644 --- a/gtk2_ardour/main.cc +++ b/gtk2_ardour/main.cc @@ -57,6 +57,9 @@ #include "i18n.h" +#ifdef COMPILER_MSVC +#include // Needed for '_fmode' +#endif using namespace std; using namespace Gtk; @@ -138,8 +141,15 @@ sigpipe_handler (int /*signal*/) } } -#ifdef WINDOWS_VST_SUPPORT +#if (defined(COMPILER_MSVC) && defined(NDEBUG) && !defined(RDC_BUILD)) +/* + * Release build with MSVC uses ardour_main() + */ +int ardour_main (int argc, char *argv[]) +#elif (defined WINDOWS_VST_SUPPORT && !defined PLATFORM_WINDOWS) + +// prototype for function in windows_vst_plugin_ui.cc extern int windows_vst_gui_init (int* argc, char** argv[]); /* this is called from the entry point of a wine-compiled @@ -147,14 +157,22 @@ extern int windows_vst_gui_init (int* argc, char** argv[]); as a shared library. */ extern "C" { + int ardour_main (int argc, char *argv[]) + #else int main (int argc, char *argv[]) #endif { +#ifdef COMPILER_MSVC + // Essential!! Make sure that any files used by Ardour + // will be created or opened in BINARY mode! + _fmode = O_BINARY; +#endif + fixup_bundle_environment (argc, argv, &localedir); - load_custom_fonts(); /* needs to happend before any gtk and pango init calls */ + load_custom_fonts(); /* needs to happen before any gtk and pango init calls */ if (!Glib::thread_supported()) { Glib::thread_init(); @@ -164,15 +182,15 @@ int main (int argc, char *argv[]) gtk_set_locale (); #endif -#ifdef WINDOWS_VST_SUPPORT - /* this does some magic that is needed to make GTK and Wine's own - X11 client interact properly. - */ +#if (defined WINDOWS_VST_SUPPORT && !defined PLATFORM_WINDOWS) + /* this does some magic that is needed to make GTK and X11 client interact properly. + * the platform dependent code is in windows_vst_plugin_ui.cc + */ windows_vst_gui_init (&argc, &argv); #endif #ifdef ENABLE_NLS - cerr << "bnd txt domain [" << PACKAGE << "] to " << localedir << endl; + cerr << "bind txt domain [" << PACKAGE << "] to " << localedir << endl; (void) bindtextdomain (PACKAGE, localedir); /* our i18n translations are all in UTF-8, so make sure @@ -198,6 +216,16 @@ int main (int argc, char *argv[]) #endif if (parse_opts (argc, argv)) { +#if (defined(COMPILER_MSVC) && defined(NDEBUG) && !defined(RDC_BUILD)) + // Since we don't ordinarily have access to stdout and stderr with + // an MSVC app, let the user know we encountered a parsing error. + Gtk::Main app(&argc, &argv); // Calls 'gtk_init()' + + Gtk::MessageDialog dlgReportParseError (_("\n Ardour could not understand your command line "), + false, MESSAGE_ERROR, BUTTONS_CLOSE, true); + dlgReportParseError.set_title (_("An error was encountered while launching Ardour")); + dlgReportParseError.run (); +#endif exit (1); } @@ -260,7 +288,6 @@ int main (int argc, char *argv[]) return 0; } -#ifdef WINDOWS_VST_SUPPORT -} // end of extern C block +#if (defined WINDOWS_VST_SUPPORT && !defined PLATFORM_WINDOWS) +} // end of extern "C" block #endif - diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 273ba0dbd7..0d17bdbf6a 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -164,7 +164,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView & void MidiRegionView::parameter_changed (std::string const & p) { - if (p == "diplay-first-midi-bank-as-zero") { + if (p == "display-first-midi-bank-as-zero") { if (_enable_display) { redisplay_model(); } diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index 59c30c0c02..8ced280661 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -1521,8 +1521,7 @@ MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit) real_editor->snap_to (pos, 0); - boost::shared_ptr src = _session->create_midi_source_for_session ( - view()->trackview().track().get(), view()->trackview().track()->name()); + boost::shared_ptr src = _session->create_midi_source_by_stealing_name (view()->trackview().track()); PropertyList plist; plist.add (ARDOUR::Properties::start, 0); diff --git a/gtk2_ardour/missing_file_dialog.cc b/gtk2_ardour/missing_file_dialog.cc index 37868d5572..532101e762 100644 --- a/gtk2_ardour/missing_file_dialog.cc +++ b/gtk2_ardour/missing_file_dialog.cc @@ -133,7 +133,7 @@ MissingFileDialog::add_chosen () break; } - split (str, dirs, ':'); + split (str, dirs, G_SEARCHPATH_SEPARATOR); newdir = chooser.get_filename (); @@ -144,7 +144,7 @@ MissingFileDialog::add_chosen () } if (!str.empty()) { - str += ':'; + str += G_SEARCHPATH_SEPARATOR; } str += newdir; diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 842d725234..557a567e0a 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -197,7 +197,7 @@ MixerStrip::init () button_size_group->add_widget (*monitor_input_button); } - name_button.add_elements ( ArdourButton::FlatFace ); + name_button.add_elements ( ArdourButton::Inset ); top_button_table.attach (name_button, 0, 2, 2, 3); auto_n_io_table.attach (automation_label, 0, 1, 0, 1); automation_label.show(); diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 2307f32dfd..4c2d83f5f1 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -241,6 +241,7 @@ Mixer_UI::Mixer_UI () group_display.show(); _in_group_rebuild_or_clear = false; + _maximised = false; MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context()); @@ -1562,6 +1563,19 @@ Mixer_UI::set_state (const XMLNode& node) } } + if ((prop = node.property ("maximised"))) { + bool yn = string_is_affirmative (prop->value()); + Glib::RefPtr act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer")); + assert (act); + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + bool fs = tact && tact->get_active(); + if (yn ^ fs) { + ActionManager::do_action ("Common", + "ToggleMaximalMixer"); + } + } + + return 0; } @@ -1604,6 +1618,8 @@ Mixer_UI::get_state (void) node->add_property ("show-mixer", _visible ? "yes" : "no"); + node->add_property ("maximised", _maximised ? "yes" : "no"); + return *node; } @@ -1945,3 +1961,26 @@ Mixer_UI::toggle_midi_input_active (bool flip_others) _session->set_exclusive_input_active (rl, onoff, flip_others); } +void +Mixer_UI::maximise_mixer_space () +{ + if (_maximised) { + return; + } + + fullscreen (); + + _maximised = true; +} + +void +Mixer_UI::restore_mixer_space () +{ + if (!_maximised) { + return; + } + + unfullscreen(); + + _maximised = false; +} diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index db841535b7..693fd9dfa5 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -80,6 +80,9 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR void show_strip (MixerStrip *); void hide_strip (MixerStrip *); + void maximise_mixer_space(); + void restore_mixer_space(); + void ensure_float (Gtk::Window&); MonitorSection* monitor_section() const { return _monitor_section; } @@ -279,6 +282,9 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR bool _following_editor_selection; void monitor_section_going_away (); + + /// true if we are in fullscreen mode + bool _maximised; }; #endif /* __ardour_mixer_ui_h__ */ diff --git a/gtk2_ardour/mnemonic-us.bindings.in b/gtk2_ardour/mnemonic-us.bindings.in index aff175857c..d0bc802b0e 100644 --- a/gtk2_ardour/mnemonic-us.bindings.in +++ b/gtk2_ardour/mnemonic-us.bindings.in @@ -189,6 +189,7 @@ This mode provides many different operations on both regions and control points, @trans|Editor/toggle-follow-playhead|<@PRIMARY@>f|toggle playhead tracking @trans|Transport/ToggleFollowEdits|<@TERTIARY@>f|toggle playhead follows edits @wvis|Common/ToggleMaximalEditor|<@PRIMARY@><@SECONDARY@>f|maximise editor space +@wvis|Common/ToggleMaximalMixer|F12|maximise mixer space @wvis|Region/show-rhythm-ferret|<@WINDOW@>f|show rhythm ferret window @mmode|MouseMode/set-mouse-mode-gain|g|region gain mode @epp|Region/play-selected-regions|h|play selected region(s) diff --git a/gtk2_ardour/nsmclient.cc b/gtk2_ardour/nsmclient.cc index 94c3e8570e..2fa7556207 100644 --- a/gtk2_ardour/nsmclient.cc +++ b/gtk2_ardour/nsmclient.cc @@ -27,6 +27,10 @@ #pragma GCC diagnostic ignored "-Wunused-parameter" #else #include // Needed for 'getpid()' + +#include +#define LO_TT_IMMEDIATE lo_get_tt_immediate() +lo_timetag lo_get_tt_immediate() { lo_timetag tt = {0U,1U}; return tt; } #endif namespace NSM diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 0b37a3d2cf..f3b76e9310 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -266,9 +266,14 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual framecnt_t current_page_samples() const = 0; virtual double visible_canvas_height () const = 0; virtual void temporal_zoom_step (bool coarser) = 0; - virtual void ensure_time_axis_view_is_visible (const TimeAxisView& tav) = 0; + virtual void ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top = false) { + _ensure_time_axis_view_is_visible (tav, at_top); + } + virtual void override_visible_track_count () = 0; virtual void scroll_tracks_down_line () = 0; virtual void scroll_tracks_up_line () = 0; + virtual bool scroll_down_one_track () = 0; + virtual bool scroll_up_one_track () = 0; virtual void prepare_for_cleanup () = 0; virtual void finish_cleanup () = 0; virtual void reset_x_origin (framepos_t frame) = 0; @@ -302,8 +307,6 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual void get_equivalent_regions (RegionView* rv, std::vector&, PBD::PropertyID) const = 0; sigc::signal ZoomChanged; - /** Emitted when the horizontal position of the editor view changes */ - sigc::signal HorizontalPositionChanged; sigc::signal Realized; sigc::signal UpdateAllTransportClocks; @@ -381,8 +384,9 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual Gtkmm2ext::TearOff* tools_tearoff () const = 0; virtual DragManager* drags () const = 0; - virtual void maybe_autoscroll (bool, bool, bool, bool) = 0; + virtual void maybe_autoscroll (bool, bool, bool from_headers) = 0; virtual void stop_canvas_autoscroll () = 0; + virtual bool autoscroll_active() const = 0; virtual MouseCursors const * cursors () const = 0; virtual VerboseCursor * verbose_cursor () const = 0; @@ -407,6 +411,9 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi PBD::Signal0 SnapChanged; PBD::Signal0 MouseModeChanged; + + protected: + virtual void _ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top) = 0; }; #endif // __gtk_ardour_public_editor_h__ diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index 72f959b5c5..d4a5c57705 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -1795,6 +1795,8 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active) )); + add_option (_("Audio"), new OptionEditorHeading (_("Regions"))); + add_option (_("Audio"), new BoolOption ( "auto-analyse-audio", @@ -2016,7 +2018,7 @@ RCOptionEditor::RCOptionEditor () add_option (_("MIDI"), new BoolOption ( - "diplay-first-midi-bank-as-zero", + "display-first-midi-bank-as-zero", _("Display first MIDI bank/program as 0"), sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero), sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero) @@ -2122,6 +2124,14 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_tooltips) )); + add_option (S_("Preferences|GUI"), + new BoolOption ( + "show-name-highlight", + _("use name highlight bars in region displays"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_name_highlight), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_name_highlight) + )); + #ifndef GTKOSX /* font scaling does nothing with GDK/Quartz */ add_option (S_("Preferences|GUI"), new FontScalingOptions (_rc_config)); @@ -2142,6 +2152,7 @@ RCOptionEditor::RCOptionEditor () _mixer_strip_visibility.add (0, X_("SoloSafe"), _("Solo Safe")); _mixer_strip_visibility.add (0, X_("SoloIsolated"), _("Solo Isolated")); _mixer_strip_visibility.add (0, X_("Comments"), _("Comments")); + _mixer_strip_visibility.add (0, X_("Group"), _("Group")); _mixer_strip_visibility.add (0, X_("MeterPoint"), _("Meter Point")); add_option ( diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc index f468eedb60..127ce79b84 100644 --- a/gtk2_ardour/region_view.cc +++ b/gtk2_ardour/region_view.cc @@ -168,20 +168,20 @@ RegionView::init (Gdk::Color const & basic_color, bool wfd) if (name_highlight) { name_highlight->set_data ("regionview", this); name_highlight->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_name_highlight_event), name_highlight, this)); - - if (frame_handle_start) { - frame_handle_start->set_data ("regionview", this); - frame_handle_start->set_data ("isleft", (void*) 1); - frame_handle_start->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_frame_handle_event), frame_handle_start, this)); - frame_handle_start->raise_to_top(); - } - - if (frame_handle_end) { - frame_handle_end->set_data ("regionview", this); - frame_handle_end->set_data ("isleft", (void*) 0); - frame_handle_end->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_frame_handle_event), frame_handle_end, this)); - frame_handle_end->raise_to_top(); - } + } + + if (frame_handle_start) { + frame_handle_start->set_data ("regionview", this); + frame_handle_start->set_data ("isleft", (void*) 1); + frame_handle_start->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_frame_handle_event), frame_handle_start, this)); + frame_handle_start->raise_to_top(); + } + + if (frame_handle_end) { + frame_handle_end->set_data ("regionview", this); + frame_handle_end->set_data ("isleft", (void*) 0); + frame_handle_end->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_frame_handle_event), frame_handle_end, this)); + frame_handle_end->raise_to_top(); } if (name_text) { diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 3175fa7f56..e05243c063 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -206,9 +206,10 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) if (!_route->is_master()) { controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); } - - controls_table.attach (route_group_button, 7, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); -// controls_table.attach (gm.get_gain_slider(), 0, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::AttachOptions (0), 3, 0); + if (!ARDOUR::Profile->get_trx()) { + controls_table.attach (route_group_button, 7, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); + // controls_table.attach (gm.get_gain_slider(), 0, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::AttachOptions (0), 3, 0); + } ARDOUR_UI::instance()->set_tip(*solo_button,_("Solo")); ARDOUR_UI::instance()->set_tip(*mute_button,_("Mute")); @@ -222,9 +223,11 @@ RouteTimeAxisView::set_route (boost::shared_ptr rt) label_view (); - controls_table.attach (automation_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + if (!ARDOUR::Profile->get_trx()) { + controls_table.attach (automation_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + } - if (is_track() && track()->mode() == ARDOUR::Normal) { + if (!ARDOUR::Profile->get_trx() && is_track() && track()->mode() == ARDOUR::Normal) { controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); } @@ -725,7 +728,7 @@ RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection) _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false)); } else { - bool needs_bounce; + bool needs_bounce = false; if (!track()->can_use_mode (mode, needs_bounce)) { diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index acd507d869..e25fd2060c 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -588,7 +588,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev) } if (!_session->engine().connected()) { - MessageDialog msg (_("Not connected to JACK - cannot engage record")); + MessageDialog msg (_("Not connected to AudioEngine - cannot engage record")); msg.run (); return true; } diff --git a/gtk2_ardour/search_path_option.cc b/gtk2_ardour/search_path_option.cc index 3e216dfeb3..b2b4b9cd3f 100644 --- a/gtk2_ardour/search_path_option.cc +++ b/gtk2_ardour/search_path_option.cc @@ -103,7 +103,7 @@ SearchPathOption::set_state_from_config () clear (); path_box.pack_start (session_label); - split (str, dirs, ':'); + split (str, dirs, G_SEARCHPATH_SEPARATOR); for (vector::iterator d = dirs.begin(); d != dirs.end(); ++d) { add_path (*d); @@ -118,7 +118,7 @@ SearchPathOption::changed () for (list::iterator p = paths.begin(); p != paths.end(); ++p) { if (!str.empty()) { - str += ':'; + str += G_SEARCHPATH_SEPARATOR; } str += (*p)->entry.get_text (); } diff --git a/gtk2_ardour/session_option_editor.cc b/gtk2_ardour/session_option_editor.cc index f243973013..9560fddc79 100644 --- a/gtk2_ardour/session_option_editor.cc +++ b/gtk2_ardour/session_option_editor.cc @@ -88,7 +88,7 @@ SessionOptionEditor::SessionOptionEditor (Session* s) add_option (_("Sync"), new BoolOption ( "videotimeline-pullup", - _("Apply Pull-Up/Down to Video Timeline and Video Monitor (Unless in JACK-sync)."), + _("Apply Pull-Up/Down to Video Timeline and Video Monitor (Unless using JACK-sync)."), sigc::mem_fun (*_session_config, &SessionConfiguration::get_videotimeline_pullup), sigc::mem_fun (*_session_config, &SessionConfiguration::set_videotimeline_pullup) )); diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc index 83a9c08459..e175d20dc7 100644 --- a/gtk2_ardour/sfdb_ui.cc +++ b/gtk2_ardour/sfdb_ui.cc @@ -21,6 +21,8 @@ #include "gtk2ardour-config.h" #endif +#include "i18n.h" + #include #include #include @@ -69,8 +71,6 @@ #include "sfdb_freesound_mootcher.h" -#include "i18n.h" - using namespace ARDOUR; using namespace PBD; using namespace std; diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index 036323627c..f67ca6a3ce 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -298,7 +298,7 @@ TimeAxisView::controls_ebox_scroll (GdkEventScroll* ev) e.stepping_axis_view()->step_height (false); return true; } else if (Keyboard::no_modifiers_active (ev->state)) { - _editor.scroll_tracks_up_line(); + _editor.scroll_up_one_track(); return true; } break; @@ -313,7 +313,7 @@ TimeAxisView::controls_ebox_scroll (GdkEventScroll* ev) e.stepping_axis_view()->step_height (true); return true; } else if (Keyboard::no_modifiers_active (ev->state)) { - _editor.scroll_tracks_down_line(); + _editor.scroll_down_one_track(); return true; } break; @@ -370,32 +370,11 @@ TimeAxisView::controls_ebox_motion (GdkEventMotion* ev) * are pretending that the drag is taking place over the canvas * (which perhaps in the glorious future, when track headers * and the canvas are unified, will actually be true.) - * - * First, translate the event coordinates into the canvas - * coordinate space that DragManager::motion_handler is - * expecting (this requires translation into the *window* - * coordinates for the track canvas window, and then conversion - * from window to canvas coordinate spaces). - * - * Then fake a DragManager motion event so that when - * maybe_autoscroll asks DragManager for the current pointer - * position it will get the correct answers. */ - int tx, ty; - controls_ebox.translate_coordinates (*_editor.get_track_canvas(), ev->x, ev->y, tx, ty); + _editor.maybe_autoscroll (false, true, true); - /* x-axis of track headers is not shared with the canvas, but - the y-axis is, so we we can get a valid translation here. - */ - - Duple canvas_coord = _editor.get_track_canvas()->canvas()->window_to_canvas (Duple (tx, ty)); - ev->y = (int) floor (canvas_coord.y); - - _editor.drags()->motion_handler ((GdkEvent *) ev, false); - _editor.maybe_autoscroll (false, true, false, ev->y_root < _resize_drag_start); - - /* now do the actual TAV resize */ + /* now schedule the actual TAV resize */ int32_t const delta = (int32_t) floor (ev->y_root - _resize_drag_start); _editor.add_to_idle_resize (this, delta); _resize_drag_start = ev->y_root; @@ -545,6 +524,8 @@ TimeAxisView::set_height (uint32_t h) /* resize the selection rect */ show_selection (_editor.get_selection().time); } + + _editor.override_visible_track_count (); } bool diff --git a/gtk2_ardour/time_axis_view_item.cc b/gtk2_ardour/time_axis_view_item.cc index ca615f5045..ad2ab9c344 100644 --- a/gtk2_ardour/time_axis_view_item.cc +++ b/gtk2_ardour/time_axis_view_item.cc @@ -35,6 +35,8 @@ #include "canvas/text.h" #include "canvas/utils.h" +#include "ardour/profile.h" + #include "ardour_ui.h" /* * ardour_ui.h was moved up in the include list @@ -87,8 +89,20 @@ TimeAxisViewItem::set_constant_heights () layout = foo.create_pango_layout (X_("H")); /* just the ascender */ NAME_HEIGHT = height; - NAME_Y_OFFSET = height + 1; - NAME_HIGHLIGHT_SIZE = height + 2; + + /* Config->get_show_name_highlight) == true: + Y_OFFSET is measured from bottom of the time axis view item. + Config->get_show_name_highlight) == false: + Y_OFFSET is measured from the top of the time axis view item. + */ + + if (Config->get_show_name_highlight()) { + NAME_Y_OFFSET = height + 1; + NAME_HIGHLIGHT_SIZE = height + 2; + } else { + NAME_Y_OFFSET = 3; + NAME_HIGHLIGHT_SIZE = 0; + } NAME_HIGHLIGHT_THRESH = NAME_HIGHLIGHT_SIZE * 3; } @@ -189,7 +203,7 @@ TimeAxisViewItem::init (ArdourCanvas::Group* parent, double fpp, Gdk::Color cons if (visibility & ShowFrame) { frame = new ArdourCanvas::Rectangle (group, - ArdourCanvas::Rect (0.0, 1.0, + ArdourCanvas::Rect (0.0, 0.0, trackview.editor().sample_to_pixel(duration) + RIGHT_EDGE_SHIFT, trackview.current_height() - 1.0)); @@ -203,14 +217,14 @@ TimeAxisViewItem::init (ArdourCanvas::Group* parent, double fpp, Gdk::Color cons frame->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TimeAxisFrame()); } - // frame->set_outline_what (ArdourCanvas::Rectangle::What (ArdourCanvas::Rectangle::RIGHT|ArdourCanvas::Rectangle::LEFT)); + frame->set_outline_what (ArdourCanvas::Rectangle::What (ArdourCanvas::Rectangle::RIGHT|ArdourCanvas::Rectangle::LEFT)); } else { frame = 0; } - if (visibility & ShowNameHighlight) { + if (Config->get_show_name_highlight() && (visibility & ShowNameHighlight)) { double width; double start; @@ -240,7 +254,11 @@ TimeAxisViewItem::init (ArdourCanvas::Group* parent, double fpp, Gdk::Color cons if (visibility & ShowNameText) { name_text = new ArdourCanvas::Text (group); CANVAS_DEBUG_NAME (name_text, string_compose ("name text for %1", get_item_name())); - name_text->set_position (ArdourCanvas::Duple (NAME_X_OFFSET, trackview.current_height() - NAME_Y_OFFSET)); + if (Config->get_show_name_highlight()) { + name_text->set_position (ArdourCanvas::Duple (NAME_X_OFFSET, trackview.current_height() - NAME_Y_OFFSET)); + } else { + name_text->set_position (ArdourCanvas::Duple (NAME_X_OFFSET, NAME_Y_OFFSET)); + } name_text->set_font_description (NAME_FONT); } else { name_text = 0; @@ -570,7 +588,11 @@ TimeAxisViewItem::set_height (double height) manage_name_highlight (); if (visibility & ShowNameText) { - name_text->set_y_position (height - NAME_Y_OFFSET); + if (Config->get_show_name_highlight()) { + name_text->set_y_position (height - NAME_Y_OFFSET); + } else { + name_text->set_y_position (NAME_Y_OFFSET); + } } if (frame) { @@ -834,6 +856,13 @@ TimeAxisViewItem::set_frame_gradient () void TimeAxisViewItem::set_trim_handle_colors() { +#if 1 + /* Leave them transparent for now */ + if (frame_handle_start) { + frame_handle_start->set_fill_color (0x00000000); + frame_handle_end->set_fill_color (0x00000000); + } +#else if (frame_handle_start) { if (position_locked) { frame_handle_start->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TrimHandleLocked()); @@ -843,6 +872,7 @@ TimeAxisViewItem::set_trim_handle_colors() frame_handle_end->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TrimHandle()); } } +#endif } bool diff --git a/gtk2_ardour/time_info_box.cc b/gtk2_ardour/time_info_box.cc index 364b0fda43..5d11c35c79 100644 --- a/gtk2_ardour/time_info_box.cc +++ b/gtk2_ardour/time_info_box.cc @@ -27,6 +27,7 @@ #include "gtkmm2ext/actions.h" #include "ardour/location.h" +#include "ardour/profile.h" #include "ardour/session.h" #include "time_info_box.h" @@ -71,7 +72,9 @@ TimeInfoBox::TimeInfoBox () set_border_width (2); pack_start (left, true, true); - pack_start (right, true, true); + if (!ARDOUR::Profile->get_trx()) { + pack_start (right, true, true); + } left.set_homogeneous (false); left.set_spacings (0); diff --git a/gtk2_ardour/transcode_ffmpeg.cc b/gtk2_ardour/transcode_ffmpeg.cc index 9e531ca0e9..4a0fc4b342 100644 --- a/gtk2_ardour/transcode_ffmpeg.cc +++ b/gtk2_ardour/transcode_ffmpeg.cc @@ -46,6 +46,7 @@ TranscodeFfmpeg::TranscodeFfmpeg (std::string f) m_avoffset = m_lead_in = m_lead_out = 0; m_width = m_height = 0; m_aspect = m_fps = 0; + m_sar = ""; #if 1 /* tentative debug mode */ debug_enable = false; #endif @@ -138,6 +139,7 @@ TranscodeFfmpeg::probe () m_width = m_height = 0; m_fps = m_aspect = 0; m_duration = 0; + m_sar.clear(); m_codec.clear(); m_audio.clear(); @@ -199,6 +201,13 @@ TranscodeFfmpeg::probe () m_duration = atof(value) * m_fps * timebase; } else if (key == X_("duration") && m_fps != 0 && m_duration == 0) { m_duration = atof(value) * m_fps; + } else if (key == X_("sample_aspect_ratio")) { + std::string::size_type pos; + pos = value.find_first_of(':'); + if (pos != std::string::npos && atof(value.substr(pos+1)) != 0) { + m_sar = value; + m_sar.replace(pos, 1, "/"); + } } else if (key == X_("display_aspect_ratio")) { std::string::size_type pos; pos = value.find_first_of(':'); @@ -340,20 +349,28 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf if (m_lead_in != 0 && m_lead_out != 0) { std::ostringstream osstream; argp[a++] = strdup("-vf"); - osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in << X_(" [pre]; "); - osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out << X_(" [post]; "); + osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in; + if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; + osstream << X_(" [pre]; "); + osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out; + if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; + osstream << X_(" [post]; "); osstream << X_("[pre] [in] [post] concat=n=3"); argp[a++] = strdup(osstream.str().c_str()); } else if (m_lead_in != 0) { std::ostringstream osstream; argp[a++] = strdup("-vf"); - osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in << X_(" [pre]; "); + osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in; + if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; + osstream << X_(" [pre]; "); osstream << X_("[pre] [in] concat=n=2"); argp[a++] = strdup(osstream.str().c_str()); } else if (m_lead_out != 0) { std::ostringstream osstream; argp[a++] = strdup("-vf"); - osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out << X_(" [post]; "); + osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out; + if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; + osstream << X_(" [post]; "); osstream << X_("[in] [post] concat=n=2"); argp[a++] = strdup(osstream.str().c_str()); } diff --git a/gtk2_ardour/transcode_ffmpeg.h b/gtk2_ardour/transcode_ffmpeg.h index 184f37932b..b54d9e54c7 100644 --- a/gtk2_ardour/transcode_ffmpeg.h +++ b/gtk2_ardour/transcode_ffmpeg.h @@ -134,6 +134,7 @@ class TranscodeFfmpeg : public sigc::trackable double m_fps; double m_aspect; + std::string m_sar; ARDOUR::framecnt_t m_duration; int m_width; int m_height; diff --git a/gtk2_ardour/transcode_video_dialog.cc b/gtk2_ardour/transcode_video_dialog.cc index 26cd3c3009..9a8eaa65f2 100644 --- a/gtk2_ardour/transcode_video_dialog.cc +++ b/gtk2_ardour/transcode_video_dialog.cc @@ -179,16 +179,18 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) 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")); + video_combo.append_text(_("Reference From Current Location (Previously Transcoded Files Only)")); if (ffok) { video_combo.append_text(_("Import/Transcode Video to Session")); - video_combo.set_active(2); - } else { video_combo.set_active(1); + } else { + video_combo.set_active(0); video_combo.set_sensitive(false); audio_combo.set_sensitive(false); } + if (as.size() > 0) { + video_combo.append_text(_("Do Not Import Video (Audio Import Only)")); + } options_box->pack_start (video_combo, false, false, 4); @@ -227,8 +229,11 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) t->attach (*l, 0, 1, 2, 3); audio_combo.set_name ("PaddedButton"); t->attach (audio_combo, 1, 4, 2, 3); - audio_combo.append_text("No audio"); - if (as.size() > 0) { + if (as.size() == 0) { + audio_combo.append_text(_("No Audio Track Present")); + audio_combo.set_sensitive(false); + } else { + audio_combo.append_text(_("Do Not Extract Audio")); for (TranscodeFfmpeg::FFAudioStreams::iterator it = as.begin(); it < as.end(); ++it) { audio_combo.append_text((*it).name); } @@ -366,7 +371,7 @@ TranscodeVideoDialog::dialog_progress_mode () void TranscodeVideoDialog::launch_transcode () { - if (video_combo.get_active_row_number() != 2) { + if (video_combo.get_active_row_number() != 1) { launch_audioonly(); return; } @@ -415,8 +420,8 @@ TranscodeVideoDialog::launch_transcode () void TranscodeVideoDialog::video_combo_changed () { - int i = video_combo.get_active_row_number(); - if (i != 2) { + const int i = video_combo.get_active_row_number(); + if (i != 1) { scale_combo.set_sensitive(false); aspect_checkbox.set_sensitive(false); height_spinner.set_sensitive(false); @@ -429,12 +434,19 @@ TranscodeVideoDialog::video_combo_changed () bitrate_checkbox.set_sensitive(true); bitrate_spinner.set_sensitive(true); } + if (i == 2 && audio_combo.get_active_row_number() == 0) { + audio_combo.set_active(1); + } } void TranscodeVideoDialog::audio_combo_changed () { - ; + if (video_combo.get_active_row_number() == 2 + && audio_combo.get_active_row_number() == 0) + { + audio_combo.set_active(1); + } } void diff --git a/gtk2_ardour/transcode_video_dialog.h b/gtk2_ardour/transcode_video_dialog.h index eb2808e560..835b32d82c 100644 --- a/gtk2_ardour/transcode_video_dialog.h +++ b/gtk2_ardour/transcode_video_dialog.h @@ -31,9 +31,9 @@ #include "transcode_ffmpeg.h" enum VtlTranscodeOption { - VTL_IMPORT_NO_VIDEO = 0, - VTL_IMPORT_REFERENCE = 1, - VTL_IMPORT_TRANSCODED = 2 + VTL_IMPORT_REFERENCE = 0, + VTL_IMPORT_TRANSCODED = 1, + VTL_IMPORT_NO_VIDEO = 2 }; /** @class TranscodeVideoDialog diff --git a/gtk2_ardour/video_timeline.cc b/gtk2_ardour/video_timeline.cc index 8adc7bc4d0..ca1da8d693 100644 --- a/gtk2_ardour/video_timeline.cc +++ b/gtk2_ardour/video_timeline.cc @@ -716,7 +716,7 @@ void VideoTimeLine::find_xjadeo () { std::string xjadeo_file_path; if (getenv("XJREMOTE")) { - _xjadeo_bin = strdup(getenv("XJREMOTE")); // XXX TODO: free it?! + _xjadeo_bin = getenv("XJREMOTE"); } else if (find_file_in_search_path (Searchpath(Glib::getenv("PATH")), X_("xjremote"), xjadeo_file_path)) { _xjadeo_bin = xjadeo_file_path; } diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 6c2fe48517..8b9d9708c1 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -377,7 +377,6 @@ def build(bld): # here using winegcc, and link it to the GTK front-end library obj = bld (features = 'cxx c cxxprogram wine') obj.source = ( - '../libs/fst/fst.c', '../libs/fst/vstwin.c', '../vst/winmain.c', ) @@ -398,7 +397,7 @@ def build(bld): obj.includes = [ '../libs/fst', '.' ] obj.linkflags = ['-mwindows', '-Wl,--export-dynamic'] obj.defines = ['_POSIX_SOURCE', 'USE_WS_PREFIX'] - obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3') + obj.install_path = bld.env['DLLDIR'] # end of the wine executable # now the shared library containing the GTK GUI for ardour @@ -439,7 +438,7 @@ def build(bld): 'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"', 'LOCALEDIR="' + os.path.join(os.path.normpath(bld.env['DATADIR']), 'locale') + '"', ] - obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3') + obj.install_path = os.path.join(bld.env['DLLDIR']) obj.uselib = 'UUID FLAC FONTCONFIG GLIBMM GTHREAD GTK OGG CURL DL' obj.uselib += ' GTKMM CANVAS FFTW3F' obj.uselib += ' AUDIOUNITS OSX GTKOSX LO ' @@ -493,11 +492,15 @@ def build(bld): # Wrappers + print 'DLL = ' + bld.env['DLLDIR'], '\n' + print 'DATADIR = ' + bld.env['DATADIR'], '\n' + print 'CONF = ' + bld.env['CONFDIR'], '\n' + wrapper_subst_dict = { 'INSTALL_PREFIX' : bld.env['PREFIX'], - 'LIBDIR' : os.path.normpath(bld.env['LIBDIR']), + 'LIBDIR' : os.path.normpath(bld.env['DLLDIR']), 'DATADIR' : os.path.normpath(bld.env['DATADIR']), - 'SYSCONFDIR' : os.path.normpath(bld.env['SYSCONFDIR']), + 'SYSCONFDIR' : os.path.normpath(bld.env['CONFDIR']), 'LIBS' : 'build/libs', 'VERSION' : bld.env['VERSION'], 'EXECUTABLE' : 'build/gtk2_ardour/tracks' @@ -662,14 +665,14 @@ def build(bld): # find and add all ##include dependencies as sources obj.source += _doPyp (bld.path.find_resource ('ardour3_ui_dark.rc.in').srcpath(), True) obj.target = 'ardour3_ui_dark.rc' - obj.install_path = '${SYSCONFDIR}/ardour3' + obj.install_path = bld.env['CONFDIR'] obj = bld (rule = include_processor) obj.source = [ 'ardour3_ui_light.rc.pre' ] # find and add all ##include dependencies as sources obj.source += _doPyp (bld.path.find_resource ('ardour3_ui_light.rc.in').srcpath(), True) obj.target = 'ardour3_ui_light.rc' - obj.install_path = '${SYSCONFDIR}/ardour3' + obj.install_path = bld.env['CONFDIR'] # Menus menus_argv = [] @@ -704,27 +707,24 @@ def build(bld): source = b + '.bindings.in', rule = a_rule ) - obj.install_path = os.path.join(bld.env['SYSCONFDIR'], 'ardour3') + obj.install_path = os.path.join(bld.env['CONFDIR']) # not modified at present - bld.install_files(os.path.join(bld.env['SYSCONFDIR'], 'ardour3'), - 'step_editing.bindings') - bld.install_files(os.path.join(bld.env['SYSCONFDIR'], 'ardour3'), - 'mixer.bindings') + bld.install_files(bld.env['CONFDIR'], 'step_editing.bindings') + bld.install_files(bld.env['CONFDIR'], 'mixer.bindings') # Icons/Images - bld.install_files('${DATADIR}/ardour3/icons', bld.path.ant_glob('icons/*.png')) - bld.install_files('${DATADIR}/ardour3/pixmaps', bld.path.ant_glob('pixmaps/*.xpm')) - bld.install_files('${DATADIR}/ardour3/ui', bld.path.ant_glob('ui/*.*')) - bld.install_files('${DATADIR}/ardour3', 'splash.png') - bld.install_files('${DATADIR}/ardour3', 'small-splash.png') - bld.install_files('${DATADIR}/ardour3', 'ArdourMono.ttf') + bld.install_files(os.path.join (bld.env['DATADIR'], 'icons'), bld.path.ant_glob('icons/*.png')) + bld.install_files(os.path.join (bld.env['DATADIR'], 'pixmaps'), bld.path.ant_glob('pixmaps/*.xpm')) + bld.install_files(bld.env['DATADIR'], 'splash.png') + bld.install_files(bld.env['DATADIR'], 'small-splash.png') + bld.install_files(bld.env['DATADIR'], 'ArdourMono.ttf') # Default UI configuration - bld.install_files('${SYSCONFDIR}/ardour3', 'ardour3_ui_default.conf') + bld.install_files(bld.env['CONFDIR'], 'ardour3_ui_default.conf') # Default export stuff - bld.install_files('${SYSCONFDIR}/ardour3/export', bld.path.ant_glob('export/*.format')) + bld.install_files(os.path.join(bld.env['CONFDIR'],' export'), bld.path.ant_glob('export/*.format')) # i18n if bld.is_defined('ENABLE_NLS'): diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index c0b78bad13..2e838ff628 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -139,7 +139,6 @@ class LIBARDOUR_API AudioDiskstream : public Diskstream void set_block_size (pframes_t); int internal_playback_seek (framecnt_t distance); int can_internal_playback_seek (framecnt_t distance); - std::list > steal_write_sources(); void reset_write_sources (bool, bool force = false); void non_realtime_input_change (); void non_realtime_locate (framepos_t location); diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h index 53819c1c9e..e0a199fd72 100644 --- a/libs/ardour/ardour/audiofilesource.h +++ b/libs/ardour/ardour/audiofilesource.h @@ -39,10 +39,6 @@ class LIBARDOUR_API AudioFileSource : public AudioSource, public FileSource { public: virtual ~AudioFileSource (); - bool set_name (const std::string& newname) { - return (set_source_name(newname, destructive()) == 0); - } - std::string peak_path (std::string audio_path); std::string find_broken_peakfile (std::string missing_peak_path, std::string audio_path); diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index 5bd18663b8..dd74d5cb52 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -71,6 +71,8 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream virtual bool set_name (const std::string& str); + virtual std::string steal_write_source_name () { return std::string(); } + boost::shared_ptr io() const { return _io; } void set_track (ARDOUR::Track *); diff --git a/libs/ardour/ardour/file_source.h b/libs/ardour/ardour/file_source.h index 34e84c2428..37a7e67d2e 100644 --- a/libs/ardour/ardour/file_source.h +++ b/libs/ardour/ardour/file_source.h @@ -44,7 +44,7 @@ class LIBARDOUR_API MissingSource : public std::exception /** A source associated with a file on disk somewhere */ class LIBARDOUR_API FileSource : virtual public Source { public: - virtual ~FileSource () {} + virtual ~FileSource (); virtual const std::string& path() const { return _path; } @@ -82,6 +82,9 @@ public: static PBD::Signal2 > AmbiguousFileName; + void existence_check (); + virtual void prevent_deletion (); + protected: FileSource (Session& session, DataType type, const std::string& path, @@ -103,7 +106,6 @@ protected: std::string _origin; bool _open; - void prevent_deletion (); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index 01e8904736..5a10042096 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -111,7 +111,7 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream void set_block_size (pframes_t); int internal_playback_seek (framecnt_t distance); int can_internal_playback_seek (framecnt_t distance); - std::list > steal_write_sources(); + std::string steal_write_source_name(); void reset_write_sources (bool, bool force = false); void non_realtime_input_change (); void non_realtime_locate (framepos_t location); diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index b326bb30d8..38229b998b 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -64,6 +64,7 @@ class LIBARDOUR_API MidiRegion : public Region ~MidiRegion(); boost::shared_ptr clone (std::string path = std::string()) const; + boost::shared_ptr clone (boost::shared_ptr) const; boost::shared_ptr midi_source (uint32_t n=0) const; diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index ba50102ec9..07a32c5bfc 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -49,9 +49,21 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha MidiSource (Session& session, const XMLNode&); virtual ~MidiSource (); - boost::shared_ptr clone (const std::string& path, - Evoral::MusicalTime begin = Evoral::MinMusicalTime, - Evoral::MusicalTime end = Evoral::MaxMusicalTime); + /** Write the data in the given time range to another MidiSource + * \param newsrc MidiSource to which data will be written. Should be a + * new, empty source. If it already has contents, the results are + * undefined. Source must be writable. + * + * \param begin time of earliest event that can be written. + * \param end time of latest event that can be written. + * + * Returns zero on success, non-zero if the write failed for any + * reason. + * + */ + int write_to (boost::shared_ptr newsrc, + Evoral::MusicalTime begin = Evoral::MinMusicalTime, + Evoral::MusicalTime end = Evoral::MaxMusicalTime); /** Read the data in a given time range from the MIDI source. * All time stamps in parameters are in audio frames (even if the source has tempo time). diff --git a/libs/ardour/ardour/public_diskstream.h b/libs/ardour/ardour/public_diskstream.h index 5b5cd48231..4700e7b6be 100644 --- a/libs/ardour/ardour/public_diskstream.h +++ b/libs/ardour/ardour/public_diskstream.h @@ -38,7 +38,7 @@ public: virtual bool destructive () const = 0; virtual std::list > & last_capture_sources () = 0; virtual void set_capture_offset () = 0; - virtual std::list > steal_write_sources () = 0; + virtual std::string steal_write_source_name () = 0; virtual void reset_write_sources (bool, bool force = false) = 0; virtual float playback_buffer_load () const = 0; virtual float capture_buffer_load () const = 0; diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index de9ed5125a..677b53ae8d 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -45,7 +45,7 @@ CONFIG_VARIABLE (bool, midi_feedback, "midi-feedback", false) CONFIG_VARIABLE (int32_t, mmc_receive_device_id, "mmc-receive-device-id", 0x7f) CONFIG_VARIABLE (int32_t, mmc_send_device_id, "mmc-send-device-id", 0) CONFIG_VARIABLE (int32_t, initial_program_change, "initial-program-change", -1) -CONFIG_VARIABLE (bool, first_midi_bank_is_zero, "diplay-first-midi-bank-as-zero", false) +CONFIG_VARIABLE (bool, first_midi_bank_is_zero, "display-first-midi-bank-as-zero", false) /* Timecode and related */ @@ -227,6 +227,7 @@ CONFIG_VARIABLE (bool, use_tooltips, "use-tooltips", true) CONFIG_VARIABLE (std::string, mixer_strip_visibility, "mixer-strip-visibility", "PhaseInvert,SoloSafe,SoloIsolated,Group,MeterPoint") CONFIG_VARIABLE (bool, allow_non_quarter_pulse, "allow-non-quarter-pulse", false) CONFIG_VARIABLE (bool, show_region_gain, "show-region-gain", false) +CONFIG_VARIABLE (bool, show_name_highlight, "show-name-highlight", false) /* web addresses used in the program */ diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 463951388d..c8ffb5ae3c 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -194,8 +194,6 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop std::string peak_path (std::string) const; - std::string change_source_path_by_name (std::string oldpath, std::string oldname, std::string newname, bool destructive); - std::string peak_path_from_audio_path (std::string) const; std::string new_audio_source_name (const std::string&, uint32_t nchans, uint32_t chan, bool destructive); std::string new_midi_source_name (const std::string&); @@ -582,11 +580,12 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop boost::shared_ptr create_audio_source_for_session ( size_t, std::string const &, uint32_t, bool destructive); - boost::shared_ptr create_midi_source_for_session ( - Track*, std::string const &); + boost::shared_ptr create_midi_source_for_session (std::string const &); + boost::shared_ptr create_midi_source_by_stealing_name (boost::shared_ptr); boost::shared_ptr source_by_id (const PBD::ID&); - boost::shared_ptr source_by_path_and_channel (const std::string&, uint16_t); + boost::shared_ptr source_by_path_and_channel (const std::string&, uint16_t) const; + boost::shared_ptr source_by_path (const std::string&) const; uint32_t count_sources_by_origin (const std::string&); void add_playlist (boost::shared_ptr, bool unused = false); diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 82e6252b45..9d85f94352 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -45,12 +45,19 @@ public: virtual ~SMFSource (); + /** Rename the file on disk referenced by this source to \param newname + * + * This method exists only for MIDI file sources, not for audio, which + * can never be renamed. It exists for MIDI so that we can get + * consistent and sane region/source numbering when regions are added + * manually (which never happens with audio). + */ + int rename (const std::string& name); + bool safe_file_extension (const std::string& path) const { return safe_midi_file_extension(path); } - bool set_name (const std::string& newname) { return (set_source_name(newname, false) == 0); } - void append_event_unlocked_beats (const Evoral::Event& ev); void append_event_unlocked_frames (const Evoral::Event& ev, framepos_t source_start); @@ -69,6 +76,8 @@ public: static bool safe_midi_file_extension (const std::string& path); + void prevent_deletion (); + protected: void set_path (const std::string& newpath); diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index 2a6d3f7ad4..ee74fee46e 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -120,7 +120,7 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream bool destructive () const; std::list > & last_capture_sources (); void set_capture_offset (); - std::list > steal_write_sources(); + std::string steal_write_source_name (); void reset_write_sources (bool, bool force = false); float playback_buffer_load () const; float capture_buffer_load () const; diff --git a/libs/ardour/ardour/vst_types.h b/libs/ardour/ardour/vst_types.h index 1b443dc192..35b52435ab 100644 --- a/libs/ardour/ardour/vst_types.h +++ b/libs/ardour/ardour/vst_types.h @@ -62,7 +62,6 @@ struct LIBARDOUR_API _VSTHandle { void* dll; char* name; - char* nameptr; char* path; main_entry_t main_entry; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index dd2dcf324e..ffb8ef8a1b 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -1926,14 +1926,6 @@ AudioDiskstream::use_new_write_source (uint32_t n) return 0; } -list > -AudioDiskstream::steal_write_sources() -{ - /* not possible to steal audio write sources */ - list > ret; - return ret; -} - void AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/) { diff --git a/libs/ardour/audio_library.cc b/libs/ardour/audio_library.cc index 4a6089dac3..35c0972847 100644 --- a/libs/ardour/audio_library.cc +++ b/libs/ardour/audio_library.cc @@ -105,15 +105,15 @@ AudioLibrary::get_tags (string member) { vector tags; #ifdef HAVE_LRDF + char * uri = strdup(Glib::filename_to_uri(member).c_str()); lrdf_statement pattern; - pattern.subject = strdup(Glib::filename_to_uri(member).c_str()); + pattern.subject = uri; pattern.predicate = const_cast(TAG); pattern.object = 0; pattern.object_type = lrdf_literal; lrdf_statement* matches = lrdf_matches (&pattern); - free (pattern.subject); lrdf_statement* current = matches; while (current != 0) { @@ -125,6 +125,7 @@ AudioLibrary::get_tags (string member) lrdf_free_statements (matches); sort (tags.begin(), tags.end()); + free (uri); #endif return tags; } diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc index d0b6205cb2..c08cea962b 100644 --- a/libs/ardour/audiosource.cc +++ b/libs/ardour/audiosource.cc @@ -303,7 +303,7 @@ framecnt_t AudioSource::write (Sample *dst, framecnt_t cnt) { Glib::Threads::Mutex::Lock lm (_lock); - /* any write makes the fill not removable */ + /* any write makes the file not removable */ _flags = Flag (_flags & ~Removable); return write_unlocked (dst, cnt); } diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc index f3dc4f8c17..49b3d07761 100644 --- a/libs/ardour/control_protocol_manager.cc +++ b/libs/ardour/control_protocol_manager.cc @@ -245,9 +245,32 @@ ControlProtocolManager::discover_control_protocols () { vector cp_modules; +#ifdef COMPILER_MSVC + /** + * Different build targets (Debug / Release etc) use different versions + * of the 'C' runtime (which can't be 'mixed & matched'). Therefore, in + * case the supplied search path contains multiple version(s) of a given + * module, only select the one(s) which match the current build target + */ + #if defined (_DEBUG) + Glib::PatternSpec dll_extension_pattern("*D.dll"); + #elif defined (RDC_BUILD) + Glib::PatternSpec dll_extension_pattern("*RDC.dll"); + #elif defined (_WIN64) + Glib::PatternSpec dll_extension_pattern("*64.dll"); + #else + Glib::PatternSpec dll_extension_pattern("*32.dll"); + #endif +#else + Glib::PatternSpec dll_extension_pattern("*.dll"); +#endif + Glib::PatternSpec so_extension_pattern("*.so"); Glib::PatternSpec dylib_extension_pattern("*.dylib"); + find_matching_files_in_search_path (control_protocol_search_path (), + dll_extension_pattern, cp_modules); + find_matching_files_in_search_path (control_protocol_search_path (), so_extension_pattern, cp_modules); diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc index 947c66e756..010905d120 100644 --- a/libs/ardour/coreaudiosource.cc +++ b/libs/ardour/coreaudiosource.cc @@ -28,6 +28,8 @@ #include #include +#include + #include "i18n.h" #include @@ -36,21 +38,32 @@ using namespace std; using namespace ARDOUR; using namespace PBD; +/** Create a new CoreAudioSource using session state, which implies that the + * file must already exist. + */ CoreAudioSource::CoreAudioSource (Session& s, const XMLNode& node) : Source (s, node) , AudioFileSource (s, node) { init_cafile (); + + assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)); + existence_check (); } +/** Create a new CoreAudioSource from an existing file. Sources created with this + * method are never writable or removable. + */ CoreAudioSource::CoreAudioSource (Session& s, const string& path, int chn, Flag flags) - /* files created this way are never writable or removable */ : Source (s, DataType::AUDIO, path, Source::Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy))), AudioFileSource (s, path, Source::Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy))) { _channel = chn; init_cafile (); + + assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)); + existence_check (); } void diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc index 288a4b7034..109539ce2d 100644 --- a/libs/ardour/file_source.cc +++ b/libs/ardour/file_source.cc @@ -62,8 +62,6 @@ FileSource::FileSource (Session& session, DataType type, const string& path, con , _open (false) { set_within_session_from_path (path); - - prevent_deletion (); } FileSource::FileSource (Session& session, const XMLNode& node, bool /*must_exist*/) @@ -77,23 +75,28 @@ FileSource::FileSource (Session& session, const XMLNode& node, bool /*must_exist _path = _name; _within_session = true; +} - prevent_deletion (); +FileSource::~FileSource() +{ +} + +void +FileSource::existence_check () +{ + if (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)) { + prevent_deletion (); + } } void FileSource::prevent_deletion () { - /* if this file already exists, it cannot be removed, ever - */ - - if (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)) { - if (!(_flags & Destructive)) { - mark_immutable (); - } else { - _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy)); - } - } + if (!(_flags & Destructive)) { + mark_immutable (); + } else { + _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy)); + } } bool @@ -509,35 +512,6 @@ out: return ret; } -int -FileSource::set_source_name (const string& newname, bool destructive) -{ - Glib::Threads::Mutex::Lock lm (_lock); - string oldpath = _path; - string newpath = _session.change_source_path_by_name (oldpath, _name, newname, destructive); - - if (newpath.empty()) { - error << string_compose (_("programming error: %1"), "cannot generate a changed file path") << endmsg; - return -1; - } - - // Test whether newpath exists, if yes notify the user but continue. - if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) { - error << string_compose (_("Programming error! %1 tried to rename a file over another file! It's safe to continue working, but please report this to the developers."), PROGRAM_NAME) << endmsg; - return -1; - } - - if (::rename (oldpath.c_str(), newpath.c_str()) != 0) { - error << string_compose (_("cannot rename file %1 to %2 (%3)"), oldpath, newpath, strerror(errno)) << endmsg; - return -1; - } - - _name = Glib::path_get_basename (newpath); - _path = newpath; - - return 0; -} - void FileSource::mark_immutable () { diff --git a/libs/ardour/linux_vst_support.cc b/libs/ardour/linux_vst_support.cc index 9d36905f48..0d976d653b 100644 --- a/libs/ardour/linux_vst_support.cc +++ b/libs/ardour/linux_vst_support.cc @@ -112,7 +112,7 @@ vstfx_new () void* vstfx_load_vst_library(const char* path) { void* dll; - char* full_path; + char* full_path = NULL; char* envdup; char* lxvst_path; size_t len1; @@ -160,6 +160,7 @@ void* vstfx_load_vst_library(const char* path) vstfx_error ("\"%s\"", lxvst_path); len1 = strlen(lxvst_path); + if (full_path) free(full_path); full_path = (char*)malloc(len1 + 1 + len2 + 1); memcpy(full_path, lxvst_path, len1); full_path[len1] = '/'; @@ -180,7 +181,7 @@ void* vstfx_load_vst_library(const char* path) } /*Free the path*/ - + if (full_path) free(full_path); free(envdup); return dll; @@ -209,8 +210,6 @@ vstfx_load (const char *path) buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero sprintf (buf, "%s.so", path); - - fhandle->nameptr = strdup (path); } else @@ -218,8 +217,6 @@ vstfx_load (const char *path) /*We already have .so appened to the filename*/ buf = strdup(path); - - fhandle->nameptr = strdup (path); } /* get a name for the plugin based on the path: ye old VST problem where @@ -227,7 +224,7 @@ vstfx_load (const char *path) which we don't want to do at this point */ - fhandle->name = strdup (PBD::basename_nosuffix (fhandle->nameptr).c_str()); + fhandle->name = strdup (PBD::basename_nosuffix (path).c_str()); /*call load_vstfx_library to actually load the .so into memory*/ @@ -289,9 +286,8 @@ vstfx_unload (VSTHandle* fhandle) fhandle->dll = 0; } - if (fhandle->nameptr) + if (fhandle->name) { - free (fhandle->nameptr); free (fhandle->name); } @@ -310,8 +306,9 @@ vstfx_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr) if(fhandle == 0) { - vstfx_error( "** ERROR ** VSTFX : The handle was 0\n" ); - return 0; + vstfx_error( "** ERROR ** VSTFX : The handle was 0\n" ); + free (vstfx); + return 0; } if ((vstfx->plugin = fhandle->main_entry (amc)) == 0) diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 5c12524d78..33b02a76e3 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -26,12 +26,12 @@ #include #include -#include #include #include #include +#include "pbd/clear_dir.h" #include "pbd/pathscanner.h" #include "pbd/compose.h" #include "pbd/error.h" @@ -881,27 +881,6 @@ LV2Plugin::lv2_state_make_path(LV2_State_Make_Path_Handle handle, return g_strndup(abs_path.c_str(), abs_path.length()); } -static void -remove_directory(const std::string& path) -{ - if (!Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) { - warning << string_compose("\"%1\" is not a directory", path) << endmsg; - return; - } - - Glib::RefPtr dir = Gio::File::create_for_path(path); - Glib::RefPtr e = dir->enumerate_children(); - Glib::RefPtr fi; - while ((fi = e->next_file())) { - if (fi->get_type() == Gio::FILE_TYPE_DIRECTORY) { - remove_directory(fi->get_name()); - } else { - dir->get_child(fi->get_name())->remove(); - } - } - dir->remove(); -} - void LV2Plugin::add_state(XMLNode* root) const { @@ -953,7 +932,7 @@ LV2Plugin::add_state(XMLNode* root) const } else { // State is identical, decrement version and nuke directory lilv_state_free(state); - remove_directory(new_dir); + PBD::remove_directory(new_dir); --_state_version; } diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index a1a640cd1c..4a878c3898 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -1198,7 +1198,7 @@ MidiDiskstream::use_new_write_source (uint32_t n) try { _write_source = boost::dynamic_pointer_cast( - _session.create_midi_source_for_session (0, name ())); + _session.create_midi_source_for_session (name ())); if (!_write_source) { throw failed_constructor(); @@ -1213,25 +1213,36 @@ MidiDiskstream::use_new_write_source (uint32_t n) return 0; } - -list > -MidiDiskstream::steal_write_sources() +/** + * We want to use the name of the existing write source (the one that will be + * used by the next capture) for another purpose. So change the name of the + * current source, and return its current name. + * + * Return an empty string if the change cannot be accomplished. + */ +std::string +MidiDiskstream::steal_write_source_name () { - list > ret; + string our_old_name = _write_source->name(); - /* put some data on the disk, even if its just a header for an empty file */ - boost::dynamic_pointer_cast (_write_source)->ensure_disk_file (); + /* this will bump the name of the current write source to the next one + * (e.g. "MIDI 1-1" gets renamed to "MIDI 1-2"), thus leaving the + * current write source name (e.g. "MIDI 1-1" available). See the + * comments in Session::create_midi_source_by_stealing_name() about why + * we do this. + */ - /* never let it go away */ - _write_source->mark_nonremovable (); - - ret.push_back (_write_source); - - /* get a new one */ - - use_new_write_source (0); - - return ret; + try { + string new_name = _session.new_midi_source_name (name()); + + if (_write_source->rename (new_name)) { + return string(); + } + } catch (...) { + return string (); + } + + return our_old_name; } void diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 716d511798..ef9544589d 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -1252,7 +1252,7 @@ MidiModel::PatchChangePtr MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n) { XMLProperty* prop; - Evoral::event_id_t id; + Evoral::event_id_t id = 0; Evoral::MusicalTime time = 0; int channel = 0; int program = 0; @@ -1284,6 +1284,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n) } PatchChangePtr p (new Evoral::PatchChange (time, channel, program, bank)); + assert(id); p->set_id (id); return p; } diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 8509e55f97..e7298e7526 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -25,6 +25,8 @@ #include #include +#include +#include #include "pbd/xml++.h" #include "pbd/basename.h" @@ -36,6 +38,7 @@ #include "ardour/midi_source.h" #include "ardour/region_factory.h" #include "ardour/session.h" +#include "ardour/source_factory.h" #include "ardour/tempo.h" #include "ardour/types.h" @@ -126,16 +129,31 @@ MidiRegion::~MidiRegion () */ boost::shared_ptr MidiRegion::clone (string path) const +{ + boost::shared_ptr newsrc; + + /* caller must check for pre-existing file */ + assert (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)); + newsrc = boost::dynamic_pointer_cast( + SourceFactory::createWritable(DataType::MIDI, _session, + path, false, _session.frame_rate())); + return clone (newsrc); +} + +boost::shared_ptr +MidiRegion::clone (boost::shared_ptr newsrc) const { BeatsFramesConverter bfc (_session.tempo_map(), _position); Evoral::MusicalTime const bbegin = bfc.from (_start); Evoral::MusicalTime const bend = bfc.from (_start + _length); - boost::shared_ptr ms = midi_source(0)->clone (path, bbegin, bend); + if (midi_source(0)->write_to (newsrc, bbegin, bend)) { + return boost::shared_ptr (); + } PropertyList plist; - plist.add (Properties::name, PBD::basename_nosuffix (ms->name())); + plist.add (Properties::name, PBD::basename_nosuffix (newsrc->name())); plist.add (Properties::whole_file, true); plist.add (Properties::start, _start); plist.add (Properties::start_beats, _start_beats); @@ -143,7 +161,7 @@ MidiRegion::clone (string path) const plist.add (Properties::length_beats, _length_beats); plist.add (Properties::layer, 0); - return boost::dynamic_pointer_cast (RegionFactory::create (ms, plist, true)); + return boost::dynamic_pointer_cast (RegionFactory::create (newsrc, plist, true)); } void diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 1887b74302..655222413a 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -38,6 +38,7 @@ #include "ardour/midi_model.h" #include "ardour/midi_state_tracker.h" #include "ardour/midi_source.h" +#include "ardour/file_source.h" #include "ardour/session.h" #include "ardour/session_directory.h" #include "ardour/source_factory.h" @@ -331,31 +332,9 @@ MidiSource::mark_streaming_write_completed () mark_midi_streaming_write_completed (Evoral::Sequence::DeleteStuckNotes); } -boost::shared_ptr -MidiSource::clone (const string& path, Evoral::MusicalTime begin, Evoral::MusicalTime end) +int +MidiSource::write_to (boost::shared_ptr newsrc, Evoral::MusicalTime begin, Evoral::MusicalTime end) { - string newname = PBD::basename_nosuffix(_name.val()); - string newpath; - - if (path.empty()) { - - /* get a new name for the MIDI file we're going to write to - */ - - do { - newname = bump_name_once (newname, '-'); - newpath = Glib::build_filename (_session.session_directory().midi_path(), newname + ".mid"); - - } while (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)); - } else { - /* caller must check for pre-existing file */ - newpath = path; - } - - boost::shared_ptr newsrc = boost::dynamic_pointer_cast( - SourceFactory::createWritable(DataType::MIDI, _session, - newpath, false, _session.frame_rate())); - newsrc->set_timeline_position(_timeline_position); newsrc->copy_interpolation_from (this); newsrc->copy_automation_state_from (this); @@ -368,7 +347,7 @@ MidiSource::clone (const string& path, Evoral::MusicalTime begin, Evoral::Musica } } else { error << string_compose (_("programming error: %1"), X_("no model for MidiSource during ::clone()")); - return boost::shared_ptr(); + return -1; } newsrc->flush_midi(); @@ -380,8 +359,12 @@ MidiSource::clone (const string& path, Evoral::MusicalTime begin, Evoral::Musica } else { newsrc->set_model (_model); } + + /* this file is not removable (but since it is MIDI, it is mutable) */ - return newsrc; + boost::dynamic_pointer_cast (newsrc)->prevent_deletion (); + + return 0; } void diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index 2db24ed269..7c3eae538f 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -116,10 +116,9 @@ PluginManager::PluginManager () char* s; string lrdf_path; - if (!PBD::find_file_in_search_path ( - PBD::Searchpath(Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst")), - "ardour-vst-scanner", scanner_bin_path)) { - PBD::warning << "VST scanner app not found.'" << endmsg; + string scan_p = Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst"); + if (!PBD::find_file_in_search_path ( PBD::Searchpath(scan_p), "ardour-vst-scanner", scanner_bin_path)) { + PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << scan_p << endmsg; } load_statuses (); diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index bcbf14bdaf..4d7bb5802d 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -3911,7 +3911,7 @@ Route::setup_invisible_processors () ++amp; } - assert (amp != _processors.end ()); + assert (amp != new_processors.end ()); /* and the processor after the amp */ diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 6847220da6..f183694ad7 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -88,6 +88,7 @@ #include "ardour/smf_source.h" #include "ardour/source_factory.h" #include "ardour/speakers.h" +#include "ardour/track.h" #include "ardour/utils.h" #include "midi++/port.h" @@ -3525,12 +3526,16 @@ Session::source_by_id (const PBD::ID& id) return source; } -boost::shared_ptr -Session::source_by_path_and_channel (const string& path, uint16_t chn) +boost::shared_ptr +Session::source_by_path_and_channel (const string& path, uint16_t chn) const { + /* Restricted to audio files because only audio sources have channel + as a property. + */ + Glib::Threads::Mutex::Lock lm (source_lock); - for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) { + for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) { boost::shared_ptr afs = boost::dynamic_pointer_cast(i->second); @@ -3538,7 +3543,31 @@ Session::source_by_path_and_channel (const string& path, uint16_t chn) return afs; } } - return boost::shared_ptr(); + + return boost::shared_ptr(); +} + +boost::shared_ptr +Session::source_by_path (const std::string& path) const +{ + /* Restricted to MIDI files because audio sources require a channel + for unique identification, in addition to a path. + */ + + Glib::Threads::Mutex::Lock lm (source_lock); + + for (SourceMap::const_iterator s = sources.begin(); s != sources.end(); ++s) { + boost::shared_ptr ms + = boost::dynamic_pointer_cast(s->second); + boost::shared_ptr fs + = boost::dynamic_pointer_cast(s->second); + + if (ms && fs && fs->path() == path) { + return ms; + } + } + + return boost::shared_ptr(); } uint32_t @@ -3559,111 +3588,6 @@ Session::count_sources_by_origin (const string& path) return cnt; } - -string -Session::change_source_path_by_name (string path, string oldname, string newname, bool destructive) -{ - string look_for; - string old_basename = PBD::basename_nosuffix (oldname); - string new_legalized = legalize_for_path (newname); - - /* note: we know (or assume) the old path is already valid */ - - if (destructive) { - - /* destructive file sources have a name of the form: - - /path/to/Tnnnn-NAME(%[LR])?.wav - - the task here is to replace NAME with the new name. - */ - - string dir; - string prefix; - string::size_type dash; - - dir = Glib::path_get_dirname (path); - path = Glib::path_get_basename (path); - - /* '-' is not a legal character for the NAME part of the path */ - - if ((dash = path.find_last_of ('-')) == string::npos) { - return ""; - } - - prefix = path.substr (0, dash); - - path += prefix; - path += '-'; - path += new_legalized; - path += native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO); - path = Glib::build_filename (dir, path); - - } else { - - /* non-destructive file sources have a name of the form: - - /path/to/NAME-nnnnn(%[LR])?.ext - - the task here is to replace NAME with the new name. - */ - - string dir; - string suffix; - string::size_type dash; - string::size_type postfix; - - dir = Glib::path_get_dirname (path); - path = Glib::path_get_basename (path); - - /* '-' is not a legal character for the NAME part of the path */ - - if ((dash = path.find_last_of ('-')) == string::npos) { - return ""; - } - - suffix = path.substr (dash+1); - - // Suffix is now everything after the dash. Now we need to eliminate - // the nnnnn part, which is done by either finding a '%' or a '.' - - postfix = suffix.find_last_of ("%"); - if (postfix == string::npos) { - postfix = suffix.find_last_of ('.'); - } - - if (postfix != string::npos) { - suffix = suffix.substr (postfix); - } else { - error << "Logic error in Session::change_source_path_by_name(), please report" << endl; - return ""; - } - - const uint32_t limit = 10000; - char buf[PATH_MAX+1]; - - for (uint32_t cnt = 1; cnt <= limit; ++cnt) { - - snprintf (buf, sizeof(buf), "%s-%u%s", newname.c_str(), cnt, suffix.c_str()); - - if (!matching_unsuffixed_filename_exists_in (dir, buf)) { - path = Glib::build_filename (dir, buf); - break; - } - - path = ""; - } - - if (path.empty()) { - fatal << string_compose (_("FATAL ERROR! Could not find a suitable version of %1 for a rename"), - newname) << endl; - /*NOTREACHED*/ - } - } - - return path; -} - /** Return the full path (in some session directory) for a new within-session source. * \a name must be a session-unique name that does not contain slashes * (e.g. as returned by new_*_source_name) @@ -3767,6 +3691,22 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha existing++; break; } + + /* it is possible that we have the path already + * assigned to a source that has not yet been written + * (ie. the write source for a diskstream). we have to + * check this in order to make sure that our candidate + * path isn't used again, because that can lead to + * two Sources point to the same file with different + * notions of their removability. + */ + + string possible_path = Glib::build_filename (spath, buf); + + if (source_by_path (possible_path)) { + existing++; + break; + } } if (existing == 0) { @@ -3796,19 +3736,21 @@ Session::create_audio_source_for_session (size_t n_chans, string const & n, uint SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate())); } -/** Return a unique name based on \a base for a new internal MIDI source */ +/** Return a unique name based on \a owner_name for a new internal MIDI source */ string -Session::new_midi_source_name (const string& base) +Session::new_midi_source_name (const string& owner_name) { uint32_t cnt; char buf[PATH_MAX+1]; const uint32_t limit = 10000; string legalized; + string possible_name; buf[0] = '\0'; - legalized = legalize_for_path (base); + legalized = legalize_for_path (owner_name); // Find a "version" of the file name that doesn't exist in any of the possible directories. + for (cnt = 1; cnt <= limit; ++cnt) { vector::iterator i; @@ -3817,12 +3759,17 @@ Session::new_midi_source_name (const string& base) for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { SessionDirectory sdir((*i).path); + + snprintf (buf, sizeof(buf), "%s-%u.mid", legalized.c_str(), cnt); + possible_name = buf; - std::string p = Glib::build_filename (sdir.midi_path(), legalized); + std::string possible_path = Glib::build_filename (sdir.midi_path(), possible_name); + + if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) { + existing++; + } - snprintf (buf, sizeof(buf), "%s-%u.mid", p.c_str(), cnt); - - if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) { + if (source_by_path (possible_path)) { existing++; } } @@ -3834,37 +3781,64 @@ Session::new_midi_source_name (const string& base) if (cnt > limit) { error << string_compose( _("There are already %1 recordings for %2, which I consider too many."), - limit, base) << endmsg; + limit, owner_name) << endmsg; destroy (); throw failed_constructor(); } } - return Glib::path_get_basename(buf); + return possible_name; } /** Create a new within-session MIDI source */ boost::shared_ptr -Session::create_midi_source_for_session (Track* track, string const & n) +Session::create_midi_source_for_session (string const & basic_name) { - /* try to use the existing write source for the track, to keep numbering sane - */ + std::string name; - if (track) { - /*MidiTrack* mt = dynamic_cast (track); - assert (mt); - */ - - list > l = track->steal_write_sources (); - - if (!l.empty()) { - assert (boost::dynamic_pointer_cast (l.front())); - return boost::dynamic_pointer_cast (l.front()); - } + if (name.empty()) { + name = new_midi_source_name (basic_name); + } + + const string path = new_source_path_from_name (DataType::MIDI, name); + + return boost::dynamic_pointer_cast ( + SourceFactory::createWritable ( + DataType::MIDI, *this, path, false, frame_rate())); +} + +/** Create a new within-session MIDI source */ +boost::shared_ptr +Session::create_midi_source_by_stealing_name (boost::shared_ptr track) +{ + /* the caller passes in the track the source will be used in, + so that we can keep the numbering sane. + + Rationale: a track with the name "Foo" that has had N + captures carried out so far will ALREADY have a write source + named "Foo-N+1.mid" waiting to be used for the next capture. + + If we call new_midi_source_name() we will get "Foo-N+2". But + there is no region corresponding to "Foo-N+1", so when + "Foo-N+2" appears in the track, the gap presents the user + with odd behaviour - why did it skip past Foo-N+1? + + We could explain this to the user in some odd way, but + instead we rename "Foo-N+1.mid" as "Foo-N+2.mid", and then + use "Foo-N+1" here. + + If that attempted rename fails, we get "Foo-N+2.mid" anyway. + */ + + boost::shared_ptr mt = boost::dynamic_pointer_cast (track); + assert (mt); + std::string name = track->steal_write_source_name (); + + if (name.empty()) { + return boost::shared_ptr(); } - const string name = new_midi_source_name (n); const string path = new_source_path_from_name (DataType::MIDI, name); return boost::dynamic_pointer_cast ( diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 0e920ec6e0..af5e8841bf 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -802,7 +802,7 @@ Session::load_state (string snapshot_name) set_dirty(); - _writable = exists_and_writable (xmlpath); + _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath)); if (!state_tree->read (xmlpath)) { error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg; @@ -920,7 +920,7 @@ Session::state (bool full_state) p += (*i).path; if (next != session_dirs.end()) { - p += ':'; + p += G_SEARCHPATH_SEPARATOR; } else { break; } @@ -2684,7 +2684,7 @@ Session::cleanup_sources (CleanupReport& rep) audio_path += sdir.sound_path(); if (nexti != session_dirs.end()) { - audio_path += ':'; + audio_path += G_SEARCHPATH_SEPARATOR; } i = nexti; @@ -2702,7 +2702,7 @@ Session::cleanup_sources (CleanupReport& rep) midi_path += sdir.midi_path(); if (nexti != session_dirs.end()) { - midi_path += ':'; + midi_path += G_SEARCHPATH_SEPARATOR; } i = nexti; diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index c504f50006..812e06c27b 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -63,9 +63,12 @@ SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags) { /* note that origin remains empty */ - if (init(_path, false)) { + if (init (_path, false)) { throw failed_constructor (); } + + assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS)); + existence_check (); /* file is not opened until write */ @@ -73,9 +76,10 @@ SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags) return; } - if (open(_path)) { + if (open (_path)) { throw failed_constructor (); } + _open = true; } @@ -93,10 +97,13 @@ SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist) throw failed_constructor (); } - if (init(_path, true)) { + if (init (_path, true)) { throw failed_constructor (); } + assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)); + existence_check (); + if (open(_path)) { throw failed_constructor (); } @@ -658,3 +665,44 @@ SMFSource::ensure_disk_file () } } +void +SMFSource::prevent_deletion () +{ + /* Unlike the audio case, the MIDI file remains mutable (because we can + edit MIDI data) + */ + + _flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy)); +} + +int +SMFSource::rename (const string& newname) +{ + Glib::Threads::Mutex::Lock lm (_lock); + string oldpath = _path; + string newpath = _session.new_source_path_from_name (DataType::MIDI, newname); + + if (newpath.empty()) { + error << string_compose (_("programming error: %1"), "cannot generate a changed file path") << endmsg; + return -1; + } + + // Test whether newpath exists, if yes notify the user but continue. + if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) { + error << string_compose (_("Programming error! %1 tried to rename a file over another file! It's safe to continue working, but please report this to the developers."), PROGRAM_NAME) << endmsg; + return -1; + } + + if (Glib::file_test (oldpath.c_str(), Glib::FILE_TEST_EXISTS)) { + /* rename only needed if file exists on disk */ + if (::rename (oldpath.c_str(), newpath.c_str()) != 0) { + error << string_compose (_("cannot rename file %1 to %2 (%3)"), oldpath, newpath, strerror(errno)) << endmsg; + return -1; + } + } + + _name = Glib::path_get_basename (newpath); + _path = newpath; + + return 0; +} diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index 1c3144f164..e0851602fc 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -31,6 +31,7 @@ #ifdef PLATFORM_WINDOWS #include #endif +#include #include #include "ardour/sndfilesource.h" @@ -57,39 +58,70 @@ const Source::Flag SndFileSource::default_writable_flags = Source::Flag ( SndFileSource::SndFileSource (Session& s, const XMLNode& node) : Source(s, node) , AudioFileSource (s, node) + , _descriptor (0) + , _broadcast_info (0) + , _capture_start (false) + , _capture_end (false) + , file_pos (0) + , xfade_buf (0) { init_sndfile (); + assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)); + existence_check (); + if (open()) { throw failed_constructor (); } } -/** Files created this way are never writable or removable */ +/** Constructor for existing external-to-session files. + Files created this way are never writable or removable +*/ SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags) : Source(s, DataType::AUDIO, path, flags) /* note that the origin of an external file is itself */ , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy))) + , _descriptor (0) + , _broadcast_info (0) + , _capture_start (false) + , _capture_end (false) + , file_pos (0) + , xfade_buf (0) { _channel = chn; init_sndfile (); + assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)); + existence_check (); + if (open()) { throw failed_constructor (); } } -/** This constructor is used to construct new files, not open existing ones. */ +/** This constructor is used to construct new internal-to-session files, + not open existing ones. +*/ SndFileSource::SndFileSource (Session& s, const string& path, const string& origin, SampleFormat sfmt, HeaderFormat hf, framecnt_t rate, Flag flags) : Source(s, DataType::AUDIO, path, flags) , AudioFileSource (s, path, origin, flags, sfmt, hf) + , _descriptor (0) + , _broadcast_info (0) + , _capture_start (false) + , _capture_end (false) + , file_pos (0) + , xfade_buf (0) { int fmt = 0; init_sndfile (); + assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS)); + existence_check (); + _file_is_new = true; switch (hf) { @@ -156,24 +188,12 @@ SndFileSource::SndFileSource (Session& s, const string& path, const string& orig void SndFileSource::init_sndfile () { - string file; - - _descriptor = 0; - - // lets try to keep the object initalizations here at the top - xfade_buf = 0; - _broadcast_info = 0; - /* although libsndfile says we don't need to set this, valgrind and source code shows us that we do. */ memset (&_info, 0, sizeof(_info)); - _capture_start = false; - _capture_end = false; - file_pos = 0; - if (destructive()) { xfade_buf = new Sample[xfade_frames]; _timeline_position = header_position_offset; diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 57239cb841..5c95de0c41 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -579,10 +579,10 @@ Track::set_capture_offset () _diskstream->set_capture_offset (); } -list > -Track::steal_write_sources() +std::string +Track::steal_write_source_name() { - return _diskstream->steal_write_sources (); + return _diskstream->steal_write_source_name (); } void diff --git a/libs/ardour/vst_info_file.cc b/libs/ardour/vst_info_file.cc index b005190e8f..bf9d196e61 100644 --- a/libs/ardour/vst_info_file.cc +++ b/libs/ardour/vst_info_file.cc @@ -34,7 +34,6 @@ #include #include #include -#include #include #include diff --git a/libs/ardour/worker.cc b/libs/ardour/worker.cc index d5238adb60..aea1c6f8e3 100644 --- a/libs/ardour/worker.cc +++ b/libs/ardour/worker.cc @@ -82,6 +82,9 @@ Worker::verify_message_completeness(RingBuffer* rb) uint32_t size; RingBuffer::rw_vector vec; rb->get_read_vector (&vec); + if (vec.len[0] + vec.len[1] < sizeof(size)) { + return false; + } if (vec.len[0] >= sizeof(size)) { memcpy (&size, vec.buf[0], sizeof (size)); } else { @@ -121,6 +124,7 @@ Worker::run() while (true) { _sem.wait(); if (_exit) { + if (buf) free(buf); return; } @@ -132,6 +136,7 @@ Worker::run() while (!verify_message_completeness(_requests)) { Glib::usleep(2000); if (_exit) { + if (buf) free(buf); return; } } @@ -143,7 +148,13 @@ Worker::run() if (size > buf_size) { buf = realloc(buf, size); - buf_size = size; + if (buf) { + buf_size = size; + } else { + PBD::error << "Worker: Error allocating memory" + << endmsg; + buf_size = 0; // TODO: This is probably fatal + } } if (_requests->read((uint8_t*)buf, size) < size) { diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 260c334a30..0302289820 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -377,7 +377,7 @@ def build(bld): obj.includes += [ '../fst' ] obj.defines += [ 'WINDOWS_VST_SUPPORT' ] if bld.env['build_target'] == 'mingw': - obj.source += [ '../fst/vstwin.c', '../fst/fst.c'] + obj.source += [ '../fst/vstwin.c'] obj.uselib += ['GDI32'] if bld.is_defined('LXVST_SUPPORT'): @@ -419,7 +419,7 @@ def build(bld): testcommon.uselib = ['CPPUNIT','SIGCPP','GLIBMM','GTHREAD', 'SAMPLERATE','XML','LRDF','COREAUDIO','TAGLIB','VAMPSDK','VAMPHOSTSDK','RUBBERBAND'] testcommon.use = ['libpbd','libmidipp','libevoral', - 'libaudiographer','ardour'] + 'libaudiographer','libardour'] if bld.is_defined('USE_EXTERNAL_LIBS'): testcommon.uselib.extend(['LIBLTC',]) else: @@ -499,7 +499,7 @@ def build(bld): session_load_tester.includes.append ('test') session_load_tester.uselib = ['CPPUNIT','SIGCPP','GLIBMM','GTHREAD', 'SAMPLERATE','XML','LRDF','COREAUDIO'] - session_load_tester.use = ['libpbd','libmidipp','ardour'] + session_load_tester.use = ['libpbd','libmidipp','libardour'] session_load_tester.name = 'libardour-session-load-tester' session_load_tester.target = 'load-session' session_load_tester.install_path = '' @@ -532,7 +532,7 @@ def build(bld): profilingobj.includes.append ('test') profilingobj.uselib = ['CPPUNIT','SIGCPP','GLIBMM','GTHREAD', 'SAMPLERATE','XML','LRDF','COREAUDIO'] - profilingobj.use = ['libpbd','libmidipp','ardour'] + profilingobj.use = ['libpbd','libmidipp','libardour'] profilingobj.name = 'libardour-profiling' profilingobj.target = p profilingobj.install_path = '' @@ -558,7 +558,7 @@ def create_ardour_test_program(bld, includes, name, target, sources): testobj.uselib = ['CPPUNIT','SIGCPP','GLIBMM','GTHREAD', 'SAMPLERATE','XML','LRDF','COREAUDIO','TAGLIB','VAMPSDK','VAMPHOSTSDK','RUBBERBAND'] testobj.use = ['libpbd','libmidipp','libevoral', - 'libaudiographer','ardour','testcommon'] + 'libaudiographer','libardour','testcommon'] if bld.is_defined('USE_EXTERNAL_LIBS'): testobj.uselib.extend(['LIBLTC']) else: diff --git a/libs/evoral/evoral/Note.hpp b/libs/evoral/evoral/Note.hpp index e84d6b9dc4..5401271621 100644 --- a/libs/evoral/evoral/Note.hpp +++ b/libs/evoral/evoral/Note.hpp @@ -33,7 +33,11 @@ namespace Evoral { * Currently a note is defined as (on event, length, off event). */ template +#ifdef COMPILER_MSVC +class LIBEVORAL_LOCAL Note { +#else class LIBEVORAL_TEMPLATE_API Note { +#endif public: Note(uint8_t chan=0, Time time=0, Time len=0, uint8_t note=0, uint8_t vel=0x40); Note(const Note