diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2013-10-22 15:29:44 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2013-10-22 15:29:44 -0400 |
commit | 664e715a002450ac0f079411f6f051c122a4322a (patch) | |
tree | 762f2a060843f77504ff39e2257ed4f32e6f83a1 | |
parent | f86599cd74197ceb3e2e5cfe80a9a2dd5ee4201a (diff) | |
parent | 61e66bb7631fc070a629d83e91855f58d7fb2489 (diff) |
merge from master
54 files changed, 1105 insertions, 370 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 43fd6bf11f..7921dc4274 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -101,6 +101,7 @@ typedef uint64_t microseconds_t; #include "missing_plugin_dialog.h" #include "mixer_ui.h" #include "mouse_cursors.h" +#include "nsm.h" #include "opts.h" #include "pingback.h" #include "processor_box.h" @@ -832,13 +833,6 @@ ARDOUR_UI::starting () } void -ARDOUR_UI::no_memory_warning () -{ - XMLNode node (X_("no-memory-warning")); - Config->add_instant_xml (node); -} - -void ARDOUR_UI::check_memory_locking () { #ifdef __APPLE__ @@ -894,9 +888,6 @@ ARDOUR_UI::check_memory_locking () VBox* vbox = msg.get_vbox(); HBox hbox; CheckButton cb (_("Do not show this window again")); - - cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning)); - hbox.pack_start (cb, true, false); vbox->pack_start (hbox); cb.show(); @@ -907,6 +898,11 @@ ARDOUR_UI::check_memory_locking () editor->ensure_float (msg); msg.run (); + + if (cb.get_active()) { + XMLNode node (X_("no-memory-warning")); + Config->add_instant_xml (node); + } } } } @@ -3741,8 +3737,8 @@ ARDOUR_UI::session_dialog (std::string msg) int ARDOUR_UI::pending_state_dialog () { - HBox* hbox = new HBox(); - Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG); + HBox* hbox = manage (new HBox()); + Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG)); ArdourDialog dialog (_("Crash Recovery"), true); Label message (string_compose (_("\ This session appears to have been in the\n\ diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 1052ee23a6..9de5df3b9c 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -71,7 +71,6 @@ #include "ardour_window.h" #include "editing.h" #include "meterbridge.h" -#include "nsm.h" #include "ui_config.h" #include "enums.h" #include "visibility_group.h" @@ -104,6 +103,7 @@ class SpeakerDialog; class ThemeManager; class TimeInfoBox; class MidiTracer; +class NSM_Client; class LevelMeterHBox; class GlobalPortMatrixWindow; class GUIObjectState; @@ -691,7 +691,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr bool first_idle (); - void no_memory_warning (); void check_memory_locking (); bool check_audioengine(); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index d9580c1eeb..01d81a156d 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -450,7 +450,7 @@ struct EditorOrderTimeAxisViewSorter { RouteTimeAxisView* ra = dynamic_cast<RouteTimeAxisView*> (a); RouteTimeAxisView* rb = dynamic_cast<RouteTimeAxisView*> (b); assert (ra && rb); - return ra->route()->order_key (EditorSort) < rb->route()->order_key (EditorSort); + return ra->route()->order_key () < rb->route()->order_key (); } }; diff --git a/gtk2_ardour/editor_group_tabs.cc b/gtk2_ardour/editor_group_tabs.cc index 997a115b71..d02181c9b6 100644 --- a/gtk2_ardour/editor_group_tabs.cc +++ b/gtk2_ardour/editor_group_tabs.cc @@ -176,12 +176,6 @@ EditorGroupTabs::default_properties () const return plist; } -RouteSortOrderKey -EditorGroupTabs::order_key () const -{ - return EditorSort; -} - RouteList EditorGroupTabs::selected_routes () const { diff --git a/gtk2_ardour/editor_group_tabs.h b/gtk2_ardour/editor_group_tabs.h index a0021e4833..3d15ef73c3 100644 --- a/gtk2_ardour/editor_group_tabs.h +++ b/gtk2_ardour/editor_group_tabs.h @@ -37,7 +37,6 @@ private: } void add_menu_items (Gtk::Menu *, ARDOUR::RouteGroup *); PBD::PropertyList default_properties () const; - ARDOUR::RouteSortOrderKey order_key () const; ARDOUR::RouteList selected_routes () const; void sync_order_keys (); }; diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 6ef4cebf6b..42d63ccc2d 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -5520,7 +5520,7 @@ Editor::split_region () struct EditorOrderRouteSorter { bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) { - return a->order_key (EditorSort) < b->order_key (EditorSort); + return a->order_key () < b->order_key (); } }; diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc index 10f2c3f5ed..515ad07972 100644 --- a/gtk2_ardour/editor_routes.cc +++ b/gtk2_ardour/editor_routes.cc @@ -284,7 +284,7 @@ EditorRoutes::EditorRoutes (Editor* e) _display.set_enable_search (false); - Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this, _1), gui_context()); + Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this), gui_context()); } bool @@ -810,7 +810,7 @@ EditorRoutes::show_track_in_display (TimeAxisView& tv) void EditorRoutes::reset_remote_control_ids () { - if (Config->get_remote_model() != EditorOrdered || !_session || _session->deletion_in_progress()) { + if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) { return; } @@ -839,7 +839,7 @@ EditorRoutes::reset_remote_control_ids () uint32_t new_rid = (visible ? rid : invisible_key--); if (new_rid != route->remote_control_id()) { - route->set_remote_control_id_from_order_key (EditorSort, new_rid); + route->set_remote_control_id_explicit (new_rid); rid_change = true; } @@ -885,20 +885,20 @@ EditorRoutes::sync_order_keys_from_treeview () boost::shared_ptr<Route> route = (*ri)[_columns.route]; bool visible = (*ri)[_columns.visible]; - uint32_t old_key = route->order_key (EditorSort); + uint32_t old_key = route->order_key (); if (order != old_key) { - route->set_order_key (EditorSort, order); + route->set_order_key (order); changed = true; } - if ((Config->get_remote_model() == EditorOrdered) && !route->is_master() && !route->is_monitor()) { + if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) { uint32_t new_rid = (visible ? rid : invisible_key--); if (new_rid != route->remote_control_id()) { - route->set_remote_control_id_from_order_key (EditorSort, new_rid); + route->set_remote_control_id_explicit (new_rid); rid_change = true; } @@ -913,7 +913,7 @@ EditorRoutes::sync_order_keys_from_treeview () if (changed) { /* tell the world that we changed the editor sort keys */ - _session->sync_order_keys (EditorSort); + _session->sync_order_keys (); } if (rid_change) { @@ -923,37 +923,17 @@ EditorRoutes::sync_order_keys_from_treeview () } void -EditorRoutes::sync_treeview_from_order_keys (RouteSortOrderKey src) +EditorRoutes::sync_treeview_from_order_keys () { - /* Some route order key(s) for `src' has been changed, make sure that + /* Some route order key(s) have been changed, make sure that we update out tree/list model and GUI to reflect the change. */ - if (!_session || _session->deletion_in_progress()) { + if (_ignore_reorder || !_session || _session->deletion_in_progress()) { return; } - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor sync model from order keys, src = %1\n", enum_2_string (src))); - - if (src == MixerSort) { - - if (!Config->get_sync_all_route_ordering()) { - /* mixer sort keys changed - we don't care */ - return; - } - - DEBUG_TRACE (DEBUG::OrderKeys, "reset editor order key to match mixer\n"); - - /* mixer sort keys were changed, update the editor sort - * keys since "sync mixer+editor order" is enabled. - */ - - boost::shared_ptr<RouteList> r = _session->get_routes (); - - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - (*i)->sync_order_keys (src); - } - } + DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from order keys.\n"); /* we could get here after either a change in the Mixer or Editor sort * order, but either way, the mixer order keys reflect the intended @@ -973,7 +953,7 @@ EditorRoutes::sync_treeview_from_order_keys (RouteSortOrderKey src) for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) { boost::shared_ptr<Route> route = (*ri)[_columns.route]; - sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key (EditorSort))); + sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key ())); } SortByNewDisplayOrder cmp; @@ -1339,7 +1319,7 @@ struct EditorOrderRouteSorter { /* everything else before master */ return false; } - return a->order_key (EditorSort) < b->order_key (EditorSort); + return a->order_key () < b->order_key (); } }; @@ -1499,7 +1479,7 @@ EditorRoutes::move_selected_tracks (bool up) } for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) { - uint32_t order = leading->second->order_key (EditorSort); + uint32_t order = leading->second->order_key (); neworder.push_back (order); } diff --git a/gtk2_ardour/editor_routes.h b/gtk2_ardour/editor_routes.h index 6118a2b057..e07a7787aa 100644 --- a/gtk2_ardour/editor_routes.h +++ b/gtk2_ardour/editor_routes.h @@ -72,7 +72,7 @@ private: void on_tv_solo_safe_toggled (std::string const &); void build_menu (); void show_menu (); - void sync_treeview_from_order_keys (ARDOUR::RouteSortOrderKey); + void sync_treeview_from_order_keys (); void route_deleted (Gtk::TreeModel::Path const &); void visible_changed (std::string const &); void active_changed (std::string const &); diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 065cfdbcba..59425b289c 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -779,7 +779,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op) RouteTimeAxisView* closest = 0; int distance = INT_MAX; - int key = rtv->route()->order_key (EditorSort); + int key = rtv->route()->order_key (); for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) { @@ -794,7 +794,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op) if (result.second) { /* newly added to already_in_selection */ - int d = artv->route()->order_key (EditorSort); + int d = artv->route()->order_key (); d -= key; @@ -810,7 +810,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op) /* now add all tracks between that one and this one */ - int okey = closest->route()->order_key (EditorSort); + int okey = closest->route()->order_key (); if (okey > key) { swap (okey, key); @@ -820,7 +820,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op) RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x); if (artv && artv != rtv) { - int k = artv->route()->order_key (EditorSort); + int k = artv->route()->order_key (); if (k >= okey && k <= key) { diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index b6306ae285..37c29f4187 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -822,7 +822,7 @@ EngineControl::EngineControl () set_popdown_strings (sample_rate_combo, s); if (desired.empty()) { - sample_rate_combo.set_active_text (s.front()); + sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate())); } else { sample_rate_combo.set_active_text (desired); } @@ -859,7 +859,7 @@ EngineControl::EngineControl () buffer_size_combo.set_sensitive (true); set_popdown_strings (buffer_size_combo, s); - buffer_size_combo.set_active_text (s.front()); + buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size())); show_buffer_duration (); } else { buffer_size_combo.set_sensitive (false); diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc index 100ab5337e..ef29c01d46 100644 --- a/gtk2_ardour/generic_pluginui.cc +++ b/gtk2_ardour/generic_pluginui.cc @@ -490,6 +490,32 @@ GenericPluginUI::integer_printer (char buf[32], Adjustment &adj, ControlUI* cui) return true; } +bool +GenericPluginUI::midinote_printer (char buf[32], Adjustment &adj, ControlUI* cui) +{ + float const v = adj.get_value (); + + if (cui->scale_points) { + Plugin::ScalePoints::const_iterator i = cui->scale_points->begin (); + while (i != cui->scale_points->end() && i->second != v) { + ++i; + } + + if (i != cui->scale_points->end ()) { + snprintf (buf, 32, "%s", i->first.c_str()); + return true; + } + } + if (v >= 0 && v <= 127) { + int mn = rint(v); + const char notename[12][3] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; + snprintf (buf, 32, "%s %d", notename[mn%12], (mn/12)-2); + } else { + snprintf (buf, 32, "%.0f", v); + } + return true; +} + void GenericPluginUI::print_parameter (char *buf, uint32_t len, uint32_t param) { @@ -610,7 +636,12 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr<Automat if (desc.integer_step) { control_ui->clickbox = new ClickBox (adj, "PluginUIClickBox"); Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->clickbox, "g9999999", 2, 2); - control_ui->clickbox->set_printer (sigc::bind (sigc::mem_fun (*this, &GenericPluginUI::integer_printer), control_ui)); + if (desc.midinote) { + printf("MIDI NOTE\n"); + control_ui->clickbox->set_printer (sigc::bind (sigc::mem_fun (*this, &GenericPluginUI::midinote_printer), control_ui)); + } else { + control_ui->clickbox->set_printer (sigc::bind (sigc::mem_fun (*this, &GenericPluginUI::integer_printer), control_ui)); + } } else { //sigc::slot<void,char*,uint32_t> pslot = sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::print_parameter), (uint32_t) port_index); diff --git a/gtk2_ardour/group_tabs.cc b/gtk2_ardour/group_tabs.cc index b8d30dc989..2394b9a6c5 100644 --- a/gtk2_ardour/group_tabs.cc +++ b/gtk2_ardour/group_tabs.cc @@ -447,23 +447,15 @@ GroupTabs::un_subgroup (RouteGroup* g) } struct CollectSorter { - CollectSorter (RouteSortOrderKey key) : _key (key) {} - bool operator () (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) { - return a->order_key (_key) < b->order_key (_key); + return a->order_key () < b->order_key (); } - - RouteSortOrderKey _key; }; struct OrderSorter { - OrderSorter (RouteSortOrderKey key) : _key (key) {} - bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) { - return a->order_key (_key) < b->order_key (_key); + return a->order_key () < b->order_key (); } - - RouteSortOrderKey _key; }; /** Collect all members of a RouteGroup so that they are together in the Editor or Mixer. @@ -473,19 +465,19 @@ void GroupTabs::collect (RouteGroup* g) { boost::shared_ptr<RouteList> group_routes = g->route_list (); - group_routes->sort (CollectSorter (order_key ())); + group_routes->sort (CollectSorter ()); int const N = group_routes->size (); RouteList::iterator i = group_routes->begin (); boost::shared_ptr<RouteList> routes = _session->get_routes (); - routes->sort (OrderSorter (order_key ())); + routes->sort (OrderSorter ()); RouteList::const_iterator j = routes->begin (); int diff = 0; int coll = -1; while (i != group_routes->end() && j != routes->end()) { - int const k = (*j)->order_key (order_key ()); + int const k = (*j)->order_key (); if (*i == *j) { @@ -496,14 +488,14 @@ GroupTabs::collect (RouteGroup* g) --diff; } - (*j)->set_order_key (order_key (), coll); + (*j)->set_order_key (coll); ++coll; ++i; } else { - (*j)->set_order_key (order_key (), k + diff); + (*j)->set_order_key (k + diff); } diff --git a/gtk2_ardour/group_tabs.h b/gtk2_ardour/group_tabs.h index 39ac42c9d5..d61358ead5 100644 --- a/gtk2_ardour/group_tabs.h +++ b/gtk2_ardour/group_tabs.h @@ -92,7 +92,6 @@ private: virtual void add_menu_items (Gtk::Menu *, ARDOUR::RouteGroup *) {} virtual PBD::PropertyList default_properties () const = 0; - virtual ARDOUR::RouteSortOrderKey order_key () const = 0; virtual ARDOUR::RouteList selected_routes () const = 0; virtual void sync_order_keys () = 0; diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc index ceb6ceb312..d01bca2a62 100644 --- a/gtk2_ardour/main.cc +++ b/gtk2_ardour/main.cc @@ -153,7 +153,7 @@ fixup_bundle_environment (int, char* []) vector<string> lpath; lpath.push_back (bundle_dir); - lpath.push_back ("share"); + lpath.push_back ("Resources"); lpath.push_back ("locale"); localedir = strdup (Glib::build_filename (lpath).c_str()); } @@ -172,9 +172,9 @@ fixup_bundle_environment (int, char* []) export_search_path (bundle_dir, "ARDOUR_INSTANT_XML_PATH", "/Resources"); export_search_path (bundle_dir, "LADSPA_PATH", "/Plugins"); export_search_path (bundle_dir, "VAMP_PATH", "/lib"); - export_search_path (bundle_dir, "SUIL_MODULE_DIR", "/lib"); export_search_path (bundle_dir, "GTK_PATH", "/lib/gtkengines"); + setenv ("SUIL_MODULE_DIR", (bundle_dir + "/lib").c_str(), 1); setenv ("PATH", (bundle_dir + "/MacOS:" + std::string(getenv ("PATH"))).c_str(), 1); /* unset GTK_RC_FILES so that we only load the RC files that we define @@ -282,9 +282,9 @@ fixup_bundle_environment (int /*argc*/, char* argv[]) export_search_path (dir_path, "ARDOUR_DATA_PATH", "/share"); export_search_path (dir_path, "LADSPA_PATH", "/plugins"); export_search_path (dir_path, "VAMP_PATH", "/lib"); - export_search_path (dir_path, "SUIL_MODULE_DIR", "/lib"); export_search_path (dir_path, "GTK_PATH", "/lib/gtkengines"); + setenv ("SUIL_MODULE_DIR", (dir_path + "/lib").c_str(), 1); setenv ("PATH", (dir_path + "/bin:" + std::string(getenv ("PATH"))).c_str(), 1); /* unset GTK_RC_FILES so that we only load the RC files that we define diff --git a/gtk2_ardour/meterbridge.cc b/gtk2_ardour/meterbridge.cc index 8756089e00..4d2a0c7b3b 100644 --- a/gtk2_ardour/meterbridge.cc +++ b/gtk2_ardour/meterbridge.cc @@ -92,7 +92,7 @@ struct SignalOrderRouteSorter { /* everything comes before b */ return true; } - return a->order_key (MixerSort) < b->order_key (MixerSort); + return a->order_key () < b->order_key (); } }; @@ -138,7 +138,7 @@ Meterbridge::Meterbridge () signal_delete_event().connect (sigc::mem_fun (*this, &Meterbridge::hide_window)); signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler)); - Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Meterbridge::sync_order_keys, this, _1), gui_context()); + Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Meterbridge::sync_order_keys, this), gui_context()); MeterStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Meterbridge::remove_strip, this, _1), gui_context()); MeterStrip::MetricChanged.connect (*this, invalidator (*this), boost::bind(&Meterbridge::resync_order, this), gui_context()); MeterStrip::ConfigurationChanged.connect (*this, invalidator (*this), boost::bind(&Meterbridge::queue_resize, this), gui_context()); @@ -637,7 +637,7 @@ Meterbridge::remove_strip (MeterStrip* strip) } void -Meterbridge::sync_order_keys (RouteSortOrderKey) +Meterbridge::sync_order_keys () { Glib::Threads::Mutex::Lock lm (_resync_mutex); @@ -776,7 +776,7 @@ Meterbridge::sync_order_keys (RouteSortOrderKey) void Meterbridge::resync_order() { - sync_order_keys(MixerSort); + sync_order_keys(); } void diff --git a/gtk2_ardour/meterbridge.h b/gtk2_ardour/meterbridge.h index 2fac91cd0a..1709455ae4 100644 --- a/gtk2_ardour/meterbridge.h +++ b/gtk2_ardour/meterbridge.h @@ -80,7 +80,7 @@ class Meterbridge : void remove_strip (MeterStrip *); void session_going_away (); - void sync_order_keys (ARDOUR::RouteSortOrderKey src); + void sync_order_keys (); void resync_order (); mutable Glib::Threads::Mutex _resync_mutex; @@ -107,7 +107,7 @@ class Meterbridge : /* everything comes before b */ return true; } - return a->order_key (ARDOUR::MixerSort) < b->order_key (ARDOUR::MixerSort); + return a->order_key () < b->order_key (); } }; diff --git a/gtk2_ardour/mixer_group_tabs.cc b/gtk2_ardour/mixer_group_tabs.cc index 4a56b01fcd..5878c3d3ac 100644 --- a/gtk2_ardour/mixer_group_tabs.cc +++ b/gtk2_ardour/mixer_group_tabs.cc @@ -170,12 +170,6 @@ MixerGroupTabs::default_properties () const return plist; } -RouteSortOrderKey -MixerGroupTabs::order_key () const -{ - return MixerSort; -} - RouteList MixerGroupTabs::selected_routes () const { diff --git a/gtk2_ardour/mixer_group_tabs.h b/gtk2_ardour/mixer_group_tabs.h index 0999dd9808..290e5a3958 100644 --- a/gtk2_ardour/mixer_group_tabs.h +++ b/gtk2_ardour/mixer_group_tabs.h @@ -36,7 +36,6 @@ private: } PBD::PropertyList default_properties () const; - ARDOUR::RouteSortOrderKey order_key () const; ARDOUR::RouteList selected_routes () const; void sync_order_keys (); diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 7e8188cac9..8126a81e85 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -96,7 +96,7 @@ Mixer_UI::Mixer_UI () /* allow this window to become the key focus window */ set_flags (CAN_FOCUS); - Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this, _1), gui_context()); + Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this), gui_context()); scroller.set_can_default (true); set_default (scroller); @@ -408,7 +408,7 @@ Mixer_UI::remove_strip (MixerStrip* strip) void Mixer_UI::reset_remote_control_ids () { - if (Config->get_remote_model() != MixerOrdered || !_session || _session->deletion_in_progress()) { + if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) { return; } @@ -434,7 +434,7 @@ Mixer_UI::reset_remote_control_ids () uint32_t new_rid = (visible ? rid : invisible_key--); if (new_rid != route->remote_control_id()) { - route->set_remote_control_id_from_order_key (MixerSort, new_rid); + route->set_remote_control_id_explicit (new_rid); rid_change = true; } @@ -476,10 +476,10 @@ Mixer_UI::sync_order_keys_from_treeview () boost::shared_ptr<Route> route = (*ri)[track_columns.route]; bool visible = (*ri)[track_columns.visible]; - uint32_t old_key = route->order_key (MixerSort); + uint32_t old_key = route->order_key (); if (order != old_key) { - route->set_order_key (MixerSort, order); + route->set_order_key (order); changed = true; } @@ -488,7 +488,7 @@ Mixer_UI::sync_order_keys_from_treeview () uint32_t new_rid = (visible ? rid : invisible_key--); if (new_rid != route->remote_control_id()) { - route->set_remote_control_id_from_order_key (MixerSort, new_rid); + route->set_remote_control_id_explicit (new_rid); rid_change = true; } @@ -503,7 +503,7 @@ Mixer_UI::sync_order_keys_from_treeview () if (changed) { /* tell everyone that we changed the mixer sort keys */ - _session->sync_order_keys (MixerSort); + _session->sync_order_keys (); } if (rid_change) { @@ -513,33 +513,13 @@ Mixer_UI::sync_order_keys_from_treeview () } void -Mixer_UI::sync_treeview_from_order_keys (RouteSortOrderKey src) +Mixer_UI::sync_treeview_from_order_keys () { if (!_session || _session->deletion_in_progress()) { return; } - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("mixer sync model from order keys, src = %1\n", enum_2_string (src))); - - if (src == EditorSort) { - - if (!Config->get_sync_all_route_ordering()) { - /* editor sort keys changed - we don't care */ - return; - } - - DEBUG_TRACE (DEBUG::OrderKeys, "reset mixer order key to match editor\n"); - - /* editor sort keys were changed, update the mixer sort - * keys since "sync mixer+editor order" is enabled. - */ - - boost::shared_ptr<RouteList> r = _session->get_routes (); - - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - (*i)->sync_order_keys (src); - } - } + DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync model from order keys.\n"); /* we could get here after either a change in the Mixer or Editor sort * order, but either way, the mixer order keys reflect the intended @@ -559,7 +539,7 @@ Mixer_UI::sync_treeview_from_order_keys (RouteSortOrderKey src) for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) { boost::shared_ptr<Route> route = (*ri)[track_columns.route]; - sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key (MixerSort))); + sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key ())); } SortByNewDisplayOrder cmp; @@ -1100,7 +1080,7 @@ struct SignalOrderRouteSorter { /* everything comes before b */ return true; } - return a->order_key (MixerSort) < b->order_key (MixerSort); + return a->order_key () < b->order_key (); } }; @@ -1122,7 +1102,7 @@ Mixer_UI::initial_track_display () add_strips (copy); } - _session->sync_order_keys (MixerSort); + _session->sync_order_keys (); redisplay_track_list (); } diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index 4f1c6823e7..db841535b7 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -250,9 +250,9 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR Width _strip_width; void sync_order_keys_from_treeview (); - void sync_treeview_from_order_keys (ARDOUR::RouteSortOrderKey); + void sync_treeview_from_order_keys (); void reset_remote_control_ids (); - void reset_order_keys (ARDOUR::RouteSortOrderKey); + void reset_order_keys (); bool ignore_reorder; diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h index cf86f3e1bb..fefa999618 100644 --- a/gtk2_ardour/plugin_ui.h +++ b/gtk2_ardour/plugin_ui.h @@ -277,6 +277,7 @@ class GenericPluginUI : public PlugUIBase, public Gtk::VBox /* XXX: remove */ void print_parameter (char *buf, uint32_t len, uint32_t param); bool integer_printer (char* buf, Gtk::Adjustment &, ControlUI *); + bool midinote_printer(char* buf, Gtk::Adjustment &, ControlUI *); }; class PluginUIWindow : public ArdourWindow diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index 2a93cf6bee..213c818b0b 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -315,7 +315,7 @@ struct RouteIOs { class RouteIOsComparator { public: bool operator() (RouteIOs const & a, RouteIOs const & b) { - return a.route->order_key (EditorSort) < b.route->order_key (EditorSort); + return a.route->order_key () < b.route->order_key (); } }; diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc index 2872ad6605..35e9a5cbd3 100644 --- a/gtk2_ardour/port_matrix.cc +++ b/gtk2_ardour/port_matrix.cc @@ -158,7 +158,7 @@ PortMatrix::init () _session->engine().PortRegisteredOrUnregistered.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports, this), gui_context()); /* watch for route order keys changing, which changes the order of things in our global ports list(s) */ - Route::SyncOrderKeys.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports_proxy, this, _1), gui_context()); + Route::SyncOrderKeys.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports_proxy, this), gui_context()); /* Part 3: other stuff */ @@ -619,15 +619,13 @@ PortMatrix::setup_global_ports () } void -PortMatrix::setup_global_ports_proxy (RouteSortOrderKey sk) +PortMatrix::setup_global_ports_proxy () { - if (sk == EditorSort) { - /* Avoid a deadlock by calling this in an idle handler: see IOSelector::io_changed_proxy - for a discussion. - */ + /* Avoid a deadlock by calling this in an idle handler: see IOSelector::io_changed_proxy + for a discussion. + */ - Glib::signal_idle().connect_once (sigc::mem_fun (*this, &PortMatrix::setup_global_ports)); - } + Glib::signal_idle().connect_once (sigc::mem_fun (*this, &PortMatrix::setup_global_ports)); } void diff --git a/gtk2_ardour/port_matrix.h b/gtk2_ardour/port_matrix.h index 2b5e9ce31d..09c334b5ef 100644 --- a/gtk2_ardour/port_matrix.h +++ b/gtk2_ardour/port_matrix.h @@ -188,7 +188,7 @@ private: void disassociate_all_on_channel (boost::weak_ptr<ARDOUR::Bundle>, uint32_t, int); void disassociate_all_on_bundle (boost::weak_ptr<ARDOUR::Bundle>, int); void setup_global_ports (); - void setup_global_ports_proxy (ARDOUR::RouteSortOrderKey); + void setup_global_ports_proxy (); void toggle_show_only_bundles (); bool on_scroll_event (GdkEventScroll *); boost::shared_ptr<ARDOUR::IO> io_from_bundle (boost::shared_ptr<ARDOUR::Bundle>) const; diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index 7b8eb2ea20..da6d2344c2 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -1408,14 +1408,6 @@ RCOptionEditor::RCOptionEditor () add_option (_("Editor"), new BoolOption ( - "sync-all-route-ordering", - _("Synchronise editor and mixer track order"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_all_route_ordering), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_all_route_ordering) - )); - - add_option (_("Editor"), - new BoolOption ( "link-editor-and-mixer-selection", _("Synchronise editor and mixer selection"), sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_editor_and_mixer_selection), @@ -1822,7 +1814,6 @@ RCOptionEditor::RCOptionEditor () rm->add (UserOrdered, _("assigned by user")); rm->add (MixerOrdered, _("follows order of mixer")); - rm->add (EditorOrdered, _("follows order of editor")); add_option (_("Control Surfaces"), rm); diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 8cc1512d3b..ad5e3bfd94 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -1815,10 +1815,9 @@ RouteUI::open_remote_control_id_dialog () _route->remote_control_id(), (_route->is_master() ? _("the master bus") : _("the monitor bus")))); } else { - l->set_markup (string_compose (_("The remote control ID of %6 is: %3\n\n\n" - "Remote Control IDs are currently determined by track/bus ordering in %1\n\n" - "%4Use the User Interaction tab of the Preferences window if you want to change this%5"), - (Config->get_remote_model() == MixerOrdered ? _("the mixer") : _("the editor")), + l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n" + "Remote Control IDs are currently determined by track/bus ordering in Ardour.\n\n" + "%3Use the User Interaction tab of the Preferences window if you want to change this%4"), (is_track() ? _("track") : _("bus")), _route->remote_control_id(), "<span size=\"small\" style=\"italic\">", diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h index cbe0bfce50..26ced33885 100644 --- a/libs/ardour/ardour/audio_backend.h +++ b/libs/ardour/ardour/audio_backend.h @@ -117,6 +117,17 @@ class AudioBackend : public PortEngine { * at any time. */ virtual std::vector<float> available_sample_rates (const std::string& device) const = 0; + + /* Returns the default sample rate that will be shown to the user when + * configuration options are first presented. If the derived class + * needs or wants to override this, it can. It also MUST override this + * if there is any chance that an SR of 44.1kHz is not in the list + * returned by available_sample_rates() + */ + virtual float default_sample_rate () const { + return 44100.0; + } + /** Returns a collection of uint32 identifying buffer sizes that are * potentially usable with the hardware identified by @param device. * Any of these values may be supplied in other calls to this backend @@ -126,6 +137,16 @@ class AudioBackend : public PortEngine { */ virtual std::vector<uint32_t> available_buffer_sizes (const std::string& device) const = 0; + /* Returns the default buffer size that will be shown to the user when + * configuration options are first presented. If the derived class + * needs or wants to override this, it can. It also MUST override this + * if there is any chance that a buffer size of 1024 is not in the list + * returned by available_buffer_sizes() + */ + virtual uint32_t default_buffer_size () const { + return 1024; + } + /** Returns the maximum number of input channels that are potentially * usable with the hardware identified by @param device. Any number from 1 * to the value returned may be supplied in other calls to this backend as @@ -306,20 +327,6 @@ class AudioBackend : public PortEngine { */ virtual int stop () = 0; - /** Temporarily cease using the device named in the most recent call to set_parameters(). - * - * If the function is successfully called, no subsequent calls to the - * process_callback() of @param engine will be made after the function - * returns, until start() is called again. - * - * The backend will retain its existing parameter configuration after a successful - * return, and does NOT require any calls to set hardware parameters before it can be - * start()-ed again. - * - * Return zero if successful, 1 if the device is not in use, negative values on error - */ - virtual int pause () = 0; - /** While remaining connected to the device, and without changing its * configuration, start (or stop) calling the process_callback() of @param engine * without waiting for the device. Once process_callback() has returned, it @@ -457,6 +464,21 @@ class AudioBackend : public PortEngine { virtual void update_latencies () = 0; + /** Set @param speed and @param position to the current speed and position + * indicated by some transport sync signal. Return whether the current + * transport state is pending, or finalized. + * + * Derived classes only need implement this if they provide some way to + * sync to a transport sync signal (e.g. Sony 9 Pin) that is not + * handled by Ardour itself (LTC and MTC are both handled by Ardour). + * The canonical example is JACK Transport. + */ + virtual bool speed_and_position (double& speed, framepos_t& position) { + speed = 0.0; + position = 0; + return false; + } + protected: AudioEngine& engine; }; diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index d5dcbffe2b..7c05f40b82 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -85,7 +85,6 @@ public: int start (bool for_latency_measurement=false); int stop (bool for_latency_measurement=false); - int pause (); int freewheel (bool start_stop); float get_cpu_load() const ; void transport_start (); diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index 55b76fbb08..8bdb96bdd0 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -116,6 +116,7 @@ class Plugin : public PBD::StatefulDestructible, public Latent bool min_unbound; bool max_unbound; bool enumeration; + bool midinote; }; XMLNode& get_state (); diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 7000dde3ca..2044271b0c 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -173,7 +173,6 @@ CONFIG_VARIABLE (bool, use_overlap_equivalency, "use-overlap-equivalency", false CONFIG_VARIABLE (bool, periodic_safety_backups, "periodic-safety-backups", true) CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-backup-interval", 120) CONFIG_VARIABLE (float, automation_interval_msecs, "automation-interval-msecs", 30) -CONFIG_VARIABLE (bool, sync_all_route_ordering, "sync-all-route-ordering", true) CONFIG_VARIABLE (bool, only_copy_imported_files, "only-copy-imported-files", false) CONFIG_VARIABLE (bool, keep_tearoffs, "keep-tearoffs", false) CONFIG_VARIABLE (bool, new_plugins_active, "new-plugins-active", true) diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 23f24cb275..83605d7413 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -101,10 +101,9 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, bool set_name (const std::string& str); static void set_name_in_state (XMLNode &, const std::string &); - uint32_t order_key (RouteSortOrderKey) const; - bool has_order_key (RouteSortOrderKey) const; - void set_order_key (RouteSortOrderKey, uint32_t); - void sync_order_keys (RouteSortOrderKey); + uint32_t order_key () const; + bool has_order_key () const; + void set_order_key (uint32_t); bool is_auditioner() const { return _flags & Auditioner; } bool is_master() const { return _flags & MasterOut; } @@ -426,7 +425,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, void set_remote_control_id (uint32_t id, bool notify_class_listeners = true); uint32_t remote_control_id () const; - void set_remote_control_id_from_order_key (RouteSortOrderKey, uint32_t order_key); + void set_remote_control_id_explicit (uint32_t order_key); /* for things concerned about *this* route's RID */ @@ -435,7 +434,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, /* for things concerned about *any* route's RID changes */ static PBD::Signal0<void> RemoteControlIDChange; - static PBD::Signal1<void,RouteSortOrderKey> SyncOrderKeys; + static PBD::Signal0<void> SyncOrderKeys; bool has_external_redirects() const; @@ -546,8 +545,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, int set_state_2X (const XMLNode&, int); void set_processor_state_2X (XMLNodeList const &, int); - typedef std::map<RouteSortOrderKey,uint32_t> OrderKeys; - OrderKeys order_keys; + uint32_t _order_key; + bool _has_order_key; uint32_t _remote_control_id; void input_change_handler (IOChange, void *src); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 8226f16866..4632d08fa7 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -242,7 +242,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi }; void notify_remote_id_change (); - void sync_order_keys (RouteSortOrderKey); + void sync_order_keys (); template<class T> void foreach_route (T *obj, void (T::*func)(Route&)); template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>)); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index ee43d1f30f..91b8888f52 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -353,11 +353,6 @@ namespace ARDOUR { PostFader }; - enum RouteSortOrderKey { - EditorSort, - MixerSort - }; - enum MonitorModel { HardwareMonitoring, ///< JACK does monitoring SoftwareMonitoring, ///< Ardour does monitoring @@ -419,8 +414,7 @@ namespace ARDOUR { enum RemoteModel { UserOrdered, - MixerOrdered, - EditorOrdered + MixerOrdered }; enum CrossfadeModel { diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index c2224a8b5e..45b8bbf757 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -663,23 +663,6 @@ AudioEngine::stop (bool for_latency) } int -AudioEngine::pause () -{ - if (!_backend) { - return 0; - } - - if (_backend->pause ()) { - return -1; - } - - _running = false; - - Stopped(); /* EMIT SIGNAL */ - return 0; -} - -int AudioEngine::freewheel (bool start_stop) { if (!_backend) { diff --git a/libs/ardour/engine_slave.cc b/libs/ardour/engine_slave.cc index eb55c9ba54..849b7320d3 100644 --- a/libs/ardour/engine_slave.cc +++ b/libs/ardour/engine_slave.cc @@ -21,6 +21,7 @@ #include <cerrno> #include "ardour/audioengine.h" +#include "ardour/audio_backend.h" #include "ardour/slave.h" using namespace std; @@ -54,26 +55,13 @@ Engine_Slave::ok() const bool Engine_Slave::speed_and_position (double& sp, framepos_t& position) { - switch (engine.transport_state()) { - case TransportStopped: - speed = 0; - _starting = false; - break; - case TransportRolling: - speed = 1.0; - _starting = false; - break; - case TransportLooping: - speed = 1.0; + boost::shared_ptr<AudioBackend> backend = engine.current_backend(); + + if (backend) { + _starting = backend->speed_and_position (sp, position); + } else { _starting = false; - break; - case TransportStarting: - _starting = true; - // don't adjust speed here, just leave it as it was - break; } - - sp = speed; - position = engine.transport_frame(); + return true; } diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 2a38cd2c8a..72125f8772 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -95,7 +95,6 @@ setup_enum_writer () AutoState _AutoState; AutoStyle _AutoStyle; AutoConnectOption _AutoConnectOption; - RouteSortOrderKey _RouteSortOrderKey; Session::StateOfTheState _Session_StateOfTheState; Route::Flag _Route_Flag; Source::Flag _Source_Flag; @@ -281,8 +280,13 @@ setup_enum_writer () REGISTER_ENUM (UserOrdered); REGISTER_ENUM (MixerOrdered); - REGISTER_ENUM (EditorOrdered); REGISTER (_RemoteModel); + /* + * EditorOrdered has been deprecated + * since the removal of independent + * editor / mixer ordering. + */ + enum_writer.add_to_hack_table ("EditorOrdered", "MixerOrdered"); REGISTER_ENUM (FullCrossfade); REGISTER_ENUM (ShortCrossfade); @@ -434,10 +438,6 @@ setup_enum_writer () REGISTER_CLASS_ENUM (Route, MonitorOut); REGISTER_BITS (_Route_Flag); - REGISTER_ENUM (MixerSort); - REGISTER_ENUM (EditorSort); - REGISTER (_RouteSortOrderKey); - REGISTER_CLASS_ENUM (Source, Writable); REGISTER_CLASS_ENUM (Source, CanRename); REGISTER_CLASS_ENUM (Source, Broadcast); diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 9538cef8b6..f5dcc26410 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -143,6 +143,8 @@ public: LilvNode* ui_GtkUI; LilvNode* ui_external; LilvNode* ui_externalkx; + LilvNode* units_unit; + LilvNode* units_midiNote; private: bool _bundle_checked; @@ -1328,8 +1330,10 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c { const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, which); + LilvNodes* portunits; LilvNode *def, *min, *max; lilv_port_get_range(_impl->plugin, port, &def, &min, &max); + portunits = lilv_port_get_value(_impl->plugin, port, _world.units_unit); desc.integer_step = lilv_port_has_property(_impl->plugin, port, _world.lv2_integer); desc.toggled = lilv_port_has_property(_impl->plugin, port, _world.lv2_toggled); @@ -1338,6 +1342,8 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c desc.label = lilv_node_as_string(lilv_port_get_name(_impl->plugin, port)); desc.lower = min ? lilv_node_as_float(min) : 0.0f; desc.upper = max ? lilv_node_as_float(max) : 1.0f; + desc.midinote = lilv_nodes_contains(portunits, _world.units_midiNote); + if (desc.sr_dependent) { desc.lower *= _session.frame_rate (); desc.upper *= _session.frame_rate (); @@ -1362,6 +1368,7 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c lilv_node_free(def); lilv_node_free(min); lilv_node_free(max); + lilv_nodes_free(portunits); return 0; } @@ -1965,10 +1972,14 @@ LV2World::LV2World() ui_GtkUI = lilv_new_uri(world, LV2_UI__GtkUI); ui_external = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#external"); ui_externalkx = lilv_new_uri(world, "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget"); + units_unit = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#unit"); + units_midiNote = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#midiNote"); } LV2World::~LV2World() { + lilv_node_free(units_midiNote); + lilv_node_free(units_unit); lilv_node_free(ui_externalkx); lilv_node_free(ui_external); lilv_node_free(ui_GtkUI); diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index de2263fad6..ae168356b6 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -174,12 +174,21 @@ MidiPort::flush_buffers (pframes_t nframes) { if (sends_output ()) { - void* port_buffer = port_engine.get_buffer (_port_handle, nframes); + void* port_buffer = 0; if (_resolve_required) { + port_buffer = port_engine.get_buffer (_port_handle, nframes); /* resolve all notes at the start of the buffer */ resolve_notes (port_buffer, 0); _resolve_required = false; + } + + if (_buffer->empty()) { + return; + } + + if (!port_buffer) { + port_buffer = port_engine.get_buffer (_port_handle, nframes); } for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) { @@ -201,6 +210,11 @@ MidiPort::flush_buffers (pframes_t nframes) << " + " << _port_buffer_offset << endl; } } + + /* done.. the data has moved to the port buffer, mark it so + */ + + _buffer->clear (); } } diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index f6af17b1b8..2f69c3340a 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -69,7 +69,7 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -PBD::Signal1<void,RouteSortOrderKey> Route::SyncOrderKeys; +PBD::Signal0<void> Route::SyncOrderKeys; PBD::Signal0<void> Route::RemoteControlIDChange; Route::Route (Session& sess, string name, Flag flg, DataType default_type) @@ -96,6 +96,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) , _have_internal_generator (false) , _solo_safe (false) , _default_type (default_type) + , _has_order_key (false) , _remote_control_id (0) , _in_configure_processors (false) , _initial_io_setup (false) @@ -268,52 +269,19 @@ Route::remote_control_id() const } bool -Route::has_order_key (RouteSortOrderKey key) const +Route::has_order_key () const { - return (order_keys.find (key) != order_keys.end()); + return _has_order_key; } uint32_t -Route::order_key (RouteSortOrderKey key) const +Route::order_key () const { - OrderKeys::const_iterator i = order_keys.find (key); - - if (i == order_keys.end()) { - return 0; - } - - return i->second; + return _order_key; } void -Route::sync_order_keys (RouteSortOrderKey base) -{ - /* this is called after changes to 1 or more route order keys have been - * made, and we want to sync up. - */ - - OrderKeys::iterator i = order_keys.find (base); - - if (i == order_keys.end()) { - return; - } - - for (OrderKeys::iterator k = order_keys.begin(); k != order_keys.end(); ++k) { - - if (k->first != base) { - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 set key for %2 to %3 from %4\n", - name(), - enum_2_string (k->first), - i->second, - enum_2_string (base))); - - k->second = i->second; - } - } -} - -void -Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t rid) +Route::set_remote_control_id_explicit (uint32_t rid) { if (is_master() || is_monitor() || is_auditioner()) { /* hard-coded remote IDs, or no remote ID */ @@ -337,18 +305,18 @@ Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t } void -Route::set_order_key (RouteSortOrderKey key, uint32_t n) +Route::set_order_key (uint32_t n) { - OrderKeys::iterator i = order_keys.find (key); + _has_order_key = true; - if (i != order_keys.end() && i->second == n) { + if (_order_key == n) { return; } - order_keys[key] = n; + _order_key = n; - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key %2 set to %3\n", - name(), enum_2_string (key), order_key (key))); + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key set to %2\n", + name(), order_key ())); _session.set_dirty (); } @@ -1909,24 +1877,8 @@ Route::state(bool full_state) node->add_property("route-group", _route_group->name()); } - string order_string; - OrderKeys::iterator x = order_keys.begin(); - - while (x != order_keys.end()) { - order_string += enum_2_string ((*x).first); - order_string += '='; - snprintf (buf, sizeof(buf), "%" PRId32, (*x).second); - order_string += buf; - - ++x; - - if (x == order_keys.end()) { - break; - } - - order_string += ':'; - } - node->add_property ("order-keys", order_string); + snprintf (buf, sizeof (buf), "%d", _order_key); + node->add_property ("order-key", buf); node->add_property ("self-solo", (_self_solo ? "yes" : "no")); snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream); node->add_property ("soloed-by-upstream", buf); @@ -2127,7 +2079,11 @@ Route::set_state (const XMLNode& node, int version) set_active (yn, this); } - if ((prop = node.property (X_("order-keys"))) != 0) { + if ((prop = node.property (X_("order-key"))) != 0) { // New order key (no separate mixer/editor ordering) + set_order_key (atoi(prop->value())); + } + + if ((prop = node.property (X_("order-keys"))) != 0) { // Deprecated order keys int32_t n; @@ -2145,17 +2101,11 @@ Route::set_state (const XMLNode& node, int version) << endmsg; } else { string keyname = remaining.substr (0, equal); - RouteSortOrderKey sk; - if (keyname == "signal") { - sk = MixerSort; - } else if (keyname == "editor") { - sk = EditorSort; - } else { - sk = (RouteSortOrderKey) string_2_enum (remaining.substr (0, equal), sk); + if ((keyname == "EditorSort") || (keyname == "editor")) { + cerr << "Setting " << name() << " order key to " << n << " using saved Editor order." << endl; + set_order_key (n); } - - set_order_key (sk, n); } } @@ -2356,17 +2306,11 @@ Route::set_state_2X (const XMLNode& node, int version) << endmsg; } else { string keyname = remaining.substr (0, equal); - RouteSortOrderKey sk; - if (keyname == "signal") { - sk = MixerSort; - } else if (keyname == "editor") { - sk = EditorSort; - } else { - sk = (RouteSortOrderKey) string_2_enum (remaining.substr (0, equal), sk); + if (keyname == "EditorSort" || keyname == "editor") { + info << string_compose(_("Converting deprecated order key for %1 using Editor order %2"), name (), n) << endmsg; + set_order_key (n); } - - set_order_key (sk, n); } } diff --git a/libs/ardour/route_graph.cc b/libs/ardour/route_graph.cc index 13264ff9fa..ee02afef24 100644 --- a/libs/ardour/route_graph.cc +++ b/libs/ardour/route_graph.cc @@ -170,7 +170,7 @@ struct RouteRecEnabledComparator if (r1->record_enabled()) { if (r2->record_enabled()) { /* both rec-enabled, just use signal order */ - return r1->order_key (MixerSort) < r2->order_key (MixerSort); + return r1->order_key () < r2->order_key (); } else { /* r1 rec-enabled, r2 not rec-enabled, run r2 early */ return false; @@ -181,7 +181,7 @@ struct RouteRecEnabledComparator return true; } else { /* neither rec-enabled, use signal order */ - return r1->order_key (MixerSort) < r2->order_key (MixerSort); + return r1->order_key () < r2->order_key (); } } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 0d078690f1..9e79ad305a 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1699,7 +1699,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r) DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n"); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2\n", - (*i)->name(), (*i)->order_key (MixerSort))); + (*i)->name(), (*i)->order_key ())); } #endif @@ -2396,15 +2396,13 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool ID in most situations. */ - if (!r->has_order_key (EditorSort)) { + if (!r->has_order_key ()) { if (r->is_auditioner()) { /* use an arbitrarily high value */ - r->set_order_key (EditorSort, UINT_MAX); - r->set_order_key (MixerSort, UINT_MAX); + r->set_order_key (UINT_MAX); } else { DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("while adding, set %1 to order key %2\n", r->name(), order)); - r->set_order_key (EditorSort, order); - r->set_order_key (MixerSort, order); + r->set_order_key (order); order++; } } @@ -3715,7 +3713,7 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost:: if (b->is_monitor()) { return false; } - return a->order_key (MixerSort) < b->order_key (MixerSort); + return a->order_key () < b->order_key (); } bool @@ -4952,8 +4950,7 @@ Session::notify_remote_id_change () } switch (Config->get_remote_model()) { - case MixerSort: - case EditorSort: + case MixerOrdered: Route::RemoteControlIDChange (); /* EMIT SIGNAL */ break; default: @@ -4962,7 +4959,7 @@ Session::notify_remote_id_change () } void -Session::sync_order_keys (RouteSortOrderKey sort_key_changed) +Session::sync_order_keys () { if (deletion_in_progress()) { return; @@ -4974,9 +4971,9 @@ Session::sync_order_keys (RouteSortOrderKey sort_key_changed) opportunity to keep them in sync if they wish to. */ - DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("Sync Order Keys, based on %1\n", enum_2_string (sort_key_changed))); + DEBUG_TRACE (DEBUG::OrderKeys, "Sync Order Keys.\n"); - Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */ + Route::SyncOrderKeys (); /* EMIT SIGNAL */ DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n"); } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index ec29f8a373..f3ad9d66dd 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -3444,22 +3444,6 @@ Session::config_changed (std::string p, bool ours) /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED TO SET REMOTE ID'S */ - } else if (p == "sync-all-route-ordering") { - - /* sync to editor order unless mixer is used for remote IDs - */ - - switch (Config->get_remote_model()) { - case UserOrdered: - sync_order_keys (EditorSort); - break; - case EditorOrdered: - sync_order_keys (EditorSort); - break; - case MixerOrdered: - sync_order_keys (MixerSort); - } - } else if (p == "initial-program-change") { if (_mmc->output_port() && Config->get_initial_program_change() >= 0) { diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 25741a77fe..c82c0fbef9 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -1,4 +1,4 @@ -1#!/usr/bin/env python +#!/usr/bin/env python from waflib.extras import autowaf as autowaf from waflib import Options import os diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc index ff76486bad..7a9b993251 100644 --- a/libs/backends/jack/jack_audiobackend.cc +++ b/libs/backends/jack/jack_audiobackend.cc @@ -582,18 +582,6 @@ JACKAudioBackend::stop () } int -JACKAudioBackend::pause () -{ - GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); - - if (_priv_jack) { - jack_deactivate (_priv_jack); - } - - return 0; -} - -int JACKAudioBackend::freewheel (bool onoff) { GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); @@ -1131,3 +1119,46 @@ JACKAudioBackend::set_midi_option (const string& opt) _target_midi_option = opt; return 0; } + +bool +JACKAudioBackend::speed_and_position (double& speed, framepos_t& position) +{ + jack_position_t pos; + jack_transport_state_t state; + bool starting; + + /* this won't be called if the port engine in use is not JACK, so we do + not have to worry about the type of PortEngine::private_handle() + */ + + speed = 0; + position = 0; + + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, true); + + state = jack_transport_query (_priv_jack, &pos); + + switch (state) { + case JackTransportStopped: + speed = 0; + starting = false; + break; + case JackTransportRolling: + speed = 1.0; + starting = false; + break; + case JackTransportLooping: + speed = 1.0; + starting = false; + break; + case JackTransportStarting: + starting = true; + // don't adjust speed here, just leave it as it was + break; + default: + std::cerr << "WARNING: Unknown JACK transport state: " << state << std::endl; + } + + position = pos.frame; + return starting; +} diff --git a/libs/backends/jack/jack_audiobackend.h b/libs/backends/jack/jack_audiobackend.h index 3c48be5ead..c59ddb5c67 100644 --- a/libs/backends/jack/jack_audiobackend.h +++ b/libs/backends/jack/jack_audiobackend.h @@ -91,7 +91,6 @@ class JACKAudioBackend : public AudioBackend { int _start (bool for_latency_measurement); int stop (); - int pause (); int freewheel (bool); float cpu_load() const; @@ -183,6 +182,10 @@ class JACKAudioBackend : public AudioBackend { void* get_buffer (PortHandle, pframes_t); + /* transport sync */ + + bool speed_and_position (double& sp, framepos_t& pos); + private: boost::shared_ptr<JackConnection> _jack_connection; bool _running; diff --git a/libs/backends/jack/jack_session.cc b/libs/backends/jack/jack_session.cc index ca51dafccc..7cd7f6c62b 100644 --- a/libs/backends/jack/jack_session.cc +++ b/libs/backends/jack/jack_session.cc @@ -23,6 +23,7 @@ #include <glibmm/miscutils.h> #include <jack/jack.h> +#include <jack/transport.h> #include "ardour/audioengine.h" #include "ardour/filename_extensions.h" diff --git a/libs/plugins/reasonablesynth.lv2/lv2.c b/libs/plugins/reasonablesynth.lv2/lv2.c new file mode 100644 index 0000000000..159f422c85 --- /dev/null +++ b/libs/plugins/reasonablesynth.lv2/lv2.c @@ -0,0 +1,190 @@ +/* reasonable simple synth + * + * Copyright (C) 2013 Robin Gareus <robin@gareus.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +/* LV2 */ +#include "lv2/lv2plug.in/ns/lv2core/lv2.h" +#include "lv2/lv2plug.in/ns/ext/atom/util.h" +#include "lv2/lv2plug.in/ns/ext/urid/urid.h" +#include "lv2/lv2plug.in/ns/ext/midi/midi.h" + +#define RSY_URI "https://community.ardour.org/node/7596" + +/* the synth interface */ +static void * synth_alloc (void); +static void synth_init (void *, double rate); +static void synth_free (void *); +static void synth_parse_midi (void *, uint8_t *data, size_t size); +static uint32_t synth_sound (void *, uint32_t written, uint32_t nframes, float **out); + +#include "rsynth.c" + +typedef enum { + RSY_MIDIIN = 0, + RSY_OUTL, + RSY_OUTR +} PortIndex; + +typedef struct { + const LV2_Atom_Sequence* midiin; + float* outL; + float* outR; + + LV2_URID_Map* map; + LV2_URID midi_MidiEvent; + + double SampleRateD; + void *synth; +} RSynth; + +/* main LV2 */ + +static LV2_Handle +instantiate(const LV2_Descriptor* descriptor, + double rate, + const char* bundle_path, + const LV2_Feature* const* features) +{ + if (rate < 8000) { + fprintf(stderr, "RSynth.lv2 error: unsupported sample-rate (must be > 8k)\n"); + return NULL; + } + RSynth* self = (RSynth*)calloc(1, sizeof(RSynth)); + if(!self) { + return NULL; + } + + self->SampleRateD = rate; + + int i; + for (i=0; features[i]; ++i) { + if (!strcmp(features[i]->URI, LV2_URID__map)) { + self->map = (LV2_URID_Map*)features[i]->data; + } + } + + if (!self->map) { + fprintf(stderr, "RSynth.lv2 error: Host does not support urid:map\n"); + free(self); + return NULL; + } + + self->midi_MidiEvent = self->map->map(self->map->handle, LV2_MIDI__MidiEvent); + + self->synth = synth_alloc(); + synth_init(self->synth, rate); + + return (LV2_Handle)self; +} + +static void +connect_port(LV2_Handle handle, + uint32_t port, + void* data) +{ + RSynth* self = (RSynth*)handle; + + switch ((PortIndex)port) { + case RSY_MIDIIN: + self->midiin = (const LV2_Atom_Sequence*)data; + break; + case RSY_OUTL: + self->outL = (float*)data; + break; + case RSY_OUTR: + self->outR = (float*)data; + break; + } +} + +static void +run(LV2_Handle handle, uint32_t n_samples) +{ + RSynth* self = (RSynth*)handle; + float* audio[2]; + + audio[0] = self->outL; + audio[1] = self->outR; + + uint32_t written = 0; + + /* Process incoming MIDI events */ + if (self->midiin) { + LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->midiin)->body); + while(!lv2_atom_sequence_is_end(&(self->midiin)->body, (self->midiin)->atom.size, ev)) { + if (ev->body.type == self->midi_MidiEvent) { + if (written + BUFFER_SIZE_SAMPLES < ev->time.frames + && ev->time.frames < n_samples) { + /* first synthesize sound up until the message timestamp */ + written = synth_sound(self->synth, written, ev->time.frames, audio); + } + /* send midi message to synth */ + synth_parse_midi(self->synth, (uint8_t*)(ev+1), ev->body.size); + } + ev = lv2_atom_sequence_next(ev); + } + } + + /* synthesize [remaining] sound */ + synth_sound(self->synth, written, n_samples, audio); +} + +static void +cleanup(LV2_Handle handle) +{ + RSynth* self = (RSynth*)handle; + synth_free(self->synth); + free(handle); +} + +static const void* +extension_data(const char* uri) +{ + return NULL; +} + +static const LV2_Descriptor descriptor = { + RSY_URI, + instantiate, + connect_port, + NULL, + run, + NULL, + cleanup, + extension_data +}; + +LV2_SYMBOL_EXPORT +const LV2_Descriptor* +lv2_descriptor(uint32_t index) +{ + switch (index) { + case 0: + return &descriptor; + default: + return NULL; + } +} + +/* vi:set ts=8 sts=2 sw=2: */ diff --git a/libs/plugins/reasonablesynth.lv2/manifest.ttl.in b/libs/plugins/reasonablesynth.lv2/manifest.ttl.in new file mode 100644 index 0000000000..92b20b40b8 --- /dev/null +++ b/libs/plugins/reasonablesynth.lv2/manifest.ttl.in @@ -0,0 +1,7 @@ +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + +<https://community.ardour.org/node/7596> + a lv2:Plugin ; + lv2:binary <reasonablesynth@LIB_EXT@> ; + rdfs:seeAlso <reasonablesynth.ttl> . diff --git a/libs/plugins/reasonablesynth.lv2/reasonablesynth.ttl.in b/libs/plugins/reasonablesynth.lv2/reasonablesynth.ttl.in new file mode 100644 index 0000000000..fe4cddbad4 --- /dev/null +++ b/libs/plugins/reasonablesynth.lv2/reasonablesynth.ttl.in @@ -0,0 +1,50 @@ +@prefix atom: <http://lv2plug.in/ns/ext/atom#> . +@prefix doap: <http://usefulinc.com/ns/doap#> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> . +@prefix urid: <http://lv2plug.in/ns/ext/urid#> . + +<http://gareus.org/rgareus#me> + a foaf:Person ; + foaf:name "Robin Gareus" ; + foaf:mbox <mailto:robin@gareus.org> ; + foaf:homepage <http://gareus.org/> . + +<https://community.ardour.org/node/7596> + a lv2:Plugin, lv2:InstrumentPlugin, doap:Project; + doap:license <http://usefulinc.com/doap/licenses/gpl> ; + doap:maintainer <http://gareus.org/rgareus#me> ; + doap:name "Reasonable Synth"; + lv2:optionalFeature lv2:hardRTCapable ; + lv2:requiredFeature urid:map ; + rdfs:comment """A simple synthesizer with no controls at all but a reasonable sound instead.""" ; + lv2:port + [ + a atom:AtomPort , + lv2:InputPort ; + atom:bufferType atom:Sequence ; + atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ; + lv2:index 0 ; + lv2:symbol "MidiIn" ; + lv2:name "MIDI Input" ; + ], + [ + a lv2:AudioPort , + lv2:OutputPort ; + lv2:index 1 ; + lv2:symbol "outL" ; + lv2:name "Left output" ; + lv2:designation pg:left ; + ], + [ + a lv2:AudioPort , + lv2:OutputPort ; + lv2:index 2 ; + lv2:symbol "outR" ; + lv2:name "Right Output" ; + lv2:designation pg:right ; + ] + . diff --git a/libs/plugins/reasonablesynth.lv2/rsynth.c b/libs/plugins/reasonablesynth.lv2/rsynth.c new file mode 100644 index 0000000000..b89f0fb45f --- /dev/null +++ b/libs/plugins/reasonablesynth.lv2/rsynth.c @@ -0,0 +1,490 @@ +/* reasonable simple synth + * + * Copyright (C) 2013 Robin Gareus <robin@gareus.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE // needed for M_PI +#endif + +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <assert.h> + +#ifndef BUFFER_SIZE_SAMPLES +#define BUFFER_SIZE_SAMPLES 64 +#endif + +#ifndef MIN +#define MIN(A, B) ( (A) < (B) ? (A) : (B) ) +#endif + +/* internal MIDI event abstraction */ +enum RMIDI_EV_TYPE { + INVALID=0, + NOTE_ON, + NOTE_OFF, + PROGRAM_CHANGE, + CONTROL_CHANGE, +}; + +struct rmidi_event_t { + enum RMIDI_EV_TYPE type; + uint8_t channel; /**< the MIDI channel number 0-15 */ + union { + struct { + uint8_t note; + uint8_t velocity; + } tone; + struct { + uint8_t param; + uint8_t value; + } control; + } d; +}; + +typedef struct { + uint32_t tme[3]; // attack, decay, release times [settings:ms || internal:samples] + float vol[2]; // attack, sustain volume [0..1] + uint32_t off[3]; // internal use (added attack,decay,release times) +} ADSRcfg; + +typedef struct _RSSynthChannel { + uint32_t keycomp; + uint32_t adsr_cnt[128]; + float adsr_amp[128]; + float phase[128]; // various use, zero'ed on note-on + int8_t miditable[128]; // internal, note-on/off velocity + ADSRcfg adsr; + void (*synthesize) (struct _RSSynthChannel* sc, + const uint8_t note, const float vol, const float pc, + const size_t n_samples, float* left, float* right); +} RSSynthChannel; + +typedef void (*SynthFunction) (RSSynthChannel* sc, + const uint8_t note, const float vol, const float pc, + const size_t n_samples, float* left, float* right); + +typedef struct { + uint32_t boffset; + float buf [2][BUFFER_SIZE_SAMPLES]; + RSSynthChannel sc[16]; + float freqs[128]; + float kcgain; + float kcfilt; + double rate; +} RSSynthesizer; + + +/* initialize ADSR values + * + * @param rate sample-rate + * @param a attack time in seconds + * @param d decay time in seconds + * @param r release time in seconds + * @param avol attack gain [0..1] + * @param svol sustain volume level [0..1] + */ +static void init_adsr(ADSRcfg *adsr, const double rate, + const uint32_t a, const uint32_t d, const uint32_t r, + const float avol, const float svol) { + + adsr->vol[0] = avol; + adsr->vol[1] = svol; + adsr->tme[0] = a * rate / 1000.0; + adsr->tme[1] = d * rate / 1000.0; + adsr->tme[2] = r * rate / 1000.0; + + assert(adsr->tme[0] > 32); + assert(adsr->tme[1] > 32); + assert(adsr->tme[2] > 32); + assert(adsr->vol[0] >=0 && adsr->vol[1] <= 1.0); + assert(adsr->vol[1] >=0 && adsr->vol[1] <= 1.0); + + adsr->off[0] = adsr->tme[0]; + adsr->off[1] = adsr->tme[1] + adsr->off[0]; + adsr->off[2] = adsr->tme[2] + adsr->off[1]; +} + +/* calculate per-sample, per-key envelope */ +static inline float adsr_env(RSSynthChannel *sc, const uint8_t note) { + + if (sc->adsr_cnt[note] < sc->adsr.off[0]) { + // attack + const uint32_t p = ++sc->adsr_cnt[note]; + if (p == sc->adsr.tme[0]) { + sc->adsr_amp[note] = sc->adsr.vol[0]; + return sc->adsr.vol[0]; + } else { + const float d = sc->adsr.vol[0] - sc->adsr_amp[note]; + return sc->adsr_amp[note] + (p / (float) sc->adsr.tme[0]) * d; + } + } + else if (sc->adsr_cnt[note] < sc->adsr.off[1]) { + // decay + const uint32_t p = ++sc->adsr_cnt[note] - sc->adsr.off[0]; + if (p == sc->adsr.tme[1]) { + sc->adsr_amp[note] = sc->adsr.vol[1]; + return sc->adsr.vol[1]; + } else { + const float d = sc->adsr.vol[1] - sc->adsr_amp[note]; + return sc->adsr_amp[note] + (p / (float) sc->adsr.tme[1]) * d; + } + } + else if (sc->adsr_cnt[note] == sc->adsr.off[1]) { + // sustain + return sc->adsr.vol[1]; + } + else if (sc->adsr_cnt[note] < sc->adsr.off[2]) { + // release + const uint32_t p = ++sc->adsr_cnt[note] - sc->adsr.off[1]; + if (p == sc->adsr.tme[2]) { + sc->adsr_amp[note] = 0; + return 0; + } else { + const float d = 0 - sc->adsr_amp[note]; + return sc->adsr_amp[note] + (p / (float) sc->adsr.tme[2]) * d; + } + } + else { + sc->adsr_cnt[note] = 0; + return 0; + } +} + + +/*****************************************************************************/ +/* piano like sound w/slight stereo phase */ +static void synthesize_sineP (RSSynthChannel* sc, + const uint8_t note, const float vol, const float fq, + const size_t n_samples, float* left, float* right) { + + float phase = sc->phase[note]; + + for (size_t i=0; i < n_samples; ++i) { + float env = adsr_env(sc, note); + if (sc->adsr_cnt[note] == 0) break; + const float amp = vol * env; + + left[i] += amp * sinf(2.0 * M_PI * phase); + left[i] += .300 * amp * sinf(2.0 * M_PI * phase * 2.0); + left[i] += .150 * amp * sinf(2.0 * M_PI * phase * 3.0); + left[i] += .080 * amp * sinf(2.0 * M_PI * phase * 4.0); + //left[i] -= .007 * amp * sinf(2.0 * M_PI * phase * 5.0); + //left[i] += .010 * amp * sinf(2.0 * M_PI * phase * 6.0); + //left[i] += .020 * amp * sinf(2.0 * M_PI * phase * 7.0); + phase += fq; + right[i] += amp * sinf(2.0 * M_PI * phase); + right[i] += .300 * amp * sinf(2.0 * M_PI * phase * 2.0); + right[i] += .150 * amp * sinf(2.0 * M_PI * phase * 3.0); + right[i] -= .080 * amp * sinf(2.0 * M_PI * phase * 4.0); + //right[i] += .007 * amp * sinf(2.0 * M_PI * phase * 5.0); + //right[i] += .010 * amp * sinf(2.0 * M_PI * phase * 6.0); + //right[i] -= .020 * amp * sinf(2.0 * M_PI * phase * 7.0); + if (phase > 1.0) phase -= 2.0; + } + sc->phase[note] = phase; +} + +static const ADSRcfg piano_adsr = {{ 5, 1300, 100}, { 1.0, 0.0}, {0,0,0}}; + +/*****************************************************************************/ + + +/* process note - move through ADSR states, count active keys,.. */ +static void process_key (void *synth, + const uint8_t chn, const uint8_t note, + const size_t n_samples, float *left, float *right) +{ + RSSynthesizer* rs = (RSSynthesizer*)synth; + RSSynthChannel* sc = &rs->sc[chn]; + const int8_t vel = sc->miditable[note]; + const float vol = /* master_volume */ 0.25 * fabsf(vel) / 127.0; + const float phase = sc->phase[note]; + + if (phase == -10 && vel > 0) { + // new note on + assert(sc->adsr_cnt[note] == 0); + sc->adsr_amp[note] = 0; + sc->adsr_cnt[note] = 0; + sc->phase[note] = 0; + sc->keycomp++; + //printf("[On] Now %d keys active on chn %d\n", sc->keycomp, chn); + } + else if (phase >= -1.0 && phase <= 1.0 && vel > 0) { + // sustain note or re-start note while adsr in progress: + if (sc->adsr_cnt[note] > sc->adsr.off[1]) { + // x-fade to attack + sc->adsr_amp[note] = adsr_env(sc, note); + sc->adsr_cnt[note] = 0; + } + } + else if (phase >= -1.0 && phase <= 1.0 && vel < 0) { + // note off + if (sc->adsr_cnt[note] <= sc->adsr.off[1]) { + if (sc->adsr_cnt[note] != sc->adsr.off[1]) { + // x-fade to release + sc->adsr_amp[note] = adsr_env(sc, note); + } + sc->adsr_cnt[note] = sc->adsr.off[1] + 1; + } + } + else { + /* note-on + off in same cycle */ + sc->miditable[note] = 0; + sc->adsr_cnt[note] = 0; + sc->phase[note] = -10; + return; + } + + // synthesize actual sound + sc->synthesize(sc, note, vol, rs->freqs[note], n_samples, left, right); + + if (sc->adsr_cnt[note] == 0) { + //printf("Note %d,%d released\n", chn, note); + sc->miditable[note] = 0; + sc->adsr_amp[note] = 0; + sc->phase[note] = -10; + sc->keycomp--; + //printf("[off] Now %d keys active on chn %d\n", sc->keycomp, chn); + } +} + +/* synthesize a BUFFER_SIZE_SAMPLES's of audio-data */ +static void synth_fragment (void *synth, const size_t n_samples, float *left, float *right) { + RSSynthesizer* rs = (RSSynthesizer*)synth; + memset (left, 0, n_samples * sizeof(float)); + memset (right, 0, n_samples * sizeof(float)); + uint8_t keycomp = 0; + + for (int c=0; c < 16; ++c) { + for (int k=0; k < 128; ++k) { + if (rs->sc[c].miditable[k] == 0) continue; + process_key(synth, c, k, n_samples, left, right); + } + keycomp += rs->sc[c].keycomp; + } + +#if 1 // key-compression + float kctgt = 8.0 / (float)(keycomp + 7.0); + if (kctgt < .5) kctgt = .5; + if (kctgt > 1.0) kctgt = 1.0; + const float _w = rs->kcfilt; + for (unsigned int i=0; i < n_samples; ++i) { + rs->kcgain += _w * (kctgt - rs->kcgain); + left[i] *= rs->kcgain; + right[i] *= rs->kcgain; + } + rs->kcgain += 1e-12; +#endif +} + +static void synth_reset_channel(RSSynthChannel* sc) { + for (int k=0; k < 128; ++k) { + sc->adsr_cnt[k] = 0; + sc->adsr_amp[k] = 0; + sc->phase[k] = -10; + sc->miditable[k] = 0; + } + sc->keycomp = 0; +} + +static void synth_reset(void *synth) { + RSSynthesizer* rs = (RSSynthesizer*)synth; + for (int c=0; c < 16; ++c) { + synth_reset_channel(&(rs->sc[c])); + } + rs->kcgain = 0; +} + +static void synth_load(RSSynthChannel *sc, const double rate, + SynthFunction synthesize, + ADSRcfg const * const adsr) { + synth_reset_channel(sc); + init_adsr(&sc->adsr, rate, + adsr->tme[0], adsr->tme[1], adsr->tme[2], + adsr->vol[0], adsr->vol[1]); + sc->synthesize = synthesize; +} + + +/** + * internal abstraction of MIDI data handling + */ +static void synth_process_midi_event(void *synth, struct rmidi_event_t *ev) { + RSSynthesizer* rs = (RSSynthesizer*)synth; + switch(ev->type) { + case NOTE_ON: + if (rs->sc[ev->channel].miditable[ev->d.tone.note] <= 0) + rs->sc[ev->channel].miditable[ev->d.tone.note] = ev->d.tone.velocity; + break; + case NOTE_OFF: + if (rs->sc[ev->channel].miditable[ev->d.tone.note] > 0) + rs->sc[ev->channel].miditable[ev->d.tone.note] *= -1.0; + break; + case PROGRAM_CHANGE: + break; + case CONTROL_CHANGE: + if (ev->d.control.param == 0x00 || ev->d.control.param == 0x20) { + /* 0x00 and 0x20 are used for BANK select */ + break; + } else + if (ev->d.control.param == 121) { + /* reset all controllers */ + break; + } else + if (ev->d.control.param == 120 || ev->d.control.param == 123) { + /* Midi panic: 120: all sound off, 123: all notes off*/ + synth_reset_channel(&(rs->sc[ev->channel])); + break; + } else + if (ev->d.control.param >= 120) { + /* params 122-127 are reserved - skip them. */ + break; + } + break; + default: + break; + } +} + +/****************************************************************************** + * PUBLIC API (used by lv2.c) + */ + +/** + * align LV2 and internal synth buffers + * call synth_fragment as often as needed for the given LV2 buffer size + * + * @param synth synth-handle + * @param written samples written so far (offset in \ref out) + * @param nframes total samples to synthesize and write to the \out buffer + * @param out pointer to stereo output buffers + * @return end of buffer (written + nframes) + */ +static uint32_t synth_sound (void *synth, uint32_t written, const uint32_t nframes, float **out) { + RSSynthesizer* rs = (RSSynthesizer*)synth; + + while (written < nframes) { + uint32_t nremain = nframes - written; + + if (rs->boffset >= BUFFER_SIZE_SAMPLES) { + rs->boffset = 0; + synth_fragment(rs, BUFFER_SIZE_SAMPLES, rs->buf[0], rs->buf[1]); + } + + uint32_t nread = MIN(nremain, (BUFFER_SIZE_SAMPLES - rs->boffset)); + + memcpy(&out[0][written], &rs->buf[0][rs->boffset], nread*sizeof(float)); + memcpy(&out[1][written], &rs->buf[1][rs->boffset], nread*sizeof(float)); + + written += nread; + rs->boffset += nread; + } + return written; +} + +/** + * parse raw midi-data. + * + * @param synth synth-handle + * @param data 8bit midi message + * @param size number of bytes in the midi-message + */ +static void synth_parse_midi(void *synth, uint8_t *data, size_t size) { + if (size < 2 || size > 3) return; + // All messages need to be 3 bytes; except program-changes: 2bytes. + if (size == 2 && (data[0] & 0xf0) != 0xC0) return; + + struct rmidi_event_t ev; + + ev.channel = data[0]&0x0f; + switch (data[0] & 0xf0) { + case 0x80: + ev.type=NOTE_OFF; + ev.d.tone.note=data[1]&0x7f; + ev.d.tone.velocity=data[2]&0x7f; + break; + case 0x90: + ev.type=NOTE_ON; + ev.d.tone.note=data[1]&0x7f; + ev.d.tone.velocity=data[2]&0x7f; + break; + case 0xB0: + ev.type=CONTROL_CHANGE; + ev.d.control.param=data[1]&0x7f; + ev.d.control.value=data[2]&0x7f; + break; + case 0xC0: + ev.type=PROGRAM_CHANGE; + ev.d.control.value=data[1]&0x7f; + break; + default: + return; + } + synth_process_midi_event(synth, &ev); +} + +/** + * initialize the synth + * This should be called after synth_alloc() + * as soon as the sample-rate is known + * + * @param synth synth-handle + * @param rate sample-rate + */ +static void synth_init(void *synth, double rate) { + RSSynthesizer* rs = (RSSynthesizer*)synth; + rs->rate = rate; + rs->boffset = BUFFER_SIZE_SAMPLES; + const float tuning = 440; + for (int k=0; k < 128; k++) { + rs->freqs[k] = (2.0 * tuning / 32.0f) * powf(2, (k - 9.0) / 12.0) / rate; + assert(rs->freqs[k] < M_PI/2); // otherwise spatialization may phase out.. + } + rs->kcfilt = 12.0 / rate; + synth_reset(synth); + + for (int c=0; c < 16; c++) { + synth_load(&rs->sc[c], rate, &synthesize_sineP, &piano_adsr); + } +} + +/** + * Allocate data-structure, create a handle for all other synth_* functions. + * + * This data should be freeded with \ref synth_free when the synth is no + * longer needed. + * + * The synth can only be used after calling \rev synth_init as well. + * + * @return synth-handle + */ +static void * synth_alloc(void) { + return calloc(1, sizeof(RSSynthesizer)); +} + +/** + * release synth data structure + * @param synth synth-handle + */ +static void synth_free(void *synth) { + free(synth); +} +/* vi:set ts=8 sts=2 sw=2: */ diff --git a/libs/plugins/reasonablesynth.lv2/wscript b/libs/plugins/reasonablesynth.lv2/wscript new file mode 100644 index 0000000000..b534e2011b --- /dev/null +++ b/libs/plugins/reasonablesynth.lv2/wscript @@ -0,0 +1,48 @@ +#!/usr/bin/env python +import os +import re +import shutil +import waflib.extras.autowaf as autowaf +from waflib import Options + +# Mandatory variables +top = '.' +out = 'build' + +def options(opt): + autowaf.set_options(opt) + +def configure(conf): + conf.load('compiler_c') + autowaf.configure(conf) + autowaf.set_c99_mode(conf) + if Options.options.lv2: + autowaf.check_pkg(conf, 'lv2', atleast_version='1.4.0', + uselib_store='LV2_1_4_0') + +def build(bld): + bundle = 'reasonablesynth.lv2' + module_pat = re.sub('^lib', '', bld.env.cshlib_PATTERN) + module_ext = module_pat[module_pat.rfind('.'):] + + if bld.is_defined ('HAVE_LV2'): + # Build RDF files + for i in ['manifest.ttl', 'reasonablesynth.ttl']: + bld(features = 'subst', + source = i + '.in', + target = '../../LV2/%s/%s' % (bundle, i), + install_path = '${LV2DIR}/%s' % bundle, + LIB_EXT = module_ext) + + # Build plugin library + obj = bld(features = 'c cshlib', + source = 'lv2.c', + dep_files = 'rsynth.c', + name = 'reasonablesynth', + target = '../../LV2/%s/reasonablesynth' % bundle, + install_path = '${LV2DIR}/%s' % bundle, + use = 'LV2_1_4_0' + ) + obj.env.cshlib_PATTERN = module_pat + +# vi:set ts=4 sw=4 et: diff --git a/tools/linux_packaging/build b/tools/linux_packaging/build index 3bf793a637..e7f7d8b6dd 100755 --- a/tools/linux_packaging/build +++ b/tools/linux_packaging/build @@ -534,6 +534,9 @@ cp -R ../../gtk2_ardour/splash.png $Shared cp -R ../../gtk2_ardour/small-splash.png $Shared cp -R ../../gtk2_ardour/ArdourMono.ttf $Shared +# install bundled LV2s to <app>/lib/LV2/ +cp -R $BUILD_ROOT/libs/LV2 $APPLIB/ + # go through and recursively remove any .svn dirs in the bundle for svndir in `find $APPDIR -name .svn -type d`; do rm -rf $svndir diff --git a/tools/osx_packaging/osx_build b/tools/osx_packaging/osx_build index 276eb90fe5..c47e64483c 100755 --- a/tools/osx_packaging/osx_build +++ b/tools/osx_packaging/osx_build @@ -219,21 +219,42 @@ fi # copy locale files if test x$WITH_NLS != x ; then echo "NLS support ..." - echo "I hope you remembered to run scons msgupdate!" + echo "I hope you remembered to run waf i18n" LINGUAS= - for file in $BUILD_ROOT/gtk2_ardour/*.mo - do - lang=`basename $file | sed 's/\.mo//'` - mkdir -p $Locale/$lang/LC_MESSAGES - cp $file $Locale/$lang/LC_MESSAGES/gtk2_ardour.mo - LINGUAS="$LINGUAS $lang" - done - for file in $BUILD_ROOT/libs/ardour/*.mo - do - lang=`basename $file | sed 's/\.mo//'` - mkdir -p $Locale/$lang/LC_MESSAGES - cp $file $Locale/$lang/LC_MESSAGES/libardour.mo + + for pkg in gtk2_ardour libs/ardour libs/gtkmm2ext ; do + files=`find ../../$pkg -name "*.mo"` + + # + # the package name is appended with a number so that + # it can be parallel installed during a regular install + # with older (and newer) versions. it is just the major + # number of the release (i.e. leading digits) + # + + vsuffix=`echo $release_version | sed 's/^\([0-9][0-9]*\).*/\1/'` + + if [ -z "$files" ]; then + echo "" + echo "!!!! WARNING !!!! - Did not find any .mo files in ../../$pkg" + echo "" + fi + + for file in $files + do + echo $file + lang=`basename $file | sed 's/\.mo//'` + mkdir -p $Locale/$lang/LC_MESSAGES + cp $file $Locale/$lang/LC_MESSAGES/`basename $pkg`$vsuffix.mo + echo copy $file to $Locale/$lang/LC_MESSAGES/`basename $pkg`$vsuffix.mo + if echo $LINGUAS | grep $lang >/dev/null 2>&1 ; then + : + else + LINGUAS="$LINGUAS $lang" + fi + done done + for l in $LINGUAS do if [ -d $GTKSTACK_ROOT/share/locale/$l ] ; then @@ -417,6 +438,9 @@ for svndir in `find $APPDIR -name .svn -type dir`; do rm -rf $svndir done +# install bundled LV2s to <app>/Contents/lib/LV2/ +cp -R $BUILD_ROOT/libs/LV2 $Frameworks/ + # now fix up the executables echo "Fixing up executable dependency names ..." executables=$MAIN_EXECUTABLE @@ -36,6 +36,7 @@ children = [ 'libs/clearlooks-newer', 'libs/audiographer', 'libs/canvas', + 'libs/plugins/reasonablesynth.lv2', 'gtk2_ardour', 'export', 'midi_maps', @@ -68,7 +69,7 @@ def fetch_gcc_version (CC): return version def fetch_git_revision (): - cmd = "git describe --tags HEAD" + cmd = "git describe HEAD" output = subprocess.Popen(cmd, shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0].splitlines() rev = output[0].decode('utf-8') return rev |