mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-21 14:16:31 +01:00
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:
parent
576f73e032
commit
3bb7d368a8
57 changed files with 1595 additions and 280 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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__ */
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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 ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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__ */
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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*);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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>));
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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*
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 ;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 ();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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. -->
|
||||||
|
|
|
||||||
83
midi_maps/Korg_nanoKONTROL2.map
Normal file
83
midi_maps/Korg_nanoKONTROL2.map
Normal 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>
|
||||||
90
midi_maps/Korg_nanoKONTROL2_With_Master.map
Normal file
90
midi_maps/Korg_nanoKONTROL2_With_Master.map
Normal 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>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue