merge from master
This commit is contained in:
commit
664e715a00
|
@ -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"
|
||||
|
@ -831,13 +832,6 @@ ARDOUR_UI::starting ()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::no_memory_warning ()
|
||||
{
|
||||
XMLNode node (X_("no-memory-warning"));
|
||||
Config->add_instant_xml (node);
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::check_memory_locking ()
|
||||
{
|
||||
|
@ -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\
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -176,12 +176,6 @@ EditorGroupTabs::default_properties () const
|
|||
return plist;
|
||||
}
|
||||
|
||||
RouteSortOrderKey
|
||||
EditorGroupTabs::order_key () const
|
||||
{
|
||||
return EditorSort;
|
||||
}
|
||||
|
||||
RouteList
|
||||
EditorGroupTabs::selected_routes () const
|
||||
{
|
||||
|
|
|
@ -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 ();
|
||||
};
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 &);
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -170,12 +170,6 @@ MixerGroupTabs::default_properties () const
|
|||
return plist;
|
||||
}
|
||||
|
||||
RouteSortOrderKey
|
||||
MixerGroupTabs::order_key () const
|
||||
{
|
||||
return MixerSort;
|
||||
}
|
||||
|
||||
RouteList
|
||||
MixerGroupTabs::selected_routes () const
|
||||
{
|
||||
|
|
|
@ -36,7 +36,6 @@ private:
|
|||
}
|
||||
|
||||
PBD::PropertyList default_properties () const;
|
||||
ARDOUR::RouteSortOrderKey order_key () const;
|
||||
ARDOUR::RouteList selected_routes () const;
|
||||
void sync_order_keys ();
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1406,14 +1406,6 @@ RCOptionEditor::RCOptionEditor ()
|
|||
sigc::mem_fun (*_rc_config, &RCConfiguration::set_update_editor_during_summary_drag)
|
||||
));
|
||||
|
||||
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",
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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\">",
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -116,6 +116,7 @@ class Plugin : public PBD::StatefulDestructible, public Latent
|
|||
bool min_unbound;
|
||||
bool max_unbound;
|
||||
bool enumeration;
|
||||
bool midinote;
|
||||
};
|
||||
|
||||
XMLNode& get_state ();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -662,23 +662,6 @@ AudioEngine::stop (bool for_latency)
|
|||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
_starting = false;
|
||||
break;
|
||||
case TransportStarting:
|
||||
_starting = true;
|
||||
// don't adjust speed here, just leave it as it was
|
||||
break;
|
||||
}
|
||||
boost::shared_ptr<AudioBackend> backend = engine.current_backend();
|
||||
|
||||
sp = speed;
|
||||
position = engine.transport_frame();
|
||||
if (backend) {
|
||||
_starting = backend->speed_and_position (sp, position);
|
||||
} else {
|
||||
_starting = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -581,18 +581,6 @@ JACKAudioBackend::stop ()
|
|||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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: */
|
|
@ -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> .
|
|
@ -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 ;
|
||||
]
|
||||
.
|
|
@ -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: */
|
|
@ -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:
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
3
wscript
3
wscript
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue