merge 12791:13034 from 3.0

git-svn-id: svn://localhost/ardour2/branches/3.0-SG@13105 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-08-02 00:04:51 +00:00
parent 576f73e032
commit 3bb7d368a8
57 changed files with 1595 additions and 280 deletions

View file

@ -794,6 +794,8 @@ If you still wish to quit, please use the\n\n\
*/ */
save_ardour_state (); save_ardour_state ();
loading_message (_("Please wait while Ardour cleans up..."));
if (_session) { if (_session) {
// _session->set_deletion_in_progress (); // _session->set_deletion_in_progress ();
_session->set_clean (); _session->set_clean ();
@ -2394,20 +2396,6 @@ ARDOUR_UI::idle_load (const std::string& path)
} }
} }
void
ARDOUR_UI::loading_message (const std::string& msg)
{
if (ARDOUR_COMMAND_LINE::no_splash) {
return;
}
show_splash ();
if (splash) {
splash->message (msg);
flush_pending ();
}
}
/** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */ /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
int int
ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template) ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
@ -2812,7 +2800,7 @@ ARDOUR_UI::launch_manual ()
void void
ARDOUR_UI::launch_reference () ARDOUR_UI::launch_reference ()
{ {
PBD::open_uri("http://ardour.org/refmanual"); PBD::open_uri ("http://ardour.org/refmanual");
} }
void void
@ -2830,6 +2818,20 @@ ARDOUR_UI::about_signal_response (int /*response*/)
hide_about(); hide_about();
} }
void
ARDOUR_UI::loading_message (const std::string& msg)
{
if (ARDOUR_COMMAND_LINE::no_splash) {
return;
}
if (!splash) {
show_splash ();
}
splash->message (msg);
}
void void
ARDOUR_UI::show_splash () ARDOUR_UI::show_splash ()
{ {
@ -2841,11 +2843,7 @@ ARDOUR_UI::show_splash ()
} }
} }
splash->present (); splash->display ();
splash->pop_front ();
splash->queue_draw ();
splash->get_window()->process_updates (true);
flush_pending ();
} }
void void

View file

@ -611,6 +611,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
About* about; About* about;
Splash* splash; Splash* splash;
void pop_back_splash (Gtk::Window&); void pop_back_splash (Gtk::Window&);
/* cleanup */ /* cleanup */

View file

@ -1455,15 +1455,6 @@ AudioClock::on_button_press_event (GdkEventButton *ev)
switch (ev->button) { switch (ev->button) {
case 1: case 1:
if (editable && !_off) { if (editable && !_off) {
dragging = true;
/* make absolutely sure that the pointer is grabbed */
gdk_pointer_grab(ev->window,false ,
GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
NULL,NULL,ev->time);
drag_accum = 0;
drag_start_y = ev->y;
drag_y = ev->y;
int index; int index;
int trailing; int trailing;
int y; int y;
@ -1478,8 +1469,14 @@ AudioClock::on_button_press_event (GdkEventButton *ev)
if (_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) { if (_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
drag_field = index_to_field (index); drag_field = index_to_field (index);
} else { dragging = true;
drag_field = Field (0); /* make absolutely sure that the pointer is grabbed */
gdk_pointer_grab(ev->window,false ,
GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
NULL,NULL,ev->time);
drag_accum = 0;
drag_start_y = ev->y;
drag_y = ev->y;
} }
} }
break; break;
@ -1660,7 +1657,7 @@ AudioClock::on_motion_notify_event (GdkEventMotion *ev)
int dir; int dir;
dir = (drag_accum < 0 ? 1:-1); dir = (drag_accum < 0 ? 1:-1);
pos = current_time(); pos = current_time();
frames = get_frame_step (drag_field,pos,dir); frames = get_frame_step (drag_field, pos, dir);
if (frames != 0 && frames * drag_accum < current_time()) { if (frames != 0 && frames * drag_accum < current_time()) {
set ((framepos_t) floor (pos - drag_accum * frames), false); // minus because up is negative in GTK set ((framepos_t) floor (pos - drag_accum * frames), false); // minus because up is negative in GTK

View file

@ -66,6 +66,7 @@ using namespace Editing;
using namespace ArdourCanvas; using namespace ArdourCanvas;
static const int32_t sync_mark_width = 9; static const int32_t sync_mark_width = 9;
static double const handle_size = 6; /* height of fade handles */
AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu, AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu,
Gdk::Color const & basic_color) Gdk::Color const & basic_color)
@ -79,9 +80,11 @@ AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView
, start_xfade_in (0) , start_xfade_in (0)
, start_xfade_out (0) , start_xfade_out (0)
, start_xfade_rect (0) , start_xfade_rect (0)
, _start_xfade_visible (false)
, end_xfade_in (0) , end_xfade_in (0)
, end_xfade_out (0) , end_xfade_out (0)
, end_xfade_rect (0) , end_xfade_rect (0)
, _end_xfade_visible (false)
, _amplitude_above_axis(1.0) , _amplitude_above_axis(1.0)
, fade_color(0) , fade_color(0)
{ {
@ -100,9 +103,11 @@ AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView
, start_xfade_in (0) , start_xfade_in (0)
, start_xfade_out (0) , start_xfade_out (0)
, start_xfade_rect (0) , start_xfade_rect (0)
, _start_xfade_visible (false)
, end_xfade_in (0) , end_xfade_in (0)
, end_xfade_out (0) , end_xfade_out (0)
, end_xfade_rect (0) , end_xfade_rect (0)
, _end_xfade_visible (false)
, _amplitude_above_axis(1.0) , _amplitude_above_axis(1.0)
, fade_color(0) , fade_color(0)
{ {
@ -119,9 +124,11 @@ AudioRegionView::AudioRegionView (const AudioRegionView& other, boost::shared_pt
, start_xfade_in (0) , start_xfade_in (0)
, start_xfade_out (0) , start_xfade_out (0)
, start_xfade_rect (0) , start_xfade_rect (0)
, _start_xfade_visible (false)
, end_xfade_in (0) , end_xfade_in (0)
, end_xfade_out (0) , end_xfade_out (0)
, end_xfade_rect (0) , end_xfade_rect (0)
, _end_xfade_visible (false)
, _amplitude_above_axis (other._amplitude_above_axis) , _amplitude_above_axis (other._amplitude_above_axis)
, fade_color(0) , fade_color(0)
{ {
@ -161,13 +168,13 @@ AudioRegionView::init (Gdk::Color const & basic_color, bool wfd)
if (!_recregion) { if (!_recregion) {
fade_in_handle = new ArdourCanvas::SimpleRect (*group); fade_in_handle = new ArdourCanvas::SimpleRect (*group);
fade_in_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fill_color, 0); fade_in_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fill_color, 0);
fade_in_handle->property_outline_pixels() = 0; fade_in_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 0);
fade_in_handle->set_data ("regionview", this); fade_in_handle->set_data ("regionview", this);
fade_out_handle = new ArdourCanvas::SimpleRect (*group); fade_out_handle = new ArdourCanvas::SimpleRect (*group);
fade_out_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fill_color, 0); fade_out_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fill_color, 0);
fade_out_handle->property_outline_pixels() = 0; fade_out_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 0);
fade_out_handle->set_data ("regionview", this); fade_out_handle->set_data ("regionview", this);
@ -448,17 +455,15 @@ AudioRegionView::setup_fade_handle_positions()
{ {
/* position of fade handle offset from the top of the region view */ /* position of fade handle offset from the top of the region view */
double const handle_pos = 2; double const handle_pos = 2;
/* height of fade handles */
double const handle_height = 5;
if (fade_in_handle) { if (fade_in_handle) {
fade_in_handle->property_y1() = handle_pos; fade_in_handle->property_y1() = handle_pos;
fade_in_handle->property_y2() = handle_pos + handle_height; fade_in_handle->property_y2() = handle_pos + handle_size;
} }
if (fade_out_handle) { if (fade_out_handle) {
fade_out_handle->property_y1() = handle_pos; fade_out_handle->property_y1() = handle_pos;
fade_out_handle->property_y2() = handle_pos + handle_height; fade_out_handle->property_y2() = handle_pos + handle_size;
} }
} }
@ -559,6 +564,7 @@ AudioRegionView::reset_fade_in_shape_width (framecnt_t width)
start_xfade_in->hide (); start_xfade_in->hide ();
start_xfade_out->hide (); start_xfade_out->hide ();
start_xfade_rect->hide (); start_xfade_rect->hide ();
_start_xfade_visible = false;
} }
} }
@ -589,7 +595,7 @@ AudioRegionView::reset_fade_in_shape_width (framecnt_t width)
/* Put the fade in handle so that its left side is at the end-of-fade line */ /* Put the fade in handle so that its left side is at the end-of-fade line */
fade_in_handle->property_x1() = handle_center; fade_in_handle->property_x1() = handle_center;
fade_in_handle->property_x2() = handle_center + 6; fade_in_handle->property_x2() = handle_center + handle_size;
if (pwidth < 5) { if (pwidth < 5) {
fade_in_shape->hide(); fade_in_shape->hide();
@ -668,6 +674,7 @@ AudioRegionView::reset_fade_out_shape_width (framecnt_t width)
end_xfade_in->hide (); end_xfade_in->hide ();
end_xfade_out->hide (); end_xfade_out->hide ();
end_xfade_rect->hide (); end_xfade_rect->hide ();
_end_xfade_visible = false;
} }
} }
@ -1140,7 +1147,9 @@ AudioRegionView::entered (bool internal_editing)
} }
if (fade_in_handle && !internal_editing) { if (fade_in_handle && !internal_editing) {
fade_in_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 255);
fade_in_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 255); fade_in_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 255);
fade_out_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 255);
fade_out_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 255); fade_out_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 255);
} }
} }
@ -1156,7 +1165,9 @@ AudioRegionView::exited ()
} }
if (fade_in_handle) { if (fade_in_handle) {
fade_in_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 0);
fade_in_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 0); fade_in_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 0);
fade_out_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 0);
fade_out_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 0); fade_out_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 0);
} }
} }
@ -1455,6 +1466,7 @@ AudioRegionView::redraw_start_xfade ()
start_xfade_in->hide (); start_xfade_in->hide ();
start_xfade_out->hide (); start_xfade_out->hide ();
start_xfade_rect->hide (); start_xfade_rect->hide ();
_start_xfade_visible = false;
} }
return; return;
} }
@ -1544,6 +1556,8 @@ AudioRegionView::redraw_start_xfade_to (boost::shared_ptr<AudioRegion> ar, frame
start_xfade_out->show (); start_xfade_out->show ();
start_xfade_out->raise_to_top (); start_xfade_out->raise_to_top ();
_start_xfade_visible = true;
delete points; delete points;
} }
@ -1561,6 +1575,7 @@ AudioRegionView::redraw_end_xfade ()
end_xfade_in->hide (); end_xfade_in->hide ();
end_xfade_out->hide (); end_xfade_out->hide ();
end_xfade_rect->hide (); end_xfade_rect->hide ();
_end_xfade_visible = false;
} }
return; return;
} }
@ -1652,12 +1667,20 @@ AudioRegionView::redraw_end_xfade_to (boost::shared_ptr<AudioRegion> ar, framecn
end_xfade_out->show (); end_xfade_out->show ();
end_xfade_out->raise_to_top (); end_xfade_out->raise_to_top ();
_end_xfade_visible = true;
delete points; delete points;
} }
void void
AudioRegionView::hide_xfades () AudioRegionView::hide_xfades ()
{
hide_start_xfade ();
hide_end_xfade ();
}
void
AudioRegionView::hide_start_xfade ()
{ {
if (start_xfade_in) { if (start_xfade_in) {
start_xfade_in->hide(); start_xfade_in->hide();
@ -1668,6 +1691,13 @@ AudioRegionView::hide_xfades ()
if (start_xfade_rect) { if (start_xfade_rect) {
start_xfade_rect->hide (); start_xfade_rect->hide ();
} }
_start_xfade_visible = false;
}
void
AudioRegionView::hide_end_xfade ()
{
if (end_xfade_in) { if (end_xfade_in) {
end_xfade_in->hide(); end_xfade_in->hide();
} }
@ -1677,10 +1707,12 @@ AudioRegionView::hide_xfades ()
if (end_xfade_rect) { if (end_xfade_rect) {
end_xfade_rect->hide (); end_xfade_rect->hide ();
} }
_end_xfade_visible = false;
} }
void void
AudioRegionView::show_xfades () AudioRegionView::show_start_xfade ()
{ {
if (start_xfade_in) { if (start_xfade_in) {
start_xfade_in->show(); start_xfade_in->show();
@ -1691,6 +1723,13 @@ AudioRegionView::show_xfades ()
if (start_xfade_rect) { if (start_xfade_rect) {
start_xfade_rect->show (); start_xfade_rect->show ();
} }
_start_xfade_visible = true;
}
void
AudioRegionView::show_end_xfade ()
{
if (end_xfade_in) { if (end_xfade_in) {
end_xfade_in->show(); end_xfade_in->show();
} }
@ -1700,6 +1739,15 @@ AudioRegionView::show_xfades ()
if (end_xfade_rect) { if (end_xfade_rect) {
end_xfade_rect->show (); end_xfade_rect->show ();
} }
_end_xfade_visible = true;
}
void
AudioRegionView::show_xfades ()
{
show_start_xfade ();
show_end_xfade ();
} }
void void
@ -1722,11 +1770,16 @@ AudioRegionView::drag_end ()
{ {
TimeAxisViewItem::drag_end (); TimeAxisViewItem::drag_end ();
for (list<AudioRegionView*>::iterator i = _hidden_xfades.begin(); i != _hidden_xfades.end(); ++i) { for (list<AudioRegionView*>::iterator i = _hidden_xfades.first.begin(); i != _hidden_xfades.first.end(); ++i) {
(*i)->show_xfades (); (*i)->show_start_xfade ();
} }
_hidden_xfades.clear (); for (list<AudioRegionView*>::iterator i = _hidden_xfades.second.begin(); i != _hidden_xfades.second.end(); ++i) {
(*i)->show_end_xfade ();
}
_hidden_xfades.first.clear ();
_hidden_xfades.second.clear ();
} }
void void

View file

@ -119,7 +119,19 @@ class AudioRegionView : public RegionView
void redraw_end_xfade (); void redraw_end_xfade ();
void hide_xfades (); void hide_xfades ();
void hide_start_xfade ();
void hide_end_xfade ();
void show_xfades (); void show_xfades ();
void show_start_xfade ();
void show_end_xfade ();
bool start_xfade_visible () const {
return _start_xfade_visible;
}
bool end_xfade_visible () const {
return _end_xfade_visible;
}
protected: protected:
@ -149,10 +161,12 @@ class AudioRegionView : public RegionView
ArdourCanvas::Line *start_xfade_in; ArdourCanvas::Line *start_xfade_in;
ArdourCanvas::Line *start_xfade_out; ArdourCanvas::Line *start_xfade_out;
ArdourCanvas::SimpleRect* start_xfade_rect; ArdourCanvas::SimpleRect* start_xfade_rect;
bool _start_xfade_visible;
ArdourCanvas::Line *end_xfade_in; ArdourCanvas::Line *end_xfade_in;
ArdourCanvas::Line *end_xfade_out; ArdourCanvas::Line *end_xfade_out;
ArdourCanvas::SimpleRect* end_xfade_rect; ArdourCanvas::SimpleRect* end_xfade_rect;
bool _end_xfade_visible;
boost::shared_ptr<AudioRegionGainLine> gain_line; boost::shared_ptr<AudioRegionGainLine> gain_line;
@ -203,8 +217,10 @@ private:
*/ */
std::vector<PBD::ScopedConnection*> _data_ready_connections; std::vector<PBD::ScopedConnection*> _data_ready_connections;
/** RegionViews that we hid the xfades for at the start of the current drag */ /** RegionViews that we hid the xfades for at the start of the current drag;
std::list<AudioRegionView*> _hidden_xfades; * first list is for start xfades, second list is for end xfades.
*/
std::pair<std::list<AudioRegionView*>, std::list<AudioRegionView*> > _hidden_xfades;
}; };
#endif /* __gtk_ardour_audio_region_view_h__ */ #endif /* __gtk_ardour_audio_region_view_h__ */

View file

@ -493,12 +493,14 @@ AudioStreamView::hide_all_fades ()
} }
/** Hide xfades for regions that overlap ar. /** Hide xfades for regions that overlap ar.
* @return AudioRegionViews that xfades were hidden for. * @return Pair of lists; first is the AudioRegionViews that start xfades were hidden for,
* second is the AudioRegionViews that end xfades were hidden for.
*/ */
list<AudioRegionView*> pair<list<AudioRegionView*>, list<AudioRegionView*> >
AudioStreamView::hide_xfades_with (boost::shared_ptr<AudioRegion> ar) AudioStreamView::hide_xfades_with (boost::shared_ptr<AudioRegion> ar)
{ {
list<AudioRegionView*> hidden; list<AudioRegionView*> start_hidden;
list<AudioRegionView*> end_hidden;
for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i); AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
@ -507,14 +509,19 @@ AudioStreamView::hide_xfades_with (boost::shared_ptr<AudioRegion> ar)
case Evoral::OverlapNone: case Evoral::OverlapNone:
break; break;
default: default:
if (arv->start_xfade_visible ()) {
start_hidden.push_back (arv);
}
if (arv->end_xfade_visible ()) {
end_hidden.push_back (arv);
}
arv->hide_xfades (); arv->hide_xfades ();
hidden.push_back (arv);
break; break;
} }
} }
} }
return hidden; return make_pair (start_hidden, end_hidden);
} }
void void

View file

@ -59,7 +59,7 @@ class AudioStreamView : public StreamView
void show_all_fades (); void show_all_fades ();
void hide_all_fades (); void hide_all_fades ();
std::list<AudioRegionView*> hide_xfades_with (boost::shared_ptr<ARDOUR::AudioRegion> ar); std::pair<std::list<AudioRegionView*>, std::list<AudioRegionView*> > hide_xfades_with (boost::shared_ptr<ARDOUR::AudioRegion> ar);
RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool); RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool);

View file

@ -266,7 +266,7 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y)
} }
alist->freeze (); alist->freeze ();
sync_model_with_view_point (cp, 0); sync_model_with_view_point (cp);
alist->thaw (); alist->thaw ();
update_pending = false; update_pending = false;
@ -289,12 +289,12 @@ AutomationLine::reset_line_coords (ControlPoint& cp)
} }
void void
AutomationLine::sync_model_with_view_points (list<ControlPoint*> cp, int64_t distance) AutomationLine::sync_model_with_view_points (list<ControlPoint*> cp)
{ {
update_pending = true; update_pending = true;
for (list<ControlPoint*>::iterator i = cp.begin(); i != cp.end(); ++i) { for (list<ControlPoint*>::iterator i = cp.begin(); i != cp.end(); ++i) {
sync_model_with_view_point (**i, distance); sync_model_with_view_point (**i);
} }
} }
@ -309,6 +309,31 @@ AutomationLine::get_verbose_cursor_string (double fraction) const
return s; return s;
} }
string
AutomationLine::get_verbose_cursor_relative_string (double original, double fraction) const
{
std::string s = fraction_to_string (fraction);
if (_uses_gain_mapping) {
s += " dB";
}
std::string d = fraction_to_relative_string (original, fraction);
if (!d.empty()) {
s += " (\u0394";
s += d;
if (_uses_gain_mapping) {
s += " dB";
}
s += ')';
}
return s;
}
/** /**
* @param fraction y fraction * @param fraction y fraction
* @return string representation of this value, using dB if appropriate. * @return string representation of this value, using dB if appropriate.
@ -336,6 +361,45 @@ AutomationLine::fraction_to_string (double fraction) const
return buf; return buf;
} }
/**
* @param original an old y-axis fraction
* @param fraction the new y fraction
* @return string representation of the difference between original and fraction, using dB if appropriate.
*/
string
AutomationLine::fraction_to_relative_string (double original, double fraction) const
{
char buf[32];
if (original == fraction) {
return "0";
}
if (_uses_gain_mapping) {
if (original == 0.0) {
/* there is no sensible representation of a relative
change from -inf dB, so return an empty string.
*/
return "";
} else if (fraction == 0.0) {
snprintf (buf, sizeof (buf), "-inf");
} else {
double old_db = accurate_coefficient_to_dB (slider_position_to_gain_with_max (original, Config->get_max_gain()));
double new_db = accurate_coefficient_to_dB (slider_position_to_gain_with_max (fraction, Config->get_max_gain()));
snprintf (buf, sizeof (buf), "%.1f", new_db - old_db);
}
} else {
view_to_model_coord_y (original);
view_to_model_coord_y (fraction);
if (EventTypeMap::instance().is_integer (alist->parameter())) {
snprintf (buf, sizeof (buf), "%d", (int)fraction - (int)original);
} else {
snprintf (buf, sizeof (buf), "%.2f", fraction - original);
}
}
return buf;
}
/** /**
* @param s Value string in the form as returned by fraction_to_string. * @param s Value string in the form as returned by fraction_to_string.
@ -586,7 +650,7 @@ AutomationLine::end_drag ()
points.sort (ControlPointSorter ()); points.sort (ControlPointSorter ());
} }
sync_model_with_view_points (points, trackview.editor().unit_to_frame (_drag_distance)); sync_model_with_view_points (points);
alist->thaw (); alist->thaw ();
@ -601,7 +665,7 @@ AutomationLine::end_drag ()
} }
void void
AutomationLine::sync_model_with_view_point (ControlPoint& cp, framecnt_t distance) AutomationLine::sync_model_with_view_point (ControlPoint& cp)
{ {
/* find out where the visual control point is. /* find out where the visual control point is.
initial results are in canvas units. ask the initial results are in canvas units. ask the

View file

@ -113,7 +113,9 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
ArdourCanvas::Item& grab_item() const { return *line; } ArdourCanvas::Item& grab_item() const { return *line; }
std::string get_verbose_cursor_string (double) const; std::string get_verbose_cursor_string (double) const;
std::string get_verbose_cursor_relative_string (double, double) const;
std::string fraction_to_string (double) const; std::string fraction_to_string (double) const;
std::string fraction_to_relative_string (double, double) const;
double string_to_fraction (std::string const &) const; double string_to_fraction (std::string const &) const;
void view_to_model_coord (double& x, double& y) const; void view_to_model_coord (double& x, double& y) const;
void view_to_model_coord_y (double &) const; void view_to_model_coord_y (double &) const;
@ -179,8 +181,8 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
ArdourCanvas::Points line_points; /* coordinates for canvas line */ ArdourCanvas::Points line_points; /* coordinates for canvas line */
std::vector<ControlPoint*> control_points; /* visible control points */ std::vector<ControlPoint*> control_points; /* visible control points */
void sync_model_with_view_point (ControlPoint&, ARDOUR::framecnt_t); void sync_model_with_view_point (ControlPoint&);
void sync_model_with_view_points (std::list<ControlPoint*>, ARDOUR::framecnt_t); void sync_model_with_view_points (std::list<ControlPoint*>);
void start_drag_common (double, float); void start_drag_common (double, float);
virtual void change_model (ARDOUR::AutomationList::iterator, double x, double y); virtual void change_model (ARDOUR::AutomationList::iterator, double x, double y);

View file

@ -121,6 +121,9 @@ static guint32 gnome_canvas_waveview_ensure_cache (GnomeCanvasWaveView *waveview
gulong start_sample, gulong start_sample,
gulong end_sample); gulong end_sample);
static int _gradient_rendering = 0;
static GnomeCanvasItemClass *parent_class; static GnomeCanvasItemClass *parent_class;
GType GType
@ -328,6 +331,12 @@ gnome_canvas_waveview_class_init (GnomeCanvasWaveViewClass *class)
item_class->draw = gnome_canvas_waveview_draw; item_class->draw = gnome_canvas_waveview_draw;
} }
void
gnome_canvas_waveview_set_gradient_waveforms (int yn)
{
_gradient_rendering = yn;
}
GnomeCanvasWaveViewCache* GnomeCanvasWaveViewCache*
gnome_canvas_waveview_cache_new () gnome_canvas_waveview_cache_new ()
{ {
@ -1094,7 +1103,7 @@ gnome_canvas_waveview_update (GnomeCanvasItem *item, double *affine, ArtSVP *cli
} }
static void static void
gnome_canvas_waveview_render (GnomeCanvasItem *item, gnome_canvas_waveview_gradient_render (GnomeCanvasItem *item,
GnomeCanvasBuf *buf) GnomeCanvasBuf *buf)
{ {
GnomeCanvasWaveView *waveview; GnomeCanvasWaveView *waveview;
@ -1349,9 +1358,10 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
if(pymax == fill_max) { if(pymax == fill_max) {
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax); PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
++fill_max; ++fill_max;
} else {
PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max, wave_middle, wave_top);
} }
else {
PAINT_VERTA_GR(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max, wave_middle, wave_top); }
} }
if((prev_pymin > pymin && next_pymin > pymin) || if((prev_pymin > pymin && next_pymin > pymin) ||
@ -1640,6 +1650,549 @@ gnome_canvas_waveview_render (GnomeCanvasItem *item,
} }
static void
gnome_canvas_waveview_flat_render (GnomeCanvasItem *item,
GnomeCanvasBuf *buf)
{
GnomeCanvasWaveView *waveview;
gulong s1, s2;
int clip_length = 0;
int pymin, pymax;
guint cache_index;
double half_height;
int x;
char rectify;
waveview = GNOME_CANVAS_WAVEVIEW (item);
// check_cache (waveview, "start of render");
if (parent_class->render) {
(*parent_class->render) (item, buf);
}
if (buf->is_bg) {
gnome_canvas_buf_ensure_buf (buf);
buf->is_bg = FALSE;
}
/* a "unit" means a pixel */
/* begin: render start x (units) */
int const begin = MAX (waveview->bbox_ulx, buf->rect.x0);
/* zbegin: start x for zero line (units) */
int const zbegin = (begin == waveview->bbox_ulx) ? (begin + 1) : begin;
/* end: render end x (units) */
int const end = (waveview->bbox_lrx >= 0) ? MIN (waveview->bbox_lrx,buf->rect.x1) : buf->rect.x1;
/* zend: end x for zero-line (units) */
int const zend = (end == waveview->bbox_lrx) ? (end - 1) : end;
if (begin == end) {
return;
}
/* s1: start sample
s2: end sample
*/
s1 = floor ((begin - waveview->bbox_ulx) * waveview->samples_per_unit);
// fprintf (stderr, "0x%x begins at sample %f\n", waveview, waveview->bbox_ulx * waveview->samples_per_unit);
if (end == waveview->bbox_lrx) {
/* This avoids minor rounding errors when we have the
entire region visible.
*/
s2 = waveview->samples;
} else {
s2 = s1 + floor ((end - begin) * waveview->samples_per_unit);
}
#if 0
printf ("0x%x r (%d..%d)(%d..%d) bbox (%d..%d)(%d..%d)"
" b/e %d..%d s= %lu..%lu @ %f\n",
waveview,
buf->rect.x0,
buf->rect.x1,
buf->rect.y0,
buf->rect.y1,
waveview->bbox_ulx,
waveview->bbox_lrx,
waveview->bbox_uly,
waveview->bbox_lry,
begin, end, s1, s2,
waveview->samples_per_unit);
#endif
/* now ensure that the cache is full and properly
positioned.
*/
// check_cache (waveview, "pre-ensure");
if (waveview->cache_updater && waveview->reload_cache_in_render) {
waveview->cache->start = 0;
waveview->cache->end = 0;
waveview->reload_cache_in_render = FALSE;
}
// check_cache (waveview, "post-ensure");
/* don't rectify at single-sample zoom */
if (waveview->rectified && waveview->samples_per_unit > 1) {
rectify = TRUE;
}
else {
rectify = FALSE;
}
clip_length = MIN(5,(waveview->height/4));
/*
Now draw each line, clipping it appropriately. The clipping
is done by the macros PAINT_FOO().
*/
half_height = waveview->half_height;
/* this makes it slightly easier to comprehend whats going on */
#define origin half_height
if (waveview->filled && !rectify) {
int prev_pymin = 1;
int prev_pymax = 0;
int last_pymin = 1;
int last_pymax = 0;
int next_pymin, next_pymax;
double max, min;
int next_clip_max = 0;
int next_clip_min = 0;
if (s1 < waveview->samples_per_unit) {
/* we haven't got a prev vars to compare with, so outline the whole line here */
prev_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
prev_pymin = prev_pymax;
}
else {
s1 -= waveview->samples_per_unit;
}
if(end == waveview->bbox_lrx) {
/* we don't have the NEXT vars for the last sample */
last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
last_pymin = last_pymax;
}
else {
s2 += waveview->samples_per_unit;
}
cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
/*
* Compute the variables outside the rendering rect
*/
if(prev_pymax != prev_pymin) {
prev_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[cache_index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
prev_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[cache_index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
++cache_index;
}
if(last_pymax != last_pymin) {
/* take the index of one sample right of what we render */
guint index = cache_index + (end - begin);
if (index >= waveview->cache->data_size) {
/* the data we want is off the end of the cache, which must mean its beyond
the end of the region's source; hence the peak values are 0 */
last_pymax = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
last_pymin = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
} else {
last_pymax = (int) rint ((item->y1 + origin - MIN(waveview->cache->data[index].max, 1.0) * half_height) * item->canvas->pixels_per_unit);
last_pymin = (int) rint ((item->y1 + origin - MAX(waveview->cache->data[index].min, -1.0) * half_height) * item->canvas->pixels_per_unit);
}
}
/*
* initialize NEXT* variables for the first run, duplicated in the loop for speed
*/
max = waveview->cache->data[cache_index].max;
min = waveview->cache->data[cache_index].min;
if (max >= 1.0) {
max = 1.0;
next_clip_max = 1;
}
if (min <= -1.0) {
min = -1.0;
next_clip_min = 1;
}
max *= half_height;
min *= half_height;
next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
/*
* And now the loop
*/
for(x = begin; x < end; ++x) {
int clip_max = next_clip_max;
int clip_min = next_clip_min;
int fill_max, fill_min;
pymax = next_pymax;
pymin = next_pymin;
/* compute next */
if(x == end - 1) {
/*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
next_pymax = last_pymax;
next_pymin = last_pymin;
}
else {
++cache_index;
if (cache_index < waveview->cache->data_size) {
max = waveview->cache->data[cache_index].max;
min = waveview->cache->data[cache_index].min;
} else {
max = min = 0;
}
next_clip_max = 0;
next_clip_min = 0;
if (max >= 1.0) {
max = 1.0;
next_clip_max = 1;
}
if (min <= -1.0) {
min = -1.0;
next_clip_min = 1;
}
max *= half_height;
min *= half_height;
next_pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
next_pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
}
/* render */
if (pymax == pymin) {
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
} else {
if((prev_pymax < pymax && next_pymax < pymax) ||
(prev_pymax == pymax && next_pymax == pymax)) {
fill_max = pymax + 1;
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
}
else {
fill_max = MAX(prev_pymax, next_pymax);
if(pymax == fill_max) {
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
++fill_max;
}
else {
PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max);
}
}
if((prev_pymin > pymin && next_pymin > pymin) ||
(prev_pymin == pymin && next_pymin == pymin)) {
fill_min = pymin - 1;
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin-1);
}
else {
fill_min = MIN(prev_pymin, next_pymin);
if(pymin == fill_min) {
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
}
else {
PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, fill_min, pymin);
}
}
if(fill_max < fill_min) {
PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, fill_min);
}
else if(fill_max == fill_min) {
PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max);
}
}
if (clip_max) {
PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
}
if (clip_min) {
PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
}
prev_pymax = pymax;
prev_pymin = pymin;
}
} else if (waveview->filled && rectify) {
int prev_pymax = -1;
int last_pymax = -1;
int next_pymax;
double max, min;
int next_clip_max = 0;
int next_clip_min = 0;
// for rectified, this stays constant throughout the loop
pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
if(s1 < waveview->samples_per_unit) {
/* we haven't got a prev vars to compare with, so outline the whole line here */
prev_pymax = pymin;
}
else {
s1 -= waveview->samples_per_unit;
}
if(end == waveview->bbox_lrx) {
/* we don't have the NEXT vars for the last sample */
last_pymax = pymin;
}
else {
s2 += waveview->samples_per_unit;
}
cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
/*
* Compute the variables outside the rendering rect
*/
if(prev_pymax < 0) {
max = MIN(waveview->cache->data[cache_index].max, 1.0);
min = MAX(waveview->cache->data[cache_index].min, -1.0);
if (fabs (min) > fabs (max)) {
max = fabs (min);
}
prev_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
++cache_index;
}
if(last_pymax < 0) {
/* take the index of one sample right of what we render */
int index = cache_index + (end - begin);
max = MIN(waveview->cache->data[index].max, 1.0);
min = MAX(waveview->cache->data[index].min, -1.0);
if (fabs (min) > fabs (max)) {
max = fabs (min);
}
last_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
}
/*
* initialize NEXT* variables for the first run, duplicated in the loop for speed
*/
max = waveview->cache->data[cache_index].max;
min = waveview->cache->data[cache_index].min;
if (max >= 1.0) {
max = 1.0;
next_clip_max = 1;
}
if (min <= -1.0) {
min = -1.0;
next_clip_min = 1;
}
if (fabs (min) > fabs (max)) {
max = fabs (min);
}
next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
/*
* And now the loop
*/
for(x = begin; x < end; ++x) {
int clip_max = next_clip_max;
int clip_min = next_clip_min;
int fill_max;
pymax = next_pymax;
/* compute next */
if(x == end - 1) {
/*next is now the last column, which is outside the rendering rect, and possibly outside the region*/
next_pymax = last_pymax;
}
else {
++cache_index;
max = waveview->cache->data[cache_index].max;
min = waveview->cache->data[cache_index].min;
if (max >= 1.0) {
max = 1.0;
next_clip_max = 1;
}
if (min <= -1.0) {
min = -1.0;
next_clip_min = 1;
}
if (fabs (min) > fabs (max)) {
max = fabs (min);
}
next_pymax = (int) rint ((item->y1 + waveview->height - max * waveview->height) * item->canvas->pixels_per_unit);
}
/* render */
if (pymax == pymin) {
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
} else {
if((prev_pymax < pymax && next_pymax < pymax) ||
(prev_pymax == pymax && next_pymax == pymax)) {
fill_max = pymax + 1;
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
}
else {
fill_max = MAX(prev_pymax, next_pymax);
if(pymax == fill_max) {
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax);
++fill_max;
}
else {
PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, fill_max);
}
}
if(fill_max < pymin) {
PAINT_VERTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, fill_max, pymin);
}
else if(fill_max == pymin) {
PAINT_DOTA(buf, waveview->fill_r, waveview->fill_g, waveview->fill_b, waveview->fill_a, x, pymin);
}
}
if (clip_max) {
PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
}
if (clip_min) {
PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
}
prev_pymax = pymax;
}
}
else {
cache_index = gnome_canvas_waveview_ensure_cache (waveview, s1, s2);
for (x = begin; x < end; x++) {
double max, min;
int clip_max, clip_min;
clip_max = 0;
clip_min = 0;
max = waveview->cache->data[cache_index].max;
min = waveview->cache->data[cache_index].min;
if (max >= 1.0) {
max = 1.0;
clip_max = 1;
}
if (min <= -1.0) {
min = -1.0;
clip_min = 1;
}
if (rectify) {
if (fabs (min) > fabs (max)) {
max = fabs (min);
}
max = max * waveview->height;
pymax = (int) rint ((item->y1 + waveview->height - max) * item->canvas->pixels_per_unit);
pymin = (int) rint ((item->y1 + waveview->height) * item->canvas->pixels_per_unit);
} else {
max = max * half_height;
min = min * half_height;
pymax = (int) rint ((item->y1 + origin - max) * item->canvas->pixels_per_unit);
pymin = (int) rint ((item->y1 + origin - min) * item->canvas->pixels_per_unit);
}
/* OK, now fill the RGB buffer at x=i with a line between pymin and pymax,
or, if samples_per_unit == 1, then a dot at each location.
*/
if (pymax == pymin) {
PAINT_DOTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymin);
} else {
PAINT_VERTA(buf, waveview->wave_r, waveview->wave_g, waveview->wave_b, waveview->wave_a, x, pymax, pymin);
}
/* show clipped waveforms with small red lines */
if (clip_max) {
PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymax, pymax+clip_length);
}
if (clip_min) {
PAINT_VERTA(buf, waveview->clip_r, waveview->clip_g, waveview->clip_b, waveview->clip_a, x, pymin-clip_length, pymin);
}
/* presto, we're done */
cache_index++;
}
}
if (!waveview->rectified && waveview->zero_line && waveview->height >= 100) {
// Paint zeroline.
unsigned char zero_r, zero_g, zero_b, zero_a;
UINT_TO_RGBA( waveview->zero_color, &zero_r, &zero_g, &zero_b, &zero_a);
int zeroline_y = (int) rint ((item->y1 + origin) * item->canvas->pixels_per_unit);
PAINT_HORIZA(buf, zero_r, zero_g, zero_b, zero_a, zbegin, zend, zeroline_y);
}
#undef origin
}
static void
gnome_canvas_waveview_render (GnomeCanvasItem *item,
GnomeCanvasBuf *buf)
{
if (_gradient_rendering) {
gnome_canvas_waveview_gradient_render (item, buf);
} else {
gnome_canvas_waveview_flat_render (item, buf);
}
}
static void static void
gnome_canvas_waveview_draw (GnomeCanvasItem *item, gnome_canvas_waveview_draw (GnomeCanvasItem *item,
GdkDrawable *drawable, GdkDrawable *drawable,

View file

@ -64,6 +64,8 @@ struct _GnomeCanvasWaveViewCache
GnomeCanvasWaveViewCache* gnome_canvas_waveview_cache_new (); GnomeCanvasWaveViewCache* gnome_canvas_waveview_cache_new ();
void gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache*); void gnome_canvas_waveview_cache_destroy (GnomeCanvasWaveViewCache*);
void gnome_canvas_waveview_set_gradient_waveforms (int);
typedef gulong (*waveview_length_function_t)(void*); typedef gulong (*waveview_length_function_t)(void*);
typedef gulong (*waveview_sourcefile_length_function_t)(void*, double); typedef gulong (*waveview_sourcefile_length_function_t)(void*, double);
typedef void (*waveview_gain_curve_function_t)(void *arg, double start, double end, float* vector, gint64 veclen); typedef void (*waveview_gain_curve_function_t)(void *arg, double start, double end, float* vector, gint64 veclen);

View file

@ -1404,7 +1404,7 @@ Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
/** Pop up a context menu for when the user clicks on a start crossfade */ /** Pop up a context menu for when the user clicks on a start crossfade */
void void
Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type) Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
{ {
using namespace Menu_Helpers; using namespace Menu_Helpers;
@ -1419,7 +1419,7 @@ Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Ite
/** Pop up a context menu for when the user clicks on an end crossfade */ /** Pop up a context menu for when the user clicks on an end crossfade */
void void
Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type) Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
{ {
using namespace Menu_Helpers; using namespace Menu_Helpers;
@ -1909,7 +1909,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
edit_items.push_back (SeparatorElem()); edit_items.push_back (SeparatorElem());
edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection))); edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection))); edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false))); edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
edit_items.push_back (SeparatorElem()); edit_items.push_back (SeparatorElem());
edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false))); edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
@ -2743,7 +2743,10 @@ Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
_session->locations()->marks_either_side (start, before, after); _session->locations()->marks_either_side (start, before, after);
if (before == max_framepos) { if (before == max_framepos && after == max_framepos) {
/* No marks to snap to, so just don't snap */
return;
} else if (before == max_framepos) {
start = after; start = after;
} else if (after == max_framepos) { } else if (after == max_framepos) {
start = before; start = before;
@ -3251,7 +3254,7 @@ Editor::history_changed ()
} }
void void
Editor::duplicate_dialog (bool with_dialog) Editor::duplicate_range (bool with_dialog)
{ {
float times = 1.0f; float times = 1.0f;

View file

@ -1838,7 +1838,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
/* duplication */ /* duplication */
void duplicate_dialog (bool with_dialog); void duplicate_range (bool with_dialog);
framepos_t event_frame (GdkEvent const *, double* px = 0, double* py = 0) const; framepos_t event_frame (GdkEvent const *, double* px = 0, double* py = 0) const;

View file

@ -285,7 +285,7 @@ Editor::register_actions ()
reg_sens (editor_actions, "set-playhead", _("Playhead to Mouse"), sigc::mem_fun(*this, &Editor::set_playhead_cursor)); reg_sens (editor_actions, "set-playhead", _("Playhead to Mouse"), sigc::mem_fun(*this, &Editor::set_playhead_cursor));
reg_sens (editor_actions, "set-edit-point", _("Active Marker to Mouse"), sigc::mem_fun(*this, &Editor::set_edit_point)); reg_sens (editor_actions, "set-edit-point", _("Active Marker to Mouse"), sigc::mem_fun(*this, &Editor::set_edit_point));
reg_sens (editor_actions, "duplicate-range", _("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)); reg_sens (editor_actions, "duplicate-range", _("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false));
undo_action = reg_sens (editor_actions, "undo", S_("Command|Undo"), sigc::bind (sigc::mem_fun(*this, &Editor::undo), 1U)); undo_action = reg_sens (editor_actions, "undo", S_("Command|Undo"), sigc::bind (sigc::mem_fun(*this, &Editor::undo), 1U));
redo_action = reg_sens (editor_actions, "redo", _("Redo"), sigc::bind (sigc::mem_fun(*this, &Editor::redo), 1U)); redo_action = reg_sens (editor_actions, "redo", _("Redo"), sigc::bind (sigc::mem_fun(*this, &Editor::redo), 1U));
@ -1597,15 +1597,15 @@ Editor::register_region_actions ()
_region_actions, "toggle-region-fades", _("Fades"), sigc::bind (sigc::mem_fun(*this, &Editor::toggle_region_fades), 0) _region_actions, "toggle-region-fades", _("Fades"), sigc::bind (sigc::mem_fun(*this, &Editor::toggle_region_fades), 0)
); );
/* Open the dialogue to duplicate selected regions */ /* Duplicate selected regions */
reg_sens (_region_actions, "duplicate-region", _("Duplicate"), sigc::bind (sigc::mem_fun (*this, &Editor::duplicate_dialog), false)); reg_sens (_region_actions, "duplicate-region", _("Duplicate"), sigc::bind (sigc::mem_fun (*this, &Editor::duplicate_range), false));
/* Open the dialogue to duplicate selected regions multiple times */ /* Open the dialogue to duplicate selected regions multiple times */
reg_sens ( reg_sens (
_region_actions, _region_actions,
"multi-duplicate-region", "multi-duplicate-region",
_("Multi-Duplicate..."), _("Multi-Duplicate..."),
sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), true) sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), true)
); );
/* Fill tracks with selected regions */ /* Fill tracks with selected regions */

View file

@ -29,6 +29,7 @@
#include "gtkmm2ext/utils.h" #include "gtkmm2ext/utils.h"
#include "ardour/audioengine.h"
#include "ardour/audioregion.h" #include "ardour/audioregion.h"
#include "ardour/dB.h" #include "ardour/dB.h"
#include "ardour/midi_region.h" #include "ardour/midi_region.h"
@ -2170,11 +2171,22 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
s->cancel_audition (); s->cancel_audition ();
} }
if (AudioEngine::instance()->connected()) {
/* do this only if we're the engine is connected
* because otherwise this request will never be
* serviced and we'll busy wait forever. likewise,
* notice if we are disconnected while waiting for the
* request to be serviced.
*/
s->request_suspend_timecode_transmission (); s->request_suspend_timecode_transmission ();
while (!s->timecode_transmission_suspended ()) { while (AudioEngine::instance()->connected() && !s->timecode_transmission_suspended ()) {
/* twiddle our thumbs */ /* twiddle our thumbs */
} }
} }
}
fake_locate (where); fake_locate (where);
} }
@ -4094,7 +4106,7 @@ AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AutomationTimeAxisView
, _nothing_to_drag (false) , _nothing_to_drag (false)
{ {
DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n"); DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n");
y_origin = atv->y_position();
setup (atv->lines ()); setup (atv->lines ());
} }
@ -4108,6 +4120,7 @@ AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AudioRegionView* rv, l
list<boost::shared_ptr<AutomationLine> > lines; list<boost::shared_ptr<AutomationLine> > lines;
lines.push_back (rv->get_gain_line ()); lines.push_back (rv->get_gain_line ());
y_origin = rv->get_time_axis_view().y_position();
setup (lines); setup (lines);
} }
@ -4149,6 +4162,12 @@ AutomationRangeDrag::setup (list<boost::shared_ptr<AutomationLine> > const & lin
/* Now ::lines contains the AutomationLines that somehow overlap our drag */ /* Now ::lines contains the AutomationLines that somehow overlap our drag */
} }
double
AutomationRangeDrag::y_fraction (boost::shared_ptr<AutomationLine> line, double global_y) const
{
return 1.0 - ((global_y - y_origin) / line->height());
}
void void
AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{ {
@ -4157,6 +4176,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
/* Get line states before we start changing things */ /* Get line states before we start changing things */
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) { for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
i->state = &i->line->get_state (); i->state = &i->line->get_state ();
i->original_fraction = y_fraction (i->line, _drags->current_pointer_y());
} }
if (_ranges.empty()) { if (_ranges.empty()) {
@ -4262,7 +4282,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
} }
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) { for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
i->line->start_drag_multiple (i->points, 1 - (_drags->current_pointer_y() / i->line->height ()), i->state); i->line->start_drag_multiple (i->points, y_fraction (i->line, _drags->current_pointer_y()), i->state);
} }
} }
@ -4273,11 +4293,12 @@ AutomationRangeDrag::motion (GdkEvent*, bool /*first_move*/)
return; return;
} }
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) { for (list<Line>::iterator l = _lines.begin(); l != _lines.end(); ++l) {
float const f = 1 - (_drags->current_pointer_y() / i->line->height()); float const f = y_fraction (l->line, _drags->current_pointer_y());
/* we are ignoring x position for this drag, so we can just pass in anything */ /* we are ignoring x position for this drag, so we can just pass in anything */
i->line->drag_motion (0, f, true, false); l->line->drag_motion (0, f, true, false);
show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (l->original_fraction, f));
} }
} }

View file

@ -957,6 +957,7 @@ public:
private: private:
void setup (std::list<boost::shared_ptr<AutomationLine> > const &); void setup (std::list<boost::shared_ptr<AutomationLine> > const &);
double y_fraction (boost::shared_ptr<AutomationLine>, double global_y_position) const;
std::list<ARDOUR::AudioRange> _ranges; std::list<ARDOUR::AudioRange> _ranges;
@ -966,10 +967,11 @@ private:
std::list<ControlPoint*> points; ///< points to drag on the line std::list<ControlPoint*> points; ///< points to drag on the line
std::pair<ARDOUR::framepos_t, ARDOUR::framepos_t> range; ///< the range of all points on the line, in session frames std::pair<ARDOUR::framepos_t, ARDOUR::framepos_t> range; ///< the range of all points on the line, in session frames
XMLNode* state; ///< the XML state node before the drag XMLNode* state; ///< the XML state node before the drag
double original_fraction; ///< initial y-fraction before the drag
}; };
std::list<Line> _lines; std::list<Line> _lines;
double y_origin;
bool _nothing_to_drag; bool _nothing_to_drag;
}; };

View file

@ -2081,7 +2081,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item); ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
if (rect) { if (rect) {
rect->property_fill_color_rgba() = rv->get_fill_color(); rect->property_fill_color_rgba() = rv->get_fill_color();
rect->property_outline_pixels() = 0;
} }
} }
set_canvas_cursor (current_canvas_cursor); set_canvas_cursor (current_canvas_cursor);

View file

@ -817,25 +817,14 @@ EditorRoutes::sync_order_keys_from_model ()
bool changed = false; bool changed = false;
uint32_t order = 0; uint32_t order = 0;
for (ri = rows.begin(); ri != rows.end(); ++ri) { for (ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
boost::shared_ptr<Route> route = (*ri)[_columns.route]; 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 (EditorSort);
uint32_t new_key;
if (!visible) { if (order != old_key) {
new_key = UINT_MAX; route->set_order_key (EditorSort, order);
} else {
new_key = order;
}
if (old_key != new_key) {
route->set_order_key (EditorSort, new_key);
changed = true; changed = true;
} }
order++;
} }
if (changed) { if (changed) {
@ -847,6 +836,10 @@ EditorRoutes::sync_order_keys_from_model ()
void void
EditorRoutes::sync_model_from_order_keys (RouteSortOrderKey src) EditorRoutes::sync_model_from_order_keys (RouteSortOrderKey src)
{ {
/* Some route order key(s) for `src' has been changed, make sure that
we update out tree/list model and GUI to reflect the change.
*/
if (!_session || _session->deletion_in_progress()) { if (!_session || _session->deletion_in_progress()) {
return; return;
} }
@ -873,6 +866,11 @@ EditorRoutes::sync_model_from_order_keys (RouteSortOrderKey src)
} }
} }
/* 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
* order for the GUI, so reorder the treeview model to match it.
*/
/* we could get here after either a change in the Mixer or Editor sort /* 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 * order, but either way, the mixer order keys reflect the intended
* order for the GUI, so reorder the treeview model to match it. * order for the GUI, so reorder the treeview model to match it.
@ -880,7 +878,8 @@ EditorRoutes::sync_model_from_order_keys (RouteSortOrderKey src)
vector<int> neworder; vector<int> neworder;
TreeModel::Children rows = _model->children(); TreeModel::Children rows = _model->children();
uint32_t n = 0; uint32_t old_order = 0;
bool changed = false;
if (rows.empty()) { if (rows.empty()) {
return; return;
@ -888,14 +887,22 @@ EditorRoutes::sync_model_from_order_keys (RouteSortOrderKey src)
neworder.assign (rows.size(), 0); neworder.assign (rows.size(), 0);
for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++n) { for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
boost::shared_ptr<Route> route = (*ri)[_columns.route]; boost::shared_ptr<Route> route = (*ri)[_columns.route];
neworder[route->order_key (EditorSort)] = n; uint32_t new_order = route->order_key (EditorSort);
DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor change order for %1 to %2\n",
route->name(), route->order_key (MixerSort))); DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor change order for %1 from %2 to %3\n",
route->name(), old_order, new_order));
neworder[new_order] = old_order;
if (old_order != new_order) {
changed = true;
} }
{ }
if (changed) {
Unwinder<bool> uw (_ignore_reorder, true); Unwinder<bool> uw (_ignore_reorder, true);
_model->reorder (neworder); _model->reorder (neworder);
} }
@ -1595,26 +1602,3 @@ EditorRoutes::show_tracks_with_regions_at_playhead ()
resume_redisplay (); resume_redisplay ();
} }
uint32_t
EditorRoutes::count_displayed_non_special_routes () const
{
if (!_model) {
return 0;
}
uint32_t cnt = 0;
TreeModel::Children rows = _model->children ();
for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
bool visible = (*i)[_columns.visible];
if (visible) {
boost::shared_ptr<Route> route = (*i)[_columns.route];
if (route) {
if (route->is_master() || route->is_monitor()) {
continue;
}
cnt++;
}
}
}
return cnt;
}

View file

@ -59,7 +59,6 @@ public:
std::list<TimeAxisView*> views () const; std::list<TimeAxisView*> views () const;
void hide_all_tracks (bool); void hide_all_tracks (bool);
void clear (); void clear ();
uint32_t count_displayed_non_special_routes () const;
void sync_order_keys_from_model (); void sync_order_keys_from_model ();
private: private:

View file

@ -1114,6 +1114,7 @@ EngineControl::get_device_name (const string& driver, const string& human_readab
another computer system in it another computer system in it
*/ */
MessageDialog msg (_("You need to choose an audio device first.")); MessageDialog msg (_("You need to choose an audio device first."));
msg.set_position (WIN_POS_MOUSE);
msg.run (); msg.run ();
return string(); return string();
} }

View file

@ -772,6 +772,8 @@ MixerStrip::edit_output_configuration ()
} else { } else {
output_selector->present (); output_selector->present ();
} }
output_selector->set_keep_above (true);
} }
void void
@ -786,6 +788,8 @@ MixerStrip::edit_input_configuration ()
} else { } else {
input_selector->present (); input_selector->present ();
} }
input_selector->set_keep_above (true);
} }
gint gint

View file

@ -413,21 +413,12 @@ Mixer_UI::sync_order_keys_from_model ()
bool changed = false; bool changed = false;
uint32_t order = 0; uint32_t order = 0;
for (ri = rows.begin(); ri != rows.end(); ++ri) { for (ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
boost::shared_ptr<Route> route = (*ri)[track_columns.route]; 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 (MixerSort);
uint32_t new_key;
if (!visible) { if (old_key != order) {
new_key = UINT_MAX; route->set_order_key (MixerSort, order);
} else {
new_key = order;
}
if (old_key != new_key) {
route->set_order_key (MixerSort, new_key);
changed = true; changed = true;
} }
@ -477,6 +468,7 @@ Mixer_UI::sync_model_from_order_keys (RouteSortOrderKey src)
vector<int> neworder; vector<int> neworder;
TreeModel::Children rows = track_model->children(); TreeModel::Children rows = track_model->children();
uint32_t n = 0; uint32_t n = 0;
bool changed = false;
if (rows.empty()) { if (rows.empty()) {
return; return;
@ -486,12 +478,19 @@ Mixer_UI::sync_model_from_order_keys (RouteSortOrderKey src)
for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++n) { for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++n) {
boost::shared_ptr<Route> route = (*ri)[track_columns.route]; boost::shared_ptr<Route> route = (*ri)[track_columns.route];
neworder[route->order_key (MixerSort)] = n; uint32_t o = route->order_key (MixerSort);
neworder[o] = n;
if (o != n) {
changed = true;
}
DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("mixer change order for %1 to %2\n", DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("mixer change order for %1 to %2\n",
route->name(), route->order_key (MixerSort))); route->name(), route->order_key (MixerSort)));
} }
{ if (changed) {
Unwinder<bool> uw (ignore_reorder, true); Unwinder<bool> uw (ignore_reorder, true);
track_model->reorder (neworder); track_model->reorder (neworder);
} }
@ -693,6 +692,7 @@ Mixer_UI::show_strip (MixerStrip* ms)
MixerStrip* strip = (*i)[track_columns.strip]; MixerStrip* strip = (*i)[track_columns.strip];
if (strip == ms) { if (strip == ms) {
(*i)[track_columns.visible] = true; (*i)[track_columns.visible] = true;
redisplay_track_list ();
break; break;
} }
} }
@ -709,6 +709,7 @@ Mixer_UI::hide_strip (MixerStrip* ms)
MixerStrip* strip = (*i)[track_columns.strip]; MixerStrip* strip = (*i)[track_columns.strip];
if (strip == ms) { if (strip == ms) {
(*i)[track_columns.visible] = false; (*i)[track_columns.visible] = false;
redisplay_track_list ();
break; break;
} }
} }
@ -986,6 +987,8 @@ Mixer_UI::initial_track_display ()
add_strips (copy); add_strips (copy);
} }
_session->sync_order_keys (MixerSort);
redisplay_track_list (); redisplay_track_list ();
} }
@ -1023,7 +1026,6 @@ Mixer_UI::track_display_button_press (GdkEventButton* ev)
return false; return false;
case 1: /* visibility */ case 1: /* visibility */
if ((iter = track_model->get_iter (path))) { if ((iter = track_model->get_iter (path))) {
MixerStrip* strip = (*iter)[track_columns.strip]; MixerStrip* strip = (*iter)[track_columns.strip];
if (strip) { if (strip) {
@ -1031,10 +1033,8 @@ Mixer_UI::track_display_button_press (GdkEventButton* ev)
if (!strip->route()->is_master() && !strip->route()->is_monitor()) { if (!strip->route()->is_master() && !strip->route()->is_monitor()) {
bool visible = (*iter)[track_columns.visible]; bool visible = (*iter)[track_columns.visible];
(*iter)[track_columns.visible] = !visible; (*iter)[track_columns.visible] = !visible;
redisplay_track_list ();
} }
#ifdef GTKOSX
track_display.queue_draw();
#endif
} }
} }
return true; return true;

View file

@ -241,10 +241,16 @@ ShuttleControl::on_button_press_event (GdkEventButton* ev)
switch (ev->button) { switch (ev->button) {
case 1: case 1:
if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
if (_session->transport_rolling()) {
_session->request_transport_speed (1.0);
}
} else {
add_modal_grab (); add_modal_grab ();
shuttle_grabbed = true; shuttle_grabbed = true;
shuttle_speed_on_grab = _session->transport_speed (); shuttle_speed_on_grab = _session->transport_speed ();
mouse_shuttle (ev->x, true); mouse_shuttle (ev->x, true);
}
break; break;
case 2: case 2:
@ -265,6 +271,7 @@ ShuttleControl::on_button_release_event (GdkEventButton* ev)
switch (ev->button) { switch (ev->button) {
case 1: case 1:
if (shuttle_grabbed) {
shuttle_grabbed = false; shuttle_grabbed = false;
remove_modal_grab (); remove_modal_grab ();
@ -273,7 +280,7 @@ ShuttleControl::on_button_release_event (GdkEventButton* ev)
} else { } else {
mouse_shuttle (ev->x, true); mouse_shuttle (ev->x, true);
} }
}
return true; return true;
case 2: case 2:

View file

@ -21,6 +21,7 @@
#include "pbd/failed_constructor.h" #include "pbd/failed_constructor.h"
#include "pbd/file_utils.h" #include "pbd/file_utils.h"
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "ardour/filesystem_paths.h" #include "ardour/filesystem_paths.h"
@ -44,6 +45,7 @@ Splash::Splash ()
std::string splash_file; std::string splash_file;
if (!find_file_in_search_path (ardour_data_search_path(), "splash.png", splash_file)) { if (!find_file_in_search_path (ardour_data_search_path(), "splash.png", splash_file)) {
cerr << "Cannot find splash screen image file\n";
throw failed_constructor(); throw failed_constructor();
} }
@ -52,6 +54,7 @@ Splash::Splash ()
} }
catch (...) { catch (...) {
cerr << "Cannot construct splash screen image\n";
throw failed_constructor(); throw failed_constructor();
} }
@ -77,6 +80,8 @@ Splash::Splash ()
set_default_size (pixbuf->get_width(), pixbuf->get_height()); set_default_size (pixbuf->get_width(), pixbuf->get_height());
the_splash = this; the_splash = this;
expose_done = false;
ARDOUR::BootMessage.connect (msg_connection, invalidator (*this), boost::bind (&Splash::boot_message, this, _1), gui_context()); ARDOUR::BootMessage.connect (msg_connection, invalidator (*this), boost::bind (&Splash::boot_message, this, _1), gui_context());
} }
@ -107,10 +112,15 @@ Splash::on_realize ()
layout->set_font_description (get_style()->get_font()); layout->set_font_description (get_style()->get_font());
} }
bool bool
Splash::on_button_release_event (GdkEventButton*) Splash::on_button_release_event (GdkEventButton* ev)
{ {
RefPtr<Gdk::Window> window = get_window();
if (!window || ev->window != window->gobj()) {
return false;
}
hide (); hide ();
return true; return true;
} }
@ -136,6 +146,8 @@ Splash::expose (GdkEventExpose* ev)
window->draw_layout (white, 10, pixbuf->get_height() - 30, layout); window->draw_layout (white, 10, pixbuf->get_height() - 30, layout);
Glib::signal_idle().connect (sigc::mem_fun (this, &Splash::idle_after_expose));
return true; return true;
} }
@ -145,6 +157,32 @@ Splash::boot_message (std::string msg)
message (msg); message (msg);
} }
bool
Splash::idle_after_expose ()
{
expose_done = true;
return false;
}
void
Splash::display ()
{
bool was_mapped = is_mapped ();
if (!was_mapped) {
expose_done = false;
}
pop_front ();
present ();
if (!was_mapped) {
while (!expose_done) {
gtk_main_iteration ();
}
}
}
void void
Splash::message (const string& msg) Splash::message (const string& msg)
{ {
@ -156,9 +194,12 @@ Splash::message (const string& msg)
Glib::RefPtr<Gdk::Window> win = darea.get_window(); Glib::RefPtr<Gdk::Window> win = darea.get_window();
if (win) { if (win) {
win->invalidate_rect (Gdk::Rectangle (0, darea.get_height() - 30, expose_done = false;
darea.get_width(), 30), true);
win->process_updates (true); win->invalidate_rect (Gdk::Rectangle (0, darea.get_height() - 30, darea.get_width(), 30), true);
gdk_flush ();
while (!expose_done) {
gtk_main_iteration ();
}
} }
} }

View file

@ -38,6 +38,7 @@ class Splash : public Gtk::Window
static Splash* instance() { return the_splash; } static Splash* instance() { return the_splash; }
void display ();
void pop_back_for (Gtk::Window&); void pop_back_for (Gtk::Window&);
void pop_front (); void pop_front ();
@ -56,6 +57,9 @@ class Splash : public Gtk::Window
void boot_message (std::string); void boot_message (std::string);
PBD::ScopedConnection msg_connection; PBD::ScopedConnection msg_connection;
bool expose_done;
bool idle_after_expose ();
}; };
#endif /* __ardour_gtk_splash_h__ */ #endif /* __ardour_gtk_splash_h__ */

View file

@ -623,7 +623,10 @@ void
ArdourStartup::on_apply () ArdourStartup::on_apply ()
{ {
if (engine_dialog) { if (engine_dialog) {
engine_dialog->setup_engine (); if (engine_dialog->setup_engine ()) {
set_current_page (audio_page_index);
return;
}
} }
if (config_modified) { if (config_modified) {

View file

@ -35,6 +35,7 @@
#include "ardour/filesystem_paths.h" #include "ardour/filesystem_paths.h"
#include "ardour_button.h" #include "ardour_button.h"
#include "canvas-waveview.h"
#include "theme_manager.h" #include "theme_manager.h"
#include "rgb_macros.h" #include "rgb_macros.h"
#include "ardour_ui.h" #include "ardour_ui.h"
@ -56,6 +57,7 @@ ThemeManager::ThemeManager()
, light_button (_("Light Theme")) , light_button (_("Light Theme"))
, reset_button (_("Restore Defaults")) , reset_button (_("Restore Defaults"))
, flat_buttons (_("Draw \"flat\" buttons")) , flat_buttons (_("Draw \"flat\" buttons"))
, gradient_waveforms (_("Draw waveforms with color gradient"))
{ {
set_title (_("Theme Manager")); set_title (_("Theme Manager"));
@ -91,6 +93,7 @@ ThemeManager::ThemeManager()
vbox->pack_start (theme_selection_hbox, PACK_SHRINK); vbox->pack_start (theme_selection_hbox, PACK_SHRINK);
vbox->pack_start (reset_button, PACK_SHRINK); vbox->pack_start (reset_button, PACK_SHRINK);
vbox->pack_start (flat_buttons, PACK_SHRINK); vbox->pack_start (flat_buttons, PACK_SHRINK);
vbox->pack_start (gradient_waveforms, PACK_SHRINK);
vbox->pack_start (scroller); vbox->pack_start (scroller);
add (*vbox); add (*vbox);
@ -105,6 +108,7 @@ ThemeManager::ThemeManager()
light_button.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_light_theme_button_toggled)); light_button.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_light_theme_button_toggled));
reset_button.signal_clicked().connect (sigc::mem_fun (*this, &ThemeManager::reset_canvas_colors)); reset_button.signal_clicked().connect (sigc::mem_fun (*this, &ThemeManager::reset_canvas_colors));
flat_buttons.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_flat_buttons_toggled)); flat_buttons.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_flat_buttons_toggled));
gradient_waveforms.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_gradient_waveforms_toggled));
set_size_request (-1, 400); set_size_request (-1, 400);
setup_theme (); setup_theme ();
@ -238,6 +242,18 @@ ThemeManager::on_flat_buttons_toggled ()
gtk_rc_reset_styles (gtk_settings_get_default()); gtk_rc_reset_styles (gtk_settings_get_default());
} }
void
ThemeManager::on_gradient_waveforms_toggled ()
{
ARDOUR_UI::config()->gradient_waveforms.set (gradient_waveforms.get_active());
ARDOUR_UI::config()->set_dirty ();
gnome_canvas_waveview_set_gradient_waveforms (gradient_waveforms.get_active());
/* force a redraw */
gtk_rc_reset_styles (gtk_settings_get_default());
}
void void
ThemeManager::on_dark_theme_button_toggled() ThemeManager::on_dark_theme_button_toggled()
{ {
@ -347,6 +363,7 @@ ThemeManager::setup_theme ()
} }
flat_buttons.set_active (ARDOUR_UI::config()->flat_buttons.get()); flat_buttons.set_active (ARDOUR_UI::config()->flat_buttons.get());
gradient_waveforms.set_active (ARDOUR_UI::config()->gradient_waveforms.get());
load_rc_file(rcfile, false); load_rc_file(rcfile, false);
} }

View file

@ -43,6 +43,7 @@ class ThemeManager : public ArdourWindow
void on_dark_theme_button_toggled (); void on_dark_theme_button_toggled ();
void on_light_theme_button_toggled (); void on_light_theme_button_toggled ();
void on_flat_buttons_toggled (); void on_flat_buttons_toggled ();
void on_gradient_waveforms_toggled ();
private: private:
struct ColorDisplayModelColumns : public Gtk::TreeModel::ColumnRecord { struct ColorDisplayModelColumns : public Gtk::TreeModel::ColumnRecord {
@ -69,6 +70,7 @@ class ThemeManager : public ArdourWindow
Gtk::RadioButton light_button; Gtk::RadioButton light_button;
Gtk::Button reset_button; Gtk::Button reset_button;
Gtk::CheckButton flat_buttons; Gtk::CheckButton flat_buttons;
Gtk::CheckButton gradient_waveforms;
bool button_press_event (GdkEventButton*); bool button_press_event (GdkEventButton*);
}; };

View file

@ -1,3 +1,4 @@
UI_CONFIG_VARIABLE(std::string, ui_rc_file, "ui-rc-file", "ardour3_ui_dark.rc") UI_CONFIG_VARIABLE(std::string, ui_rc_file, "ui-rc-file", "ardour3_ui_dark.rc")
UI_CONFIG_VARIABLE(bool, flat_buttons, "flat-buttons", false) UI_CONFIG_VARIABLE(bool, flat_buttons, "flat-buttons", false)
UI_CONFIG_VARIABLE(bool, gradient_waveforms, "gradient-waveforms", false)

View file

@ -106,7 +106,7 @@ void CAAUParameter::Init (AudioUnit au, AudioUnitParameterID param, AudioUnitSc
} else } else
mParamName = CFStringCreateWithCString(NULL, mParamInfo.name, kCFStringEncodingUTF8); mParamName = CFStringCreateWithCString(NULL, mParamInfo.name, kCFStringEncodingUTF8);
char* str = 0; const char* str = 0;
switch (mParamInfo.unit) switch (mParamInfo.unit)
{ {
case kAudioUnitParameterUnit_Boolean: case kAudioUnitParameterUnit_Boolean:

View file

@ -81,6 +81,7 @@ public:
: AutomationControl (session, param, al, name) : AutomationControl (session, param, al, name)
, _amp (a) { , _amp (a) {
set_flags (Controllable::Flag (flags() | Controllable::GainLike)); set_flags (Controllable::Flag (flags() | Controllable::GainLike));
alist()->reset_default (1.0);
} }
void set_value (double val); void set_value (double val);

View file

@ -255,6 +255,9 @@ class Plugin : public PBD::StatefulDestructible, public Latent
void set_cycles (uint32_t c) { _cycles = c; } void set_cycles (uint32_t c) { _cycles = c; }
cycles_t cycles() const { return _cycles; } cycles_t cycles() const { return _cycles; }
PBD::Signal1<void,uint32_t> StartTouch;
PBD::Signal1<void,uint32_t> EndTouch;
protected: protected:
friend class PluginInsert; friend class PluginInsert;

View file

@ -142,7 +142,7 @@ class PluginInsert : public Processor
/* disallow copy construction */ /* disallow copy construction */
PluginInsert (const PluginInsert&); PluginInsert (const PluginInsert&);
void parameter_changed (Evoral::Parameter, float); void parameter_changed (uint32_t, float);
void set_parameter (Evoral::Parameter param, float val); void set_parameter (Evoral::Parameter param, float val);
float get_parameter (Evoral::Parameter param); float get_parameter (Evoral::Parameter param);
@ -185,6 +185,9 @@ class PluginInsert : public Processor
boost::shared_ptr<Plugin> plugin_factory (boost::shared_ptr<Plugin>); boost::shared_ptr<Plugin> plugin_factory (boost::shared_ptr<Plugin>);
void add_plugin (boost::shared_ptr<Plugin>); void add_plugin (boost::shared_ptr<Plugin>);
void start_touch (uint32_t param_id);
void end_touch (uint32_t param_id);
}; };
} // namespace ARDOUR } // namespace ARDOUR

View file

@ -423,6 +423,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
void set_remote_control_id (uint32_t id, bool notify_class_listeners = true); void set_remote_control_id (uint32_t id, bool notify_class_listeners = true);
uint32_t remote_control_id () const; uint32_t remote_control_id () const;
void set_remote_control_id_from_order_key (RouteSortOrderKey);
/* for things concerned about *this* route's RID */ /* for things concerned about *this* route's RID */
@ -534,7 +535,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
typedef std::map<RouteSortOrderKey,uint32_t> OrderKeys; typedef std::map<RouteSortOrderKey,uint32_t> OrderKeys;
OrderKeys order_keys; OrderKeys order_keys;
uint32_t* _remote_control_id; uint32_t _remote_control_id;
void input_change_handler (IOChange, void *src); void input_change_handler (IOChange, void *src);
void output_change_handler (IOChange, void *src); void output_change_handler (IOChange, void *src);

View file

@ -235,6 +235,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
}; };
void sync_order_keys (RouteSortOrderKey); void sync_order_keys (RouteSortOrderKey);
void sync_remote_id_from_order_keys (RouteSortOrderKey);
template<class T> void foreach_route (T *obj, void (T::*func)(Route&)); 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>)); template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>));

View file

@ -672,7 +672,7 @@ AudioTrack::freeze_me (InterThreadInfo& itt)
for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) { for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
if (!(*r)->does_routing()) { if (!(*r)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*r)) {
FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo ((*r)->get_state(), (*r)); FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo ((*r)->get_state(), (*r));

View file

@ -2753,6 +2753,26 @@ AUPlugin::listen_to_parameter (uint32_t param_id)
return -1; return -1;
} }
event.mEventType = kAudioUnitEvent_BeginParameterChangeGesture;
event.mArgument.mParameter.mAudioUnit = unit->AU();
event.mArgument.mParameter.mParameterID = descriptors[param_id].id;
event.mArgument.mParameter.mScope = descriptors[param_id].scope;
event.mArgument.mParameter.mElement = descriptors[param_id].element;
if (AUEventListenerAddEventType (_parameter_listener, _parameter_listener_arg, &event) != noErr) {
return -1;
}
event.mEventType = kAudioUnitEvent_EndParameterChangeGesture;
event.mArgument.mParameter.mAudioUnit = unit->AU();
event.mArgument.mParameter.mParameterID = descriptors[param_id].id;
event.mArgument.mParameter.mScope = descriptors[param_id].scope;
event.mArgument.mParameter.mElement = descriptors[param_id].element;
if (AUEventListenerAddEventType (_parameter_listener, _parameter_listener_arg, &event) != noErr) {
return -1;
}
return 0; return 0;
} }
@ -2775,6 +2795,26 @@ AUPlugin::end_listen_to_parameter (uint32_t param_id)
return -1; return -1;
} }
event.mEventType = kAudioUnitEvent_BeginParameterChangeGesture;
event.mArgument.mParameter.mAudioUnit = unit->AU();
event.mArgument.mParameter.mParameterID = descriptors[param_id].id;
event.mArgument.mParameter.mScope = descriptors[param_id].scope;
event.mArgument.mParameter.mElement = descriptors[param_id].element;
if (AUEventListenerRemoveEventType (_parameter_listener, _parameter_listener_arg, &event) != noErr) {
return -1;
}
event.mEventType = kAudioUnitEvent_EndParameterChangeGesture;
event.mArgument.mParameter.mAudioUnit = unit->AU();
event.mArgument.mParameter.mParameterID = descriptors[param_id].id;
event.mArgument.mParameter.mScope = descriptors[param_id].scope;
event.mArgument.mParameter.mElement = descriptors[param_id].element;
if (AUEventListenerRemoveEventType (_parameter_listener, _parameter_listener_arg, &event) != noErr) {
return -1;
}
return 0; return 0;
} }
@ -2787,9 +2827,23 @@ AUPlugin::_parameter_change_listener (void* arg, void* src, const AudioUnitEvent
void void
AUPlugin::parameter_change_listener (void* /*arg*/, void* /*src*/, const AudioUnitEvent* event, UInt64 /*host_time*/, Float32 new_value) AUPlugin::parameter_change_listener (void* /*arg*/, void* /*src*/, const AudioUnitEvent* event, UInt64 /*host_time*/, Float32 new_value)
{ {
ParameterMap::iterator i = parameter_map.find (event->mArgument.mParameter.mParameterID); ParameterMap::iterator i;
if (i != parameter_map.end()) { if ((i = parameter_map.find (event->mArgument.mParameter.mParameterID)) == parameter_map.end()) {
return;
}
switch (event->mEventType) {
case kAudioUnitEvent_BeginParameterChangeGesture:
StartTouch (i->second);
break;
case kAudioUnitEvent_EndParameterChangeGesture:
EndTouch (i->second);
break;
case kAudioUnitEvent_ParameterValueChange:
ParameterChanged (i->second, new_value); ParameterChanged (i->second, new_value);
break;
default:
break;
} }
} }

View file

@ -45,6 +45,7 @@ BufferManager::init (uint32_t size)
thread_buffers->write (&ts, 1); thread_buffers->write (&ts, 1);
thread_buffers_list->push_back (ts); thread_buffers_list->push_back (ts);
} }
} }
ThreadBuffers* ThreadBuffers*

View file

@ -303,7 +303,11 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization)
(void) PluginManager::instance(); (void) PluginManager::instance();
ProcessThread::init (); ProcessThread::init ();
BufferManager::init (hardware_concurrency() + 1); /* the + 4 is a bit of a handwave. i don't actually know
how many more per-thread buffer sets we need above
the h/w concurrency, but its definitely > 1 more.
*/
BufferManager::init (hardware_concurrency() + 4);
PannerManager::instance().discover_panners(); PannerManager::instance().discover_panners();

View file

@ -197,7 +197,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
template<typename T> template<typename T>
void void
MidiRingBuffer<T>::flush (framepos_t start, framepos_t end) MidiRingBuffer<T>::flush (framepos_t /*start*/, framepos_t end)
{ {
const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t); const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);

View file

@ -722,6 +722,13 @@ MidiTrack::act_on_mute ()
XXX we should should also stop all relevant note trackers. XXX we should should also stop all relevant note trackers.
*/ */
/* If we haven't got a diskstream yet, there's nothing to worry about,
and we can't call get_channel_mask() anyway.
*/
if (!midi_diskstream()) {
return;
}
if (muted()) { if (muted()) {
/* only send messages for channels we are using */ /* only send messages for channels we are using */

View file

@ -262,10 +262,12 @@ PluginInsert::create_automatable_parameters ()
} }
void void
PluginInsert::parameter_changed (Evoral::Parameter which, float val) PluginInsert::parameter_changed (uint32_t which, float val)
{ {
if (which.type() != PluginAutomation) boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, which));
return;
if (ac) {
ac->set_double (val);
Plugins::iterator i = _plugins.begin(); Plugins::iterator i = _plugins.begin();
@ -277,6 +279,7 @@ PluginInsert::parameter_changed (Evoral::Parameter which, float val)
(*i)->set_parameter (which, val); (*i)->set_parameter (which, val);
} }
} }
}
} }
int int
@ -1155,7 +1158,11 @@ PluginInsert::PluginControl::PluginControl (PluginInsert* p, const Evoral::Param
, _plugin (p) , _plugin (p)
{ {
Plugin::ParameterDescriptor desc; Plugin::ParameterDescriptor desc;
p->plugin(0)->get_parameter_descriptor (param.id(), desc); boost::shared_ptr<Plugin> plugin = p->plugin (0);
alist()->reset_default (plugin->default_value (param.id()));
plugin->get_parameter_descriptor (param.id(), desc);
_logarithmic = desc.logarithmic; _logarithmic = desc.logarithmic;
_sr_dependent = desc.sr_dependent; _sr_dependent = desc.sr_dependent;
_toggled = desc.toggled; _toggled = desc.toggled;
@ -1254,6 +1261,16 @@ void
PluginInsert::add_plugin (boost::shared_ptr<Plugin> plugin) PluginInsert::add_plugin (boost::shared_ptr<Plugin> plugin)
{ {
plugin->set_insert_info (this); plugin->set_insert_info (this);
if (_plugins.empty()) {
/* first (and probably only) plugin instance - connect to relevant signals
*/
plugin->ParameterChanged.connect_same_thread (*this, boost::bind (&PluginInsert::parameter_changed, this, _1, _2));
plugin->StartTouch.connect_same_thread (*this, boost::bind (&PluginInsert::start_touch, this, _1));
plugin->EndTouch.connect_same_thread (*this, boost::bind (&PluginInsert::end_touch, this, _1));
}
_plugins.push_back (plugin); _plugins.push_back (plugin);
} }
@ -1280,3 +1297,21 @@ PluginInsert::monitoring_changed ()
(*i)->monitoring_changed (); (*i)->monitoring_changed ();
} }
} }
void
PluginInsert::start_touch (uint32_t param_id)
{
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id));
if (ac) {
ac->start_touch (session().audible_frame());
}
}
void
PluginInsert::end_touch (uint32_t param_id)
{
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id));
if (ac) {
ac->stop_touch (true, session().audible_frame());
}
}

View file

@ -195,8 +195,6 @@ Route::~Route ()
} }
_processors.clear (); _processors.clear ();
delete _remote_control_id;
} }
void void
@ -232,11 +230,9 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
} }
if (id != remote_control_id()) { if (id != remote_control_id()) {
if (!_remote_control_id) { _remote_control_id = id;
_remote_control_id = new uint32_t;
}
*_remote_control_id = id;
RemoteControlIDChanged (); RemoteControlIDChanged ();
if (notify_class_listeners) { if (notify_class_listeners) {
RemoteControlIDChange (); RemoteControlIDChange ();
} }
@ -246,16 +242,6 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
uint32_t uint32_t
Route::remote_control_id() const Route::remote_control_id() const
{ {
switch (Config->get_remote_model()) {
case UserOrdered:
if (_remote_control_id) {
return *_remote_control_id;
}
break;
default:
break;
}
if (is_master()) { if (is_master()) {
return MasterBusRemoteControlID; return MasterBusRemoteControlID;
} }
@ -264,16 +250,7 @@ Route::remote_control_id() const
return MonitorBusRemoteControlID; return MonitorBusRemoteControlID;
} }
/* order keys are zero-based, remote control ID's are one-based return _remote_control_id;
*/
switch (Config->get_remote_model()) {
case EditorOrdered:
return order_key (EditorSort) + 1;
case MixerOrdered:
default:
return order_key (MixerSort) + 1;
}
} }
bool bool
@ -291,12 +268,25 @@ Route::order_key (RouteSortOrderKey key) const
return 0; return 0;
} }
return i->second; /* order keys are zero-based, remote control ID's are one-based
*/
switch (Config->get_remote_model()) {
case EditorOrdered:
return order_key (EditorSort) + 1;
case MixerOrdered:
default:
return order_key (MixerSort) + 1;
}
} }
void void
Route::sync_order_keys (RouteSortOrderKey base) 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); OrderKeys::iterator i = order_keys.find (base);
if (i == order_keys.end()) { if (i == order_keys.end()) {
@ -305,27 +295,113 @@ Route::sync_order_keys (RouteSortOrderKey base)
for (OrderKeys::iterator k = order_keys.begin(); k != order_keys.end(); ++k) { for (OrderKeys::iterator k = order_keys.begin(); k != order_keys.end(); ++k) {
if (k->first == MixerSort && (is_master() || is_monitor())) { if (is_master() || is_monitor()) {
/* don't sync the mixer sort keys for master/monitor, /* don't sync the sort keys for master/monitor,
* since they are not part of the normal ordering. * since they are not part of the normal ordering.
*/ */
continue; continue;
} }
if (k->first != base) { 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,
base));
k->second = i->second; k->second = i->second;
} }
} }
} }
void
Route::set_remote_control_id_from_order_key (RouteSortOrderKey key)
{
if (is_master() || is_monitor() || is_hidden()) {
/* hard-coded remote IDs, or no remote ID */
return;
}
uint32_t n = order_keys[key];
/* we have a nasty glitch in an otherwise fairly clean system here.
in theory, a route's remote control ID is determined by the order
key matching the current remote model (for UserOrdered, the user
controls everything). its one greater, because order keys are zero
based and remote control IDs start at one.
but ... an order key for the master bus may place it before or even
within normal routes, yet its remote control ID (like the monitor
bus) is hardcoded to MasterBusRemoteControlID. this means that all
routes ordered after it (in whatever controls the EditorSort or
MixerSort ordering) will end up with a remote control ID that is one
too large.
we therefore check on the master bus ordering, and adjust
later-sorted routes remote control ID to avoid this "off by one"
error, which keeps remote control ID's contiguous and "right".
ideally, this would be done in a UI layer, where this logic
is really understood and has meaning, rather than in libardour where
its fundamentally meaningless.
*/
switch (Config->get_remote_model()) {
case UserOrdered:
break;
case EditorOrdered:
if (key == EditorSort) {
boost::shared_ptr<Route> master = _session.master_out();
if (master && n > 0 && n > master->order_key (EditorSort)) {
--n;
}
_remote_control_id = n + 1;
DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: from order key %2, set edit-based RID to %3\n",
name(), n, _remote_control_id));
RemoteControlIDChanged (); /* EMIT SIGNAL * (per-route) */
}
break;
case MixerOrdered:
if (key == MixerSort) {
boost::shared_ptr<Route> master = _session.master_out();
if (master && n > 0 && n > master->order_key (MixerSort)) {
--n;
}
_remote_control_id = n + 1;
DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: from order key %2, set mix-based RID to %3\n",
name(), n, _remote_control_id));
RemoteControlIDChanged (); /* EMIT SIGNAL (per-route) */
}
break;
}
/* don't emit the class-level RID signal RemoteControlIDChange here,
leave that to the entity that changed the order key, so that we
don't get lots of emissions for no good reasons (e.g. when changing
all route order keys).
See Session::sync_remote_id_from_order_keys() for the (primary|only)
spot where that is emitted.
*/
}
void void
Route::set_order_key (RouteSortOrderKey key, uint32_t n) Route::set_order_key (RouteSortOrderKey key, uint32_t n)
{ {
if (order_keys.find (key) == order_keys.end() || order_keys[key] != n) { OrderKeys::iterator i = order_keys.find (key);
order_keys[key] = n;
_session.set_dirty (); if (i != order_keys.end() && i->second == n) {
return;
} }
order_keys[key] = n;
DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key %2 set to %3 (chk=%4)\n",
name(), enum_2_string (key), n, order_key (key)));
_session.set_dirty ();
} }
string string
@ -1894,12 +1970,10 @@ Route::state(bool full_state)
node->add_child_nocopy (_mute_control->get_state ()); node->add_child_nocopy (_mute_control->get_state ());
node->add_child_nocopy (_mute_master->get_state ()); node->add_child_nocopy (_mute_master->get_state ());
if (_remote_control_id) {
XMLNode* remote_control_node = new XMLNode (X_("RemoteControl")); XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
snprintf (buf, sizeof (buf), "%d", *_remote_control_id); snprintf (buf, sizeof (buf), "%d", _remote_control_id);
remote_control_node->add_property (X_("id"), buf); remote_control_node->add_property (X_("id"), buf);
node->add_child_nocopy (*remote_control_node); node->add_child_nocopy (*remote_control_node);
}
if (_comment.length()) { if (_comment.length()) {
XMLNode *cmt = node->add_child ("Comment"); XMLNode *cmt = node->add_child ("Comment");

View file

@ -574,6 +574,7 @@ Session::when_engine_running ()
BootMessage (_("Connect to engine")); BootMessage (_("Connect to engine"));
_engine.set_session (this); _engine.set_session (this);
_engine.reset_timebase ();
} }
void void
@ -2205,7 +2206,22 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
} }
RouteAdded (new_routes); /* EMIT SIGNAL */ RouteAdded (new_routes); /* EMIT SIGNAL */
Route::RemoteControlIDChange (); /* EMIT SIGNAL */
/* we added at least one new route, and everyone who needs to has now
* handled this event. This means that route order keys are correctly
* set and we can now ensure that remote control IDs are set.
*/
switch (Config->get_remote_model()) {
case UserOrdered:
break;
case MixerOrdered:
sync_remote_id_from_order_keys (MixerSort);
break;
case EditorOrdered:
sync_remote_id_from_order_keys (EditorSort);
break;
}
} }
void void
@ -3514,6 +3530,8 @@ Session::graph_reordered ()
boost::optional<framecnt_t> boost::optional<framecnt_t>
Session::available_capture_duration () Session::available_capture_duration ()
{ {
Glib::Mutex::Lock lm (space_lock);
if (_total_free_4k_blocks_uncertain) { if (_total_free_4k_blocks_uncertain) {
return boost::optional<framecnt_t> (); return boost::optional<framecnt_t> ();
} }
@ -4712,11 +4730,54 @@ Session::sync_order_keys (RouteSortOrderKey sort_key_changed)
/* tell everyone that something has happened to the sort keys /* tell everyone that something has happened to the sort keys
and let them sync up with the change(s) and let them sync up with the change(s)
this will give objects that manage the sort order keys the
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, string_compose ("Sync Order Keys, based on %1\n", enum_2_string (sort_key_changed)));
Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */ Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */
/* ensure that remote control IDs are in sync with the relevant
order keys.
*/
sync_remote_id_from_order_keys (sort_key_changed);
}
void
Session::sync_remote_id_from_order_keys (RouteSortOrderKey sort_key_changed)
{
/* update remote control IDs if that makes sense */
bool do_update = false;
DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("sync RID to order key %1\n", enum_2_string (sort_key_changed)));
switch (Config->get_remote_model()) {
case UserOrdered:
break;
case EditorOrdered:
if (sort_key_changed == EditorSort) {
do_update = true;
}
break;
case MixerOrdered:
if (sort_key_changed == MixerSort) {
do_update = true;
}
break;
}
if (do_update) {
DEBUG_TRACE (DEBUG::OrderKeys, "\tactually update + signal\n");
boost::shared_ptr<RouteList> r = routes.reader();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->set_remote_control_id_from_order_key (sort_key_changed);
}
Route::RemoteControlIDChange (); /* EMIT SIGNAL - static */
}
} }
bool bool

View file

@ -3506,8 +3506,33 @@ Session::config_changed (std::string p, bool ours)
setup_fpu (); setup_fpu ();
} else if (p == "history-depth") { } else if (p == "history-depth") {
set_history_depth (Config->get_history_depth()); set_history_depth (Config->get_history_depth());
} else if (p == "remote-model") {
switch (Config->get_remote_model()) {
case UserOrdered:
break;
case MixerOrdered:
sync_remote_id_from_order_keys (MixerSort);
break;
case EditorOrdered:
sync_remote_id_from_order_keys (EditorSort);
break;
}
} else if (p == "sync-all-route-ordering") { } else if (p == "sync-all-route-ordering") {
/* XXX sync_order_keys (UndefinedSort); */
/* 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") { } else if (p == "initial-program-change") {
if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) { if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) {

View file

@ -798,6 +798,14 @@ Session::start_locate (framepos_t target_frame, bool with_roll, bool with_flush,
if (target_frame != pos) { if (target_frame != pos) {
if (config.get_jack_time_master()) {
/* actually locate now, since otherwise jack_timebase_callback
will use the incorrect _transport_frame and report an old
and incorrect time to Jack transport
*/
locate (target_frame, with_roll, with_flush, with_loop, force);
}
/* tell JACK to change transport position, and we will /* tell JACK to change transport position, and we will
follow along later in ::follow_slave() follow along later in ::follow_slave()
*/ */

View file

@ -28,6 +28,7 @@
#include "ardour/processor.h" #include "ardour/processor.h"
#include "ardour/route_group_specialized.h" #include "ardour/route_group_specialized.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/session_playlists.h"
#include "ardour/track.h" #include "ardour/track.h"
#include "ardour/utils.h" #include "ardour/utils.h"
@ -333,12 +334,18 @@ Track::set_name (const string& str)
return false; return false;
} }
if (_diskstream->playlist()->all_regions_empty ()) { boost::shared_ptr<Track> me = boost::dynamic_pointer_cast<Track> (shared_from_this ());
if (_diskstream->playlist()->all_regions_empty () && _session.playlists->playlists_for_track (me).size() == 1) {
/* Only rename the diskstream (and therefore the playlist) if /* Only rename the diskstream (and therefore the playlist) if
the playlist has never had a region added to it. Otherwise a) the playlist has never had a region added to it and
people can get confused if, say, they have notes about a b) there is only one playlist for this track.
playlist with a given name and then it changes (see mantis
#4759). If (a) is not followed, people can get confused if, say,
they have notes about a playlist with a given name and then
it changes (see mantis #4759).
If (b) is not followed, we rename the current playlist and not
the other ones, which is a bit confusing (see mantis #4977).
*/ */
_diskstream->set_name (str); _diskstream->set_name (str);
} }

View file

@ -15,6 +15,7 @@
namespace AudioGrapher namespace AudioGrapher
{ {
/** /**
* Processing context. Constness only applies to data, not flags * Processing context. Constness only applies to data, not flags
*/ */
@ -23,6 +24,9 @@ template <typename T = DefaultSampleType>
class ProcessContext class ProcessContext
: public Throwing<> : public Throwing<>
{ {
// Support older compilers that don't support template base class initialization without template parameters
// This will need to be modified if if it's modified above
static const ThrowLevel throwLevel = DEFAULT_THROW_LEVEL;
BOOST_STATIC_ASSERT (boost::has_trivial_destructor<T>::value); BOOST_STATIC_ASSERT (boost::has_trivial_destructor<T>::value);
@ -43,25 +47,25 @@ public:
/// Normal copy constructor /// Normal copy constructor
ProcessContext (ProcessContext<T> const & other) ProcessContext (ProcessContext<T> const & other)
: _data (other._data), _frames (other._frames), _channels (other._channels), _flags (other._flags) : Throwing<throwLevel>(), _data (other._data), _frames (other._frames), _channels (other._channels), _flags (other._flags)
{ /* No need to validate data */ } { /* No need to validate data */ }
/// "Copy constructor" with unique data, frame and channel count, but copies flags /// "Copy constructor" with unique data, frame and channel count, but copies flags
template<typename Y> template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data, framecnt_t frames, ChannelCount channels) ProcessContext (ProcessContext<Y> const & other, T * data, framecnt_t frames, ChannelCount channels)
: _data (data), _frames (frames), _channels (channels), _flags (other.flags()) : Throwing<throwLevel>(), _data (data), _frames (frames), _channels (channels), _flags (other.flags())
{ validate_data(); } { validate_data(); }
/// "Copy constructor" with unique data and frame count, but copies channel count and flags /// "Copy constructor" with unique data and frame count, but copies channel count and flags
template<typename Y> template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data, framecnt_t frames) ProcessContext (ProcessContext<Y> const & other, T * data, framecnt_t frames)
: _data (data), _frames (frames), _channels (other.channels()), _flags (other.flags()) : Throwing<throwLevel>(), _data (data), _frames (frames), _channels (other.channels()), _flags (other.flags())
{ validate_data(); } { validate_data(); }
/// "Copy constructor" with unique data, but copies frame and channel count + flags /// "Copy constructor" with unique data, but copies frame and channel count + flags
template<typename Y> template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data) ProcessContext (ProcessContext<Y> const & other, T * data)
: _data (data), _frames (other.frames()), _channels (other.channels()), _flags (other.flags()) : Throwing<throwLevel>(), _data (data), _frames (other.frames()), _channels (other.channels()), _flags (other.flags())
{ /* No need to validate data */ } { /* No need to validate data */ }
/// Make new Context out of the beginning of this context /// Make new Context out of the beginning of this context

View file

@ -52,8 +52,6 @@
#ifndef SNDFILE_HH #ifndef SNDFILE_HH
#define SNDFILE_HH #define SNDFILE_HH
#include <iostream>
#include <sndfile.h> #include <sndfile.h>
#include <string> #include <string>
@ -171,7 +169,6 @@ SndfileHandle::SndfileHandle (const char *path, int mode, int fmt, int chans, in
p->sfinfo.seekable = 0 ; p->sfinfo.seekable = 0 ;
p->sf = sf_open (path, mode, &p->sfinfo) ; p->sf = sf_open (path, mode, &p->sfinfo) ;
std::cerr << "3 attempted to open " << path << " got " << p->sf << std::endl;
} ; } ;
return ; return ;
@ -194,7 +191,6 @@ SndfileHandle::SndfileHandle (std::string const & path, int mode, int fmt, int c
p->sfinfo.seekable = 0 ; p->sfinfo.seekable = 0 ;
p->sf = sf_open (path.c_str (), mode, &p->sfinfo) ; p->sf = sf_open (path.c_str (), mode, &p->sfinfo) ;
std::cerr << "attempted to open " << path << " got " << p->sf << std::endl;
} ; } ;
return ; return ;
@ -220,7 +216,6 @@ SndfileHandle::SndfileHandle (int fd, bool close_desc, int mode, int fmt, int ch
p->sfinfo.seekable = 0 ; p->sfinfo.seekable = 0 ;
p->sf = sf_open_fd (fd, mode, &p->sfinfo, close_desc) ; p->sf = sf_open_fd (fd, mode, &p->sfinfo, close_desc) ;
std::cerr << "2 attempted to open via fd " << fd << " got " << p->sf << std::endl;
} ; } ;
return ; return ;

View file

@ -291,10 +291,12 @@ protected:
EventList events; EventList events;
double start_time; double start_time;
double end_time; double end_time;
double same_value_cnt;
NascentInfo (double start = -1.0) NascentInfo (double start = -1.0)
: start_time (start) : start_time (start)
, end_time (-1.0) , end_time (-1.0)
, same_value_cnt (0)
{} {}
}; };

View file

@ -27,7 +27,6 @@ using namespace std;
namespace Evoral { namespace Evoral {
inline bool event_time_less_than (ControlEvent* a, ControlEvent* b) inline bool event_time_less_than (ControlEvent* a, ControlEvent* b)
{ {
return a->when < b->when; return a->when < b->when;
@ -254,12 +253,15 @@ ControlList::merge_nascent (double when)
return; return;
} }
bool was_empty = _events.empty();
for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) { for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) {
NascentInfo* ninfo = *n; NascentInfo* ninfo = *n;
EventList& nascent_events (ninfo->events); EventList& nascent_events (ninfo->events);
bool need_adjacent_start_clamp; bool need_adjacent_start_clamp;
bool need_adjacent_end_clamp; bool need_adjacent_end_clamp;
EventList::iterator at;
if (nascent_events.empty()) { if (nascent_events.empty()) {
delete ninfo; delete ninfo;
@ -276,22 +278,61 @@ ControlList::merge_nascent (double when)
ninfo->end_time = when; ninfo->end_time = when;
} }
bool preexisting = !_events.empty(); if (_events.empty()) {
if (!preexisting) { /* add an initial point just before
the nascent data, unless nascent_events
contains a point at zero or one
*/
_events = nascent_events; if (ninfo->start_time > 0) {
nascent_events.insert (nascent_events.begin(), new ControlEvent (ninfo->start_time - 1, _default_value));
}
/* add closing "clamp" point before we insert */
nascent_events.insert (nascent_events.end(), new ControlEvent (ninfo->end_time + 1, _default_value));
/* insert - front or back doesn't matter since
* _events is empty
*/
_events.insert (_events.begin(), nascent_events.begin(), nascent_events.end());
} else if (ninfo->end_time < _events.front()->when) { } else if (ninfo->end_time < _events.front()->when) {
/* all points in nascent are before the first existing point */ /* all points in nascent are before the first existing point */
if (ninfo->start_time > (_events.front()->when + 1)) {
nascent_events.insert (nascent_events.begin(), new ControlEvent (ninfo->start_time - 1, _default_value));
}
/* add closing "clamp" point before we insert */
nascent_events.insert (nascent_events.end(), new ControlEvent (ninfo->end_time + 1, _default_value));
/* insert at front */
_events.insert (_events.begin(), nascent_events.begin(), nascent_events.end()); _events.insert (_events.begin(), nascent_events.begin(), nascent_events.end());
/* now add another default control point right
after the inserted nascent data
*/
} else if (ninfo->start_time > _events.back()->when) { } else if (ninfo->start_time > _events.back()->when) {
/* all points in nascent are after the last existing point */ /* all points in nascent are after the last existing point */
if (ninfo->start_time > (_events.back()->when + 1)) {
nascent_events.insert (nascent_events.begin(), new ControlEvent (ninfo->start_time - 1, _default_value));
}
/* add closing "clamp" point before we insert */
nascent_events.insert (nascent_events.end(), new ControlEvent (ninfo->end_time + 1, _default_value));
/* insert */
_events.insert (_events.end(), nascent_events.begin(), nascent_events.end()); _events.insert (_events.end(), nascent_events.begin(), nascent_events.end());
} else { } else {
@ -350,7 +391,7 @@ ControlList::merge_nascent (double when)
range_begin is the first event on our list after the first nascent event range_begin is the first event on our list after the first nascent event
range_end is the first event on our list after the last nascent event range_end is the first event on our list after the last nascent event
range_begin may be equal to _events.end() iff the last event on our list range_begin may be equal to _events.end() if the last event on our list
was at the same time as the first nascent event. was at the same time as the first nascent event.
*/ */
@ -376,6 +417,12 @@ ControlList::merge_nascent (double when)
delete ninfo; delete ninfo;
} }
if (was_empty && !_events.empty()) {
if (_events.front()->when != 0) {
_events.insert (_events.begin(), new ControlEvent (0, _default_value));
}
}
nascent.clear (); nascent.clear ();
if (writing()) { if (writing()) {
@ -395,7 +442,7 @@ ControlList::rt_add (double when, double value)
return; return;
} }
//cerr << "RT: alist " << this << " add " << value << " @ " << when << endl; // cerr << "RT: alist " << this << " add " << value << " @ " << when << endl;
Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK); Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK);
@ -405,18 +452,28 @@ ControlList::rt_add (double when, double value)
sort them in merge_nascent. sort them in merge_nascent.
*/ */
EventList& el (nascent.back()->events); NascentInfo* ni (nascent.back());
EventList& el (ni->events);
if (!el.empty() && (when >= el.back()->when) && (value == el.back()->value)) {
if (el.size() > 1 && (when >= el.back()->when) && (value == el.back()->value)) {
/* same value, later timestamp, effective slope is /* same value, later timestamp, effective slope is
* zero, so just move the last point in nascent to our * zero, so just move the last point in nascent to our
* new time position. this avoids storing an unlimited * new time position. this avoids storing an unlimited
* number of points to represent a flat line. * number of points to represent a flat line.
*/ */
ni->same_value_cnt++;
if (ni->same_value_cnt > 1) {
el.back()->when = when; el.back()->when = when;
} else { return;
nascent.back()->events.push_back (new ControlEvent (when, value));
} }
} else {
ni->same_value_cnt = 0;
}
el.push_back (new ControlEvent (when, value));
} }
} }
@ -489,6 +546,12 @@ ControlList::add (double when, double value)
bool insert = true; bool insert = true;
iterator insertion_point; iterator insertion_point;
if (_events.empty()) {
if (when > 1) {
_events.insert (_events.end(), new ControlEvent (0, _default_value));
}
}
for (insertion_point = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); insertion_point != _events.end(); ++insertion_point) { for (insertion_point = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); insertion_point != _events.end(); ++insertion_point) {
/* only one point allowed per time point */ /* only one point allowed per time point */
@ -505,9 +568,7 @@ ControlList::add (double when, double value)
} }
if (insert) { if (insert) {
_events.insert (insertion_point, new ControlEvent (when, value)); _events.insert (insertion_point, new ControlEvent (when, value));
} }
mark_dirty (); mark_dirty ();

View file

@ -24,6 +24,7 @@
#include <glibmm/fileutils.h> #include <glibmm/fileutils.h>
#include <glibmm/miscutils.h> #include <glibmm/miscutils.h>
#include <glibmm/thread.h>
#include "pbd/controllable_descriptor.h" #include "pbd/controllable_descriptor.h"
#include "pbd/error.h" #include "pbd/error.h"
@ -284,6 +285,12 @@ GenericMidiControlProtocol::_send_feedback ()
in a single jack_midi_event_write then some bridges will only pass the in a single jack_midi_event_write then some bridges will only pass the
first on to ALSA. first on to ALSA.
*/ */
Glib::Mutex::Lock lm (controllables_lock, Glib::TRY_LOCK);
if (!lm.locked ()) {
return;
}
for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) { for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
MIDI::byte* end = (*r)->write_feedback (buf, bsize); MIDI::byte* end = (*r)->write_feedback (buf, bsize);
if (end != buf) { if (end != buf) {
@ -778,10 +785,7 @@ GenericMidiControlProtocol::reset_controllables ()
* binding" (or "lazy binding") if/when any data arrives. * binding" (or "lazy binding") if/when any data arrives.
*/ */
boost::shared_ptr<Controllable> c = session->controllable_by_descriptor (desc); existingBinding->lookup_controllable ();
if (c) {
existingBinding->set_controllable (c.get());
}
} }
iter = next; iter = next;

View file

@ -61,11 +61,12 @@ MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, bool
MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, Controllable& c, bool m) MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, Controllable& c, bool m)
: _surface (s) : _surface (s)
, controllable (&c)
, _descriptor (0) , _descriptor (0)
, _port (p) , _port (p)
, _momentary (m) , _momentary (m)
{ {
set_controllable (&c);
_learned = true; /* from controllable */ _learned = true; /* from controllable */
setting = false; setting = false;
last_value = 0; // got a better idea ? last_value = 0; // got a better idea ?
@ -113,7 +114,19 @@ MIDIControllable::drop_external_control ()
void void
MIDIControllable::set_controllable (Controllable* c) MIDIControllable::set_controllable (Controllable* c)
{ {
if (c == controllable) {
return;
}
controllable_death_connection.disconnect ();
controllable = c; controllable = c;
if (controllable) {
controllable->Destroyed.connect (controllable_death_connection, MISSING_INVALIDATOR,
boost::bind (&MIDIControllable::drop_controllable, this),
MidiControlUI::instance());
}
} }
void void
@ -199,10 +212,7 @@ MIDIControllable::lookup_controllable()
return -1; return -1;
} }
controllable = c.get(); set_controllable (c.get ());
controllable->Destroyed.connect (controllable_death_connection, MISSING_INVALIDATOR,
boost::bind (&MIDIControllable::drop_controllable, this),
MidiControlUI::instance());
return 0; return 0;
} }
@ -210,9 +220,8 @@ MIDIControllable::lookup_controllable()
void void
MIDIControllable::drop_controllable () MIDIControllable::drop_controllable ()
{ {
cerr << "removed controllable\n"; cerr << "removed controllable " << controllable << "\n";
controllable_death_connection.disconnect (); set_controllable (0);
controllable = 0;
} }
void void

View file

@ -89,6 +89,8 @@ class MIDIControllable : public PBD::Stateful
MIDI::eventType get_control_type () { return control_type; } MIDI::eventType get_control_type () { return control_type; }
MIDI::byte get_control_additional () { return control_additional; } MIDI::byte get_control_additional () { return control_additional; }
int lookup_controllable();
private: private:
int max_value_for_type () const; int max_value_for_type () const;
@ -118,7 +120,6 @@ class MIDIControllable : public PBD::Stateful
std::string _what; std::string _what;
bool _bank_relative; bool _bank_relative;
int lookup_controllable();
void drop_controllable(); void drop_controllable();
void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t); void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t);

View file

@ -5,12 +5,12 @@
<DeviceInfo bank-size="9" motorized="no" threshold="15"/> <DeviceInfo bank-size="9" motorized="no" threshold="15"/>
<!-- Transport Controls --> <!-- Transport Controls -->
<Binding channel="1" ctl="44" action="Transport/Record"/> <Binding msg="B0 2c 7f" function="rec-enable"/>
<Binding channel="1" ctl="45" function="transport-roll"/> <Binding msg="B0 2d 7f" function="transport-roll"/>
<Binding channel="1" ctl="46" function="transport-stop"/> <Binding msg="B0 2e 7f" function="transport-stop"/>
<Binding channel="1" ctl="47" function="transport-start"/> <Binding msg="B0 2f 7f" function="transport-start"/>
<Binding channel="1" ctl="48" function="transport-end"/> <Binding msg="B0 30 7f" function="transport-end"/>
<Binding channel="1" ctl="49" function="loop-toggle"/> <Binding msg="B0 31 7f" function="loop-toggle"/>
<!-- The "Scene" button toggles between four banks. For this to work as --> <!-- The "Scene" button toggles between four banks. For this to work as -->
<!-- intended, you have to configure all four scenes to be identical. --> <!-- intended, you have to configure all four scenes to be identical. -->

View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ArdourMIDIBindings version="1.1.0" name="Korg nanoKONTROL2">
<!-- Some advice: In the Korg control editor utility (Work fine under wine): -->
<!-- 1 : Set the main "RECORD", "loop" and the track "Solo" "Mute" and "Record" button to toggle-->
<!-- (normally they are on momentary) -->
<!-- 2012-07.03 Philippe Demartin inspired from the original NanoKontrol map by -->
<!-- 2010-11-26 Chooch Schubert: Map file creation -->
<DeviceInfo bank-size="8"/>
<Binding msg="B0 2d 7f" function="rec-enable"/>
<Binding msg="B0 2d 00" function="rec-disable"/>
<Binding channel="1" ctl="41" function="transport-roll"/>
<Binding channel="1" ctl="42" function="transport-stop"/>
<Binding channel="1" ctl="43" function="transport-start"/>
<Binding channel="1" ctl="44" function="transport-end"/>
<Binding channel="1" ctl="46" function="loop-toggle"/>
<Binding msg="B0 3c 7f" action="Editor/add-location-from-playhead"/>
<Binding msg="B0 3d 7f" action="Editor/jump-backward-to-mark"/>
<Binding msg="B0 3e 7f" action="Editor/jump-forward-to-mark"/>
<Binding msg="B0 3a 7f" function="prev-bank"/>
<Binding msg="B0 3b 7f" function="next-bank"/>
<!-- Channel controls: -->
<!-- - There is 3 buttons on each tarck. Assigned to -->
<!-- "Solo" "Mute" and "Record Enable". -->
<!-- - Channel pan is implemented now in Ardour-3, -->
<Binding channel="1" ctl="16" uri="/route/pandirection B1"/>
<Binding channel="1" ctl="32" uri="/route/solo B1"/>
<Binding channel="1" ctl="48" uri="/route/mute B1"/>
<Binding channel="1" ctl="64" uri="/route/recenable B1"/>
<Binding channel="1" ctl="0" uri="/route/gain B1"/>
<Binding channel="1" ctl="17" uri="/route/pandirection B2"/>
<Binding channel="1" ctl="33" uri="/route/solo B2"/>
<Binding channel="1" ctl="49" uri="/route/mute B2"/>
<Binding channel="1" ctl="65" uri="/route/recenable B2"/>
<Binding channel="1" ctl="1" uri="/route/gain B2"/>
<Binding channel="1" ctl="18" uri="/route/pandirection B3"/>
<Binding channel="1" ctl="34" uri="/route/solo B3"/>
<Binding channel="1" ctl="50" uri="/route/mute B3"/>
<Binding channel="1" ctl="66" uri="/route/recenable B3"/>
<Binding channel="1" ctl="2" uri="/route/gain B3"/>
<Binding channel="1" ctl="19" uri="/route/pandirection B4"/>
<Binding channel="1" ctl="35" uri="/route/solo B4"/>
<Binding channel="1" ctl="51" uri="/route/mute B4"/>
<Binding channel="1" ctl="67" uri="/route/recenable B4"/>
<Binding channel="1" ctl="3" uri="/route/gain B4"/>
<Binding channel="1" ctl="20" uri="/route/pandirection B5"/>
<Binding channel="1" ctl="36" uri="/route/solo B5"/>
<Binding channel="1" ctl="52" uri="/route/mute B5"/>
<Binding channel="1" ctl="68" uri="/route/recenable B5"/>
<Binding channel="1" ctl="4" uri="/route/gain B5"/>
<Binding channel="1" ctl="21" uri="/route/pandirection B6"/>
<Binding channel="1" ctl="37" uri="/route/solo B6"/>
<Binding channel="1" ctl="53" uri="/route/mute B6"/>
<Binding channel="1" ctl="69" uri="/route/recenable B6"/>
<Binding channel="1" ctl="5" uri="/route/gain B6"/>
<Binding channel="1" ctl="22" uri="/route/pandirection B7"/>
<Binding channel="1" ctl="38" uri="/route/solo B7"/>
<Binding channel="1" ctl="54" uri="/route/mute B7"/>
<Binding channel="1" ctl="70" uri="/route/recenable B7"/>
<Binding channel="1" ctl="6" uri="/route/gain B7"/>
<Binding channel="1" ctl="23" uri="/route/pandirection B8"/>
<Binding channel="1" ctl="39" uri="/route/solo B8"/>
<Binding channel="1" ctl="55" uri="/route/mute B8"/>
<Binding channel="1" ctl="71" uri="/route/recenable B8"/>
<Binding channel="1" ctl="7" uri="/route/gain B8"/>
</ArdourMIDIBindings>

View file

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<ArdourMIDIBindings version="1.1.0" name="Korg nanoKONTROL2 With Master">
<!-- This NanoKontrol2 map have some special feature. I use 7 channel for the tracks -->
<!-- and the Nº 8 for the master fader, for that reason, the "bank-size" is set to 7. -->
<!-- Some advice: In the Korg control editor utility (Work fine under wine): -->
<!-- 1 : Set the main "RECORD", "loop" and the track "Solo" "Mute" and "Record" button to toggle-->
<!-- (normally they are on momentary) -->
<!-- 2012-07.03 Philippe Demartin inspired from the original NanoKontrol map by -->
<!-- 2010-11-26 Chooch Schubert: Map file creation -->
<DeviceInfo bank-size="7"/>
<Binding msg="B0 2d 7f" function="rec-enable"/>
<Binding msg="B0 2d 00" function="rec-disable"/>
<Binding channel="1" ctl="41" function="transport-roll"/>
<Binding channel="1" ctl="42" function="transport-stop"/>
<Binding channel="1" ctl="43" function="transport-start"/>
<Binding channel="1" ctl="44" function="transport-end"/>
<Binding channel="1" ctl="46" function="loop-toggle"/>
<Binding msg="B0 3c 7f" action="Editor/add-location-from-playhead"/>
<Binding msg="B0 3d 7f" action="Editor/jump-backward-to-mark"/>
<Binding msg="B0 3e 7f" action="Editor/jump-forward-to-mark"/>
<Binding msg="B0 3a 7f" function="prev-bank"/>
<Binding msg="B0 3b 7f" function="next-bank"/>
<!-- Channel controls: -->
<!-- - There is 3 buttons on each tarck. Assigned to -->
<!-- "Solo" "Mute" and "Record Enable". -->
<!-- - Channel pan is implemented now in Ardour-3, -->
<Binding channel="1" ctl="16" uri="/route/pandirection B1"/>
<Binding channel="1" ctl="32" uri="/route/solo B1"/>
<Binding channel="1" ctl="48" uri="/route/mute B1"/>
<Binding channel="1" ctl="64" uri="/route/recenable B1"/>
<Binding channel="1" ctl="0" uri="/route/gain B1"/>
<Binding channel="1" ctl="17" uri="/route/pandirection B2"/>
<Binding channel="1" ctl="33" uri="/route/solo B2"/>
<Binding channel="1" ctl="49" uri="/route/mute B2"/>
<Binding channel="1" ctl="65" uri="/route/recenable B2"/>
<Binding channel="1" ctl="1" uri="/route/gain B2"/>
<Binding channel="1" ctl="18" uri="/route/pandirection B3"/>
<Binding channel="1" ctl="34" uri="/route/solo B3"/>
<Binding channel="1" ctl="50" uri="/route/mute B3"/>
<Binding channel="1" ctl="66" uri="/route/recenable B3"/>
<Binding channel="1" ctl="2" uri="/route/gain B3"/>
<Binding channel="1" ctl="19" uri="/route/pandirection B4"/>
<Binding channel="1" ctl="35" uri="/route/solo B4"/>
<Binding channel="1" ctl="51" uri="/route/mute B4"/>
<Binding channel="1" ctl="67" uri="/route/recenable B4"/>
<Binding channel="1" ctl="3" uri="/route/gain B4"/>
<Binding channel="1" ctl="20" uri="/route/pandirection B5"/>
<Binding channel="1" ctl="36" uri="/route/solo B5"/>
<Binding channel="1" ctl="52" uri="/route/mute B5"/>
<Binding channel="1" ctl="68" uri="/route/recenable B5"/>
<Binding channel="1" ctl="4" uri="/route/gain B5"/>
<Binding channel="1" ctl="21" uri="/route/pandirection B6"/>
<Binding channel="1" ctl="37" uri="/route/solo B6"/>
<Binding channel="1" ctl="53" uri="/route/mute B6"/>
<Binding channel="1" ctl="69" uri="/route/recenable B6"/>
<Binding channel="1" ctl="5" uri="/route/gain B6"/>
<Binding channel="1" ctl="22" uri="/route/pandirection B7"/>
<Binding channel="1" ctl="38" uri="/route/solo B7"/>
<Binding channel="1" ctl="54" uri="/route/mute B7"/>
<Binding channel="1" ctl="70" uri="/route/recenable B7"/>
<Binding channel="1" ctl="6" uri="/route/gain B7"/>
<!-- -Master section I use the pan pot as pan width, -->
<!--practical to listen to your mix in mono, -->
<!--the "Solo" button to enable and disable the mixer windows -->
<!--the "Mute" as intended and the "REC" is not used -->
<Binding channel="1" ctl="23" uri="/bus/panwidth master"/>
<Binding channel="1" ctl="39" action="Common/toggle-mixer-on-top"/>
<Binding channel="1" ctl="55" uri="/bus/mute master"/>
<Binding channel="1" ctl="7" uri="/bus/gain master"/>
</ArdourMIDIBindings>