mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 15:25:01 +01:00
merged with 2.0-ongoing changes 2582-2605 (not thoroughly tested but it compiles, start up, and creates a new session)
git-svn-id: svn://localhost/ardour2/trunk@2606 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
df20e5935f
commit
badc087263
34 changed files with 1028 additions and 568 deletions
|
|
@ -155,7 +155,7 @@ ARDOUR_UI::install_actions ()
|
||||||
Glib::RefPtr<ActionGroup> jack_actions = ActionGroup::create (X_("JACK"));
|
Glib::RefPtr<ActionGroup> jack_actions = ActionGroup::create (X_("JACK"));
|
||||||
ActionManager::register_action (jack_actions, X_("JACK"), _("JACK"));
|
ActionManager::register_action (jack_actions, X_("JACK"), _("JACK"));
|
||||||
ActionManager::register_action (jack_actions, X_("Latency"), _("Latency"));
|
ActionManager::register_action (jack_actions, X_("Latency"), _("Latency"));
|
||||||
|
|
||||||
act = ActionManager::register_action (jack_actions, X_("JACKReconnect"), _("Reconnect"), mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::reconnect_to_jack));
|
act = ActionManager::register_action (jack_actions, X_("JACKReconnect"), _("Reconnect"), mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::reconnect_to_jack));
|
||||||
ActionManager::jack_opposite_sensitive_actions.push_back (act);
|
ActionManager::jack_opposite_sensitive_actions.push_back (act);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#define IMPORTMODE(a) /*empty*/
|
#define IMPORTMODE(a) /*empty*/
|
||||||
#define IMPORTPOSITION(a)
|
#define IMPORTPOSITION(a)
|
||||||
#define IMPORTDISPOSITION(a)
|
#define IMPORTDISPOSITION(a)
|
||||||
|
#define EDITPOINT(a) /*empty*/
|
||||||
|
|
||||||
namespace Editing {
|
namespace Editing {
|
||||||
|
|
||||||
|
|
@ -168,6 +169,16 @@ enum ImportDisposition {
|
||||||
#undef IMPORTDISPOSITION
|
#undef IMPORTDISPOSITION
|
||||||
#define IMPORTDISPOSITION(a) /*empty*/
|
#define IMPORTDISPOSITION(a) /*empty*/
|
||||||
|
|
||||||
|
// EDITPOINT
|
||||||
|
#undef EDITPOINT
|
||||||
|
#define EDITPOINT(a) a,
|
||||||
|
enum EditPoint {
|
||||||
|
#include "editing_syms.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef EDITPOINT
|
||||||
|
#define EDITPOINT(a) /*empty*/
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// These don't need their state saved. yet...
|
// These don't need their state saved. yet...
|
||||||
enum CutCopyOp {
|
enum CutCopyOp {
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ ZOOMFOCUS(ZoomFocusLeft)
|
||||||
ZOOMFOCUS(ZoomFocusRight)
|
ZOOMFOCUS(ZoomFocusRight)
|
||||||
ZOOMFOCUS(ZoomFocusCenter)
|
ZOOMFOCUS(ZoomFocusCenter)
|
||||||
ZOOMFOCUS(ZoomFocusPlayhead)
|
ZOOMFOCUS(ZoomFocusPlayhead)
|
||||||
|
ZOOMFOCUS(ZoomFocusMouse)
|
||||||
ZOOMFOCUS(ZoomFocusEdit)
|
ZOOMFOCUS(ZoomFocusEdit)
|
||||||
|
|
||||||
DISPLAYCONTROL(FollowPlayhead)
|
DISPLAYCONTROL(FollowPlayhead)
|
||||||
|
|
@ -95,3 +96,8 @@ IMPORTDISPOSITION(ImportDistinctFiles=0)
|
||||||
IMPORTDISPOSITION(ImportMergeFiles=1)
|
IMPORTDISPOSITION(ImportMergeFiles=1)
|
||||||
IMPORTDISPOSITION(ImportSerializeFiles=2)
|
IMPORTDISPOSITION(ImportSerializeFiles=2)
|
||||||
IMPORTDISPOSITION(ImportDistinctChannels=3)
|
IMPORTDISPOSITION(ImportDistinctChannels=3)
|
||||||
|
|
||||||
|
|
||||||
|
EDITPOINT(EditAtPlayhead)
|
||||||
|
EDITPOINT(EditAtSelectedMarker)
|
||||||
|
EDITPOINT(EditAtMouse)
|
||||||
|
|
|
||||||
|
|
@ -139,11 +139,19 @@ static const gchar *_snap_mode_strings[] = {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const gchar *_edit_point_strings[] = {
|
||||||
|
N_("Playhead"),
|
||||||
|
N_("Marker"),
|
||||||
|
N_("Mouse"),
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
static const gchar *_zoom_focus_strings[] = {
|
static const gchar *_zoom_focus_strings[] = {
|
||||||
N_("Left"),
|
N_("Left"),
|
||||||
N_("Right"),
|
N_("Right"),
|
||||||
N_("Center"),
|
N_("Center"),
|
||||||
N_("Playhead"),
|
N_("Playhead"),
|
||||||
|
N_("Mouse"),
|
||||||
N_("Edit Cursor"),
|
N_("Edit Cursor"),
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
@ -170,20 +178,6 @@ show_me_the_size (Requisition* r, const char* what)
|
||||||
cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
|
cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
check_adjustment (Gtk::Adjustment* adj)
|
|
||||||
{
|
|
||||||
cerr << "CHANGE adj = "
|
|
||||||
<< adj->get_lower () << ' '
|
|
||||||
<< adj->get_upper () << ' '
|
|
||||||
<< adj->get_value () << ' '
|
|
||||||
<< adj->get_step_increment () << ' '
|
|
||||||
<< adj->get_page_increment () << ' '
|
|
||||||
<< adj->get_page_size () << ' '
|
|
||||||
<< endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Editor::Editor ()
|
Editor::Editor ()
|
||||||
:
|
:
|
||||||
/* time display buttons */
|
/* time display buttons */
|
||||||
|
|
@ -256,14 +250,20 @@ Editor::Editor ()
|
||||||
current_mixer_strip = 0;
|
current_mixer_strip = 0;
|
||||||
current_bbt_points = 0;
|
current_bbt_points = 0;
|
||||||
|
|
||||||
snap_type_strings = I18N (_snap_type_strings);
|
snap_type_strings = I18N (_snap_type_strings);
|
||||||
snap_mode_strings = I18N (_snap_mode_strings);
|
snap_mode_strings = I18N (_snap_mode_strings);
|
||||||
zoom_focus_strings = I18N(_zoom_focus_strings);
|
zoom_focus_strings = I18N (_zoom_focus_strings);
|
||||||
|
edit_point_strings = I18N (_edit_point_strings);
|
||||||
|
|
||||||
snap_type = SnapToFrame;
|
snap_type = SnapToFrame;
|
||||||
set_snap_to (snap_type);
|
set_snap_to (snap_type);
|
||||||
|
|
||||||
snap_mode = SnapNormal;
|
snap_mode = SnapNormal;
|
||||||
set_snap_mode (snap_mode);
|
set_snap_mode (snap_mode);
|
||||||
|
|
||||||
|
_edit_point = EditAtMouse;
|
||||||
|
set_edit_point (_edit_point);
|
||||||
|
|
||||||
snap_threshold = 5.0;
|
snap_threshold = 5.0;
|
||||||
bbt_beat_subdivision = 4;
|
bbt_beat_subdivision = 4;
|
||||||
canvas_width = 0;
|
canvas_width = 0;
|
||||||
|
|
@ -329,13 +329,7 @@ Editor::Editor ()
|
||||||
_dragging_playhead = false;
|
_dragging_playhead = false;
|
||||||
_dragging_hscrollbar = false;
|
_dragging_hscrollbar = false;
|
||||||
|
|
||||||
_scrubbing = false;
|
scrubbing_direction = 0;
|
||||||
mouse_direction = 1;
|
|
||||||
mouse_speed_update = -1;
|
|
||||||
mouse_speed_size = 16;
|
|
||||||
mouse_speed = new double[mouse_speed_size];
|
|
||||||
memset (mouse_speed, 0, sizeof(double) * mouse_speed_size);
|
|
||||||
mouse_speed_entries = 0;
|
|
||||||
|
|
||||||
sfbrowser = 0;
|
sfbrowser = 0;
|
||||||
ignore_route_order_sync = false;
|
ignore_route_order_sync = false;
|
||||||
|
|
@ -2005,6 +1999,18 @@ Editor::set_snap_mode (SnapMode mode)
|
||||||
|
|
||||||
instant_save ();
|
instant_save ();
|
||||||
}
|
}
|
||||||
|
void
|
||||||
|
Editor::set_edit_point (EditPoint ep)
|
||||||
|
{
|
||||||
|
_edit_point = ep;
|
||||||
|
string str = edit_point_strings[(int)ep];
|
||||||
|
|
||||||
|
if (str != edit_point_selector.get_active_text ()) {
|
||||||
|
edit_point_selector.set_active_text (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
instant_save ();
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Editor::set_state (const XMLNode& node)
|
Editor::set_state (const XMLNode& node)
|
||||||
|
|
@ -2082,6 +2088,10 @@ Editor::set_state (const XMLNode& node)
|
||||||
set_snap_mode ((SnapMode) atoi (prop->value()));
|
set_snap_mode ((SnapMode) atoi (prop->value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property ("edit-point"))) {
|
||||||
|
set_edit_point ((EditPoint) string_2_enum (prop->value(), _edit_point));
|
||||||
|
}
|
||||||
|
|
||||||
if ((prop = node.property ("mouse-mode"))) {
|
if ((prop = node.property ("mouse-mode"))) {
|
||||||
MouseMode m = str2mousemode(prop->value());
|
MouseMode m = str2mousemode(prop->value());
|
||||||
mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
|
mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
|
||||||
|
|
@ -2233,6 +2243,8 @@ Editor::get_state ()
|
||||||
snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
|
snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
|
||||||
node->add_property ("snap-mode", buf);
|
node->add_property ("snap-mode", buf);
|
||||||
|
|
||||||
|
node->add_property ("edit-point", enum_2_string (_edit_point));
|
||||||
|
|
||||||
snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
|
snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
|
||||||
node->add_property ("playhead", buf);
|
node->add_property ("playhead", buf);
|
||||||
snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
|
snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
|
||||||
|
|
@ -2400,7 +2412,7 @@ Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SnapToEditCursor:
|
case SnapToEditCursor:
|
||||||
start = edit_cursor->current_frame;
|
start = get_preferred_edit_position ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SnapToMark:
|
case SnapToMark:
|
||||||
|
|
@ -2681,17 +2693,24 @@ Editor::setup_toolbar ()
|
||||||
Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
|
Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
|
||||||
set_popdown_strings (snap_type_selector, snap_type_strings);
|
set_popdown_strings (snap_type_selector, snap_type_strings);
|
||||||
snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
|
snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
|
||||||
ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
|
ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
|
||||||
|
|
||||||
snap_mode_selector.set_name ("SnapModeSelector");
|
snap_mode_selector.set_name ("SnapModeSelector");
|
||||||
Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
|
Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
|
||||||
set_popdown_strings (snap_mode_selector, snap_mode_strings);
|
set_popdown_strings (snap_mode_selector, snap_mode_strings);
|
||||||
snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
|
snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
|
||||||
|
ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
|
||||||
|
|
||||||
|
edit_point_selector.set_name ("SnapModeSelector");
|
||||||
|
Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
|
||||||
|
set_popdown_strings (edit_point_selector, edit_point_strings);
|
||||||
|
edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
|
||||||
|
ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
|
||||||
|
|
||||||
snap_box.pack_start (edit_cursor_clock, false, false);
|
snap_box.pack_start (edit_cursor_clock, false, false);
|
||||||
snap_box.pack_start (snap_mode_selector, false, false);
|
snap_box.pack_start (snap_mode_selector, false, false);
|
||||||
snap_box.pack_start (snap_type_selector, false, false);
|
snap_box.pack_start (snap_type_selector, false, false);
|
||||||
|
snap_box.pack_start (edit_point_selector, false, false);
|
||||||
|
|
||||||
/* Nudge */
|
/* Nudge */
|
||||||
|
|
||||||
|
|
@ -2845,8 +2864,6 @@ Editor::convert_drop_to_paths (vector<ustring>& paths,
|
||||||
|
|
||||||
vector<ustring> uris = data.get_uris();
|
vector<ustring> uris = data.get_uris();
|
||||||
|
|
||||||
cerr << "there were " << uris.size() << " in that drag data\n";
|
|
||||||
|
|
||||||
if (uris.empty()) {
|
if (uris.empty()) {
|
||||||
|
|
||||||
/* This is seriously fucked up. Nautilus doesn't say that its URI lists
|
/* This is seriously fucked up. Nautilus doesn't say that its URI lists
|
||||||
|
|
@ -3228,6 +3245,27 @@ Editor::snap_mode_selection_done ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Editor::edit_point_selection_done ()
|
||||||
|
{
|
||||||
|
string choice = edit_point_selector.get_active_text();
|
||||||
|
EditPoint ep = EditAtSelectedMarker;
|
||||||
|
|
||||||
|
if (choice == _("Marker")) {
|
||||||
|
_edit_point = EditAtSelectedMarker;
|
||||||
|
} else if (choice == _("Playhead")) {
|
||||||
|
_edit_point = EditAtPlayhead;
|
||||||
|
} else {
|
||||||
|
_edit_point = EditAtMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<RadioAction> ract = edit_point_action (ep);
|
||||||
|
|
||||||
|
if (ract) {
|
||||||
|
ract->set_active (true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::zoom_focus_selection_done ()
|
Editor::zoom_focus_selection_done ()
|
||||||
{
|
{
|
||||||
|
|
@ -3244,6 +3282,8 @@ Editor::zoom_focus_selection_done ()
|
||||||
focus_type = ZoomFocusPlayhead;
|
focus_type = ZoomFocusPlayhead;
|
||||||
} else if (choice == _("Edit")) {
|
} else if (choice == _("Edit")) {
|
||||||
focus_type = ZoomFocusEdit;
|
focus_type = ZoomFocusEdit;
|
||||||
|
} else {
|
||||||
|
focus_type = ZoomFocusMouse;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
|
RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
|
||||||
|
|
@ -4025,6 +4065,35 @@ Editor::edit_cursor_position(bool sync)
|
||||||
return edit_cursor->current_frame;
|
return edit_cursor->current_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nframes64_t
|
||||||
|
Editor::get_preferred_edit_position() const
|
||||||
|
{
|
||||||
|
bool ignored;
|
||||||
|
nframes64_t where;
|
||||||
|
|
||||||
|
switch (_edit_point) {
|
||||||
|
case EditAtPlayhead:
|
||||||
|
return playhead_cursor->current_frame;
|
||||||
|
|
||||||
|
case EditAtSelectedMarker:
|
||||||
|
if (!selection->markers.empty()) {
|
||||||
|
bool whocares;
|
||||||
|
Location* loc = find_location_from_marker (selection->markers.front(), whocares);
|
||||||
|
if (loc) {
|
||||||
|
return loc->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* fallthru */
|
||||||
|
|
||||||
|
default:
|
||||||
|
case EditAtMouse:
|
||||||
|
if (mouse_frame (where, ignored)) {
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
|
Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
#include <pbd/stateful.h>
|
#include <pbd/stateful.h>
|
||||||
#include <ardour/session.h>
|
#include <ardour/session.h>
|
||||||
|
#include <ardour/stretch.h>
|
||||||
#include <ardour/tempo.h>
|
#include <ardour/tempo.h>
|
||||||
#include <ardour/location.h>
|
#include <ardour/location.h>
|
||||||
#include <ardour/audioregion.h>
|
#include <ardour/audioregion.h>
|
||||||
|
|
@ -183,15 +184,15 @@ class Editor : public PublicEditor
|
||||||
|
|
||||||
/* undo related */
|
/* undo related */
|
||||||
|
|
||||||
nframes_t unit_to_frame (double unit) {
|
nframes_t unit_to_frame (double unit) const {
|
||||||
return (nframes_t) rint (unit * frames_per_unit);
|
return (nframes_t) rint (unit * frames_per_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
double frame_to_unit (nframes_t frame) {
|
double frame_to_unit (nframes_t frame) const {
|
||||||
return rint ((double) frame / (double) frames_per_unit);
|
return rint ((double) frame / (double) frames_per_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
double frame_to_unit (double frame) {
|
double frame_to_unit (double frame) const {
|
||||||
return rint (frame / frames_per_unit);
|
return rint (frame / frames_per_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,7 +203,7 @@ class Editor : public PublicEditor
|
||||||
xscroll_adjustment.
|
xscroll_adjustment.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
nframes_t pixel_to_frame (double pixel) {
|
nframes64_t pixel_to_frame (double pixel) const {
|
||||||
|
|
||||||
/* pixel can be less than zero when motion events
|
/* pixel can be less than zero when motion events
|
||||||
are processed. since we've already run the world->canvas
|
are processed. since we've already run the world->canvas
|
||||||
|
|
@ -217,7 +218,7 @@ class Editor : public PublicEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gulong frame_to_pixel (nframes_t frame) {
|
gulong frame_to_pixel (nframes64_t frame) const {
|
||||||
return (gulong) rint ((frame / (frames_per_unit * GNOME_CANVAS(track_canvas.gobj())->pixels_per_unit)));
|
return (gulong) rint ((frame / (frames_per_unit * GNOME_CANVAS(track_canvas.gobj())->pixels_per_unit)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -354,6 +355,8 @@ class Editor : public PublicEditor
|
||||||
void reposition_and_zoom (nframes_t, double);
|
void reposition_and_zoom (nframes_t, double);
|
||||||
|
|
||||||
nframes_t edit_cursor_position(bool);
|
nframes_t edit_cursor_position(bool);
|
||||||
|
nframes64_t get_preferred_edit_position () const;
|
||||||
|
|
||||||
bool update_mouse_speed ();
|
bool update_mouse_speed ();
|
||||||
bool decelerate_mouse_speed ();
|
bool decelerate_mouse_speed ();
|
||||||
|
|
||||||
|
|
@ -424,8 +427,8 @@ class Editor : public PublicEditor
|
||||||
void set_color_rgba (uint32_t);
|
void set_color_rgba (uint32_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
LocationMarkers *find_location_markers (ARDOUR::Location *);
|
LocationMarkers *find_location_markers (ARDOUR::Location *) const;
|
||||||
ARDOUR::Location* find_location_from_marker (Marker *, bool& is_start);
|
ARDOUR::Location* find_location_from_marker (Marker *, bool& is_start) const;
|
||||||
|
|
||||||
typedef std::map<ARDOUR::Location*,LocationMarkers *> LocationMarkerMap;
|
typedef std::map<ARDOUR::Location*,LocationMarkers *> LocationMarkerMap;
|
||||||
LocationMarkerMap location_markers;
|
LocationMarkerMap location_markers;
|
||||||
|
|
@ -1136,16 +1139,8 @@ class Editor : public PublicEditor
|
||||||
void stop_scrolling ();
|
void stop_scrolling ();
|
||||||
|
|
||||||
bool _scrubbing;
|
bool _scrubbing;
|
||||||
bool have_full_mouse_speed;
|
double last_scrub_x;
|
||||||
nframes64_t last_scrub_frame;
|
int scrubbing_direction;
|
||||||
double last_scrub_time;
|
|
||||||
int mouse_speed_update;
|
|
||||||
double mouse_direction;
|
|
||||||
double compute_mouse_speed ();
|
|
||||||
void add_mouse_speed (double, double);
|
|
||||||
double* mouse_speed;
|
|
||||||
size_t mouse_speed_entries;
|
|
||||||
size_t mouse_speed_size;
|
|
||||||
|
|
||||||
void keyboard_selection_begin ();
|
void keyboard_selection_begin ();
|
||||||
void keyboard_selection_finish (bool add);
|
void keyboard_selection_finish (bool add);
|
||||||
|
|
@ -1834,14 +1829,18 @@ class Editor : public PublicEditor
|
||||||
|
|
||||||
void duplicate_dialog (bool for_region);
|
void duplicate_dialog (bool for_region);
|
||||||
|
|
||||||
nframes_t event_frame (GdkEvent*, double* px = 0, double* py = 0);
|
nframes64_t event_frame (GdkEvent*, double* px = 0, double* py = 0) const;
|
||||||
|
|
||||||
|
/* returns false if mouse pointer is not in track or marker canvas
|
||||||
|
*/
|
||||||
|
bool mouse_frame (nframes64_t&, bool& in_track_canvas) const;
|
||||||
|
|
||||||
void time_fx_motion (ArdourCanvas::Item*, GdkEvent*);
|
void time_fx_motion (ArdourCanvas::Item*, GdkEvent*);
|
||||||
void start_time_fx (ArdourCanvas::Item*, GdkEvent*);
|
void start_time_fx (ArdourCanvas::Item*, GdkEvent*);
|
||||||
void end_time_fx (ArdourCanvas::Item*, GdkEvent*);
|
void end_time_fx (ArdourCanvas::Item*, GdkEvent*);
|
||||||
|
|
||||||
struct TimeStretchDialog : public ArdourDialog {
|
struct TimeStretchDialog : public ArdourDialog {
|
||||||
ARDOUR::Session::TimeStretchRequest request;
|
ARDOUR::TimeStretchRequest request;
|
||||||
Editor& editor;
|
Editor& editor;
|
||||||
RegionSelection regions;
|
RegionSelection regions;
|
||||||
Gtk::ProgressBar progress_bar;
|
Gtk::ProgressBar progress_bar;
|
||||||
|
|
@ -2001,6 +2000,16 @@ class Editor : public PublicEditor
|
||||||
void history_changed ();
|
void history_changed ();
|
||||||
|
|
||||||
Gtk::HBox status_bar_hpacker;
|
Gtk::HBox status_bar_hpacker;
|
||||||
|
|
||||||
|
Editing::EditPoint _edit_point;
|
||||||
|
|
||||||
|
Gtk::ComboBoxText edit_point_selector;
|
||||||
|
|
||||||
|
void set_edit_point (Editing::EditPoint ep);
|
||||||
|
void edit_point_selection_done ();
|
||||||
|
void edit_point_chosen (Editing::EditPoint);
|
||||||
|
Glib::RefPtr<Gtk::RadioAction> edit_point_action (Editing::EditPoint);
|
||||||
|
std::vector<std::string> edit_point_strings;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_editor_h__ */
|
#endif /* __ardour_editor_h__ */
|
||||||
|
|
|
||||||
|
|
@ -291,6 +291,8 @@ Editor::register_actions ()
|
||||||
ActionManager::session_sensitive_actions.push_back (act);
|
ActionManager::session_sensitive_actions.push_back (act);
|
||||||
ActionManager::register_radio_action (zoom_actions, zoom_group, "zoom-focus-playhead", _("Zoom Focus Playhead"), bind (mem_fun(*this, &Editor::zoom_focus_chosen), Editing::ZoomFocusPlayhead));
|
ActionManager::register_radio_action (zoom_actions, zoom_group, "zoom-focus-playhead", _("Zoom Focus Playhead"), bind (mem_fun(*this, &Editor::zoom_focus_chosen), Editing::ZoomFocusPlayhead));
|
||||||
ActionManager::session_sensitive_actions.push_back (act);
|
ActionManager::session_sensitive_actions.push_back (act);
|
||||||
|
ActionManager::register_radio_action (zoom_actions, zoom_group, "zoom-focus-mouse", _("Zoom Focus Mouse"), bind (mem_fun(*this, &Editor::zoom_focus_chosen), Editing::ZoomFocusMouse));
|
||||||
|
ActionManager::session_sensitive_actions.push_back (act);
|
||||||
ActionManager::register_radio_action (zoom_actions, zoom_group, "zoom-focus-edit", _("Zoom Focus Edit"), bind (mem_fun(*this, &Editor::zoom_focus_chosen), Editing::ZoomFocusEdit));
|
ActionManager::register_radio_action (zoom_actions, zoom_group, "zoom-focus-edit", _("Zoom Focus Edit"), bind (mem_fun(*this, &Editor::zoom_focus_chosen), Editing::ZoomFocusEdit));
|
||||||
ActionManager::session_sensitive_actions.push_back (act);
|
ActionManager::session_sensitive_actions.push_back (act);
|
||||||
|
|
||||||
|
|
@ -304,6 +306,11 @@ Editor::register_actions ()
|
||||||
ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-timefx", _("Timefx Tool"), bind (mem_fun(*this, &Editor::set_mouse_mode), Editing::MouseTimeFX, false));
|
ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-timefx", _("Timefx Tool"), bind (mem_fun(*this, &Editor::set_mouse_mode), Editing::MouseTimeFX, false));
|
||||||
ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-note", _("Note Tool"), bind (mem_fun(*this, &Editor::set_mouse_mode), Editing::MouseNote, false));
|
ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-note", _("Note Tool"), bind (mem_fun(*this, &Editor::set_mouse_mode), Editing::MouseNote, false));
|
||||||
|
|
||||||
|
RadioAction::Group edit_point_group;
|
||||||
|
ActionManager::register_radio_action (editor_actions, edit_point_group, X_("edit-at-playhead"), _("Playhead"), (bind (mem_fun(*this, &Editor::edit_point_chosen), Editing::EditAtPlayhead)));
|
||||||
|
ActionManager::register_radio_action (editor_actions, edit_point_group, X_("edit-at-mouse"), _("Mouse"), (bind (mem_fun(*this, &Editor::edit_point_chosen), Editing::EditAtPlayhead)));
|
||||||
|
ActionManager::register_radio_action (editor_actions, edit_point_group, X_("edit-at-selected-marker"), _("Marker"), (bind (mem_fun(*this, &Editor::edit_point_chosen), Editing::EditAtPlayhead)));
|
||||||
|
|
||||||
ActionManager::register_action (editor_actions, X_("SnapTo"), _("Snap To"));
|
ActionManager::register_action (editor_actions, X_("SnapTo"), _("Snap To"));
|
||||||
ActionManager::register_action (editor_actions, X_("SnapMode"), _("Snap Mode"));
|
ActionManager::register_action (editor_actions, X_("SnapMode"), _("Snap Mode"));
|
||||||
|
|
||||||
|
|
@ -829,6 +836,54 @@ Editor::snap_mode_chosen (SnapMode mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<RadioAction>
|
||||||
|
Editor::edit_point_action (EditPoint ep)
|
||||||
|
{
|
||||||
|
const char* action = 0;
|
||||||
|
RefPtr<Action> act;
|
||||||
|
|
||||||
|
switch (ep) {
|
||||||
|
case Editing::EditAtPlayhead:
|
||||||
|
action = X_("edit-at-playhead");
|
||||||
|
break;
|
||||||
|
case Editing::EditAtSelectedMarker:
|
||||||
|
action = X_("edit-at-selected-marker");
|
||||||
|
break;
|
||||||
|
case Editing::EditAtMouse:
|
||||||
|
action = X_("edit-at-mouse");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fatal << string_compose (_("programming error: %1: %2"), "Editor: impossible edit point type", (int) ep) << endmsg;
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
|
||||||
|
act = ActionManager::get_action (X_("Editor"), action);
|
||||||
|
|
||||||
|
if (act) {
|
||||||
|
RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
|
||||||
|
return ract;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
error << string_compose (_("programming error: %1: %2"), "Editor::edit_point_action could not find action to match edit point.", action) << endmsg;
|
||||||
|
return RefPtr<RadioAction> ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Editor::edit_point_chosen (EditPoint ep)
|
||||||
|
{
|
||||||
|
/* this is driven by a toggle on a radio group, and so is invoked twice,
|
||||||
|
once for the item that became inactive and once for the one that became
|
||||||
|
active.
|
||||||
|
*/
|
||||||
|
|
||||||
|
RefPtr<RadioAction> ract = edit_point_action (ep);
|
||||||
|
|
||||||
|
if (ract && ract->get_active()) {
|
||||||
|
set_edit_point (ep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RefPtr<RadioAction>
|
RefPtr<RadioAction>
|
||||||
Editor::zoom_focus_action (ZoomFocus focus)
|
Editor::zoom_focus_action (ZoomFocus focus)
|
||||||
|
|
@ -849,6 +904,9 @@ Editor::zoom_focus_action (ZoomFocus focus)
|
||||||
case ZoomFocusPlayhead:
|
case ZoomFocusPlayhead:
|
||||||
action = X_("zoom-focus-playhead");
|
action = X_("zoom-focus-playhead");
|
||||||
break;
|
break;
|
||||||
|
case ZoomFocusMouse:
|
||||||
|
action = X_("zoom-focus-mouse");
|
||||||
|
break;
|
||||||
case ZoomFocusEdit:
|
case ZoomFocusEdit:
|
||||||
action = X_("zoom-focus-edit");
|
action = X_("zoom-focus-edit");
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ Editor::external_audio_dialog ()
|
||||||
|
|
||||||
switch (pos) {
|
switch (pos) {
|
||||||
case ImportAtEditCursor:
|
case ImportAtEditCursor:
|
||||||
where = edit_cursor->current_frame;
|
where = get_preferred_edit_position ();
|
||||||
break;
|
break;
|
||||||
case ImportAtTimestamp:
|
case ImportAtTimestamp:
|
||||||
where = -1;
|
where = -1;
|
||||||
|
|
@ -157,6 +157,10 @@ Editor::external_audio_dialog ()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (where < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SrcQuality quality = sfbrowser->get_src_quality();
|
SrcQuality quality = sfbrowser->get_src_quality();
|
||||||
|
|
||||||
if (sfbrowser->copy_files_btn.get_active()) {
|
if (sfbrowser->copy_files_btn.get_active()) {
|
||||||
|
|
@ -591,7 +595,7 @@ Editor::add_sources (vector<Glib::ustring> paths, SourceList& sources, nframes64
|
||||||
pos = sources[0]->natural_position();
|
pos = sources[0]->natural_position();
|
||||||
} else {
|
} else {
|
||||||
// XXX is this the best alternative ?
|
// XXX is this the best alternative ?
|
||||||
pos = edit_cursor->current_frame;
|
pos = get_preferred_edit_position ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,6 @@ Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -188,9 +188,9 @@ Editor::LocationMarkers::~LocationMarkers ()
|
||||||
}
|
}
|
||||||
|
|
||||||
Editor::LocationMarkers *
|
Editor::LocationMarkers *
|
||||||
Editor::find_location_markers (Location *location)
|
Editor::find_location_markers (Location *location) const
|
||||||
{
|
{
|
||||||
LocationMarkerMap::iterator i;
|
LocationMarkerMap::const_iterator i;
|
||||||
|
|
||||||
for (i = location_markers.begin(); i != location_markers.end(); ++i) {
|
for (i = location_markers.begin(); i != location_markers.end(); ++i) {
|
||||||
if ((*i).first == location) {
|
if ((*i).first == location) {
|
||||||
|
|
@ -202,9 +202,9 @@ Editor::find_location_markers (Location *location)
|
||||||
}
|
}
|
||||||
|
|
||||||
Location *
|
Location *
|
||||||
Editor::find_location_from_marker (Marker *marker, bool& is_start)
|
Editor::find_location_from_marker (Marker *marker, bool& is_start) const
|
||||||
{
|
{
|
||||||
LocationMarkerMap::iterator i;
|
LocationMarkerMap::const_iterator i;
|
||||||
|
|
||||||
for (i = location_markers.begin(); i != location_markers.end(); ++i) {
|
for (i = location_markers.begin(); i != location_markers.end(); ++i) {
|
||||||
LocationMarkers *lm = (*i).second;
|
LocationMarkers *lm = (*i).second;
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,46 @@ using namespace Editing;
|
||||||
|
|
||||||
const static double ZERO_GAIN_FRACTION = gain_to_slider_position(dB_to_coefficient(0.0));
|
const static double ZERO_GAIN_FRACTION = gain_to_slider_position(dB_to_coefficient(0.0));
|
||||||
|
|
||||||
nframes_t
|
bool
|
||||||
Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
|
Editor::mouse_frame (nframes64_t& where, bool& in_track_canvas) const
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
double wx, wy;
|
||||||
|
Gdk::ModifierType mask;
|
||||||
|
Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->track_canvas.get_window();
|
||||||
|
Glib::RefPtr<const Gdk::Window> pointer_window;
|
||||||
|
|
||||||
|
pointer_window = canvas_window->get_pointer (x, y, mask);
|
||||||
|
|
||||||
|
if (pointer_window == track_canvas.get_bin_window()) {
|
||||||
|
|
||||||
|
track_canvas.window_to_world (x, y, wx, wy);
|
||||||
|
in_track_canvas = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
in_track_canvas = false;
|
||||||
|
|
||||||
|
if (pointer_window == time_canvas.get_bin_window()) {
|
||||||
|
time_canvas.window_to_world (x, y, wx, wy);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wx += horizontal_adjustment.get_value();
|
||||||
|
wy += vertical_adjustment.get_value();
|
||||||
|
|
||||||
|
GdkEvent event;
|
||||||
|
event.type = GDK_BUTTON_RELEASE;
|
||||||
|
event.button.x = wx;
|
||||||
|
event.button.y = wy;
|
||||||
|
|
||||||
|
where = event_frame (&event, 0, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nframes64_t
|
||||||
|
Editor::event_frame (GdkEvent* event, double* pcx, double* pcy) const
|
||||||
{
|
{
|
||||||
double cx, cy;
|
double cx, cy;
|
||||||
|
|
||||||
|
|
@ -773,10 +811,8 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
|
||||||
|
|
||||||
case MouseAudition:
|
case MouseAudition:
|
||||||
_scrubbing = true;
|
_scrubbing = true;
|
||||||
last_scrub_frame = 0;
|
last_scrub_x = event->button.x;
|
||||||
last_scrub_time = 0;
|
scrubbing_direction = 0;
|
||||||
have_full_mouse_speed = false;
|
|
||||||
memset (mouse_speed, 0, sizeof (double) * mouse_speed_size);
|
|
||||||
/* rest handled in motion & release */
|
/* rest handled in motion & release */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1110,7 +1146,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
||||||
|
|
||||||
case MouseAudition:
|
case MouseAudition:
|
||||||
_scrubbing = false;
|
_scrubbing = false;
|
||||||
if (last_scrub_frame == 0) {
|
if (scrubbing_direction == 0) {
|
||||||
/* no drag, just a click */
|
/* no drag, just a click */
|
||||||
switch (item_type) {
|
switch (item_type) {
|
||||||
case RegionItem:
|
case RegionItem:
|
||||||
|
|
@ -1467,12 +1503,6 @@ Editor::left_automation_track ()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
_update_mouse_speed (void *arg)
|
|
||||||
{
|
|
||||||
return static_cast<Editor*>(arg)->update_mouse_speed ();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
|
Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
|
||||||
{
|
{
|
||||||
|
|
@ -1509,56 +1539,53 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
|
||||||
switch (mouse_mode) {
|
switch (mouse_mode) {
|
||||||
case MouseAudition:
|
case MouseAudition:
|
||||||
if (_scrubbing) {
|
if (_scrubbing) {
|
||||||
struct timeval tmnow;
|
|
||||||
|
|
||||||
if (last_scrub_frame == 0) {
|
double delta;
|
||||||
|
|
||||||
/* first motion, just set up the variables */
|
if (scrubbing_direction == 0) {
|
||||||
|
/* first move */
|
||||||
last_scrub_frame = (nframes64_t) drag_info.current_pointer_frame;
|
session->request_locate (drag_info.current_pointer_frame, false);
|
||||||
gettimeofday (&tmnow, 0);
|
session->request_transport_speed (0.1);
|
||||||
last_scrub_time = tmnow.tv_sec * 1000000.0 + tmnow.tv_usec;
|
scrubbing_direction = 1;
|
||||||
session->request_locate (last_scrub_frame, true);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* how fast is the mouse moving ? */
|
|
||||||
|
|
||||||
double speed;
|
|
||||||
nframes_t distance;
|
if (last_scrub_x > drag_info.current_pointer_x) {
|
||||||
double time;
|
/* move to the left */
|
||||||
double dir;
|
|
||||||
|
if (scrubbing_direction > 0) {
|
||||||
#if 1
|
/* we reversed direction to go backwards */
|
||||||
if (last_scrub_frame < (nframes64_t) drag_info.current_pointer_frame) {
|
|
||||||
distance = (nframes64_t) drag_info.current_pointer_frame - last_scrub_frame;
|
session->request_transport_speed (-0.1);
|
||||||
dir = 1.0;
|
|
||||||
|
} else {
|
||||||
|
/* still moving to the left (backwards) */
|
||||||
|
|
||||||
|
delta = 0.005 * (last_scrub_x - drag_info.current_pointer_x);
|
||||||
|
session->request_transport_speed (session->transport_speed() - delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrubbing_direction = -1;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
distance = last_scrub_frame - (nframes64_t) drag_info.current_pointer_frame;
|
/* move to the right */
|
||||||
dir = -1.0;
|
if (scrubbing_direction < 0) {
|
||||||
}
|
/* we reversed direction to go forward */
|
||||||
#else
|
|
||||||
if (drag_info.grab_x < drag_info.current_pointer_x) {
|
session->request_transport_speed (0.1);
|
||||||
distance = drag_info.current_pointer_x - drag_info.grab_x;
|
} else {
|
||||||
dir = -1.0;
|
/* still moving to the right */
|
||||||
} else {
|
|
||||||
distance = drag_info.grab_x - drag_info.current_pointer_x;
|
delta = 0.005 * (drag_info.current_pointer_x - last_scrub_x);
|
||||||
dir = 1.0;
|
session->request_transport_speed (session->transport_speed() + delta);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
scrubbing_direction = 1;
|
||||||
gettimeofday (&tmnow, 0);
|
|
||||||
time = (tmnow.tv_sec * 1000000.0 + tmnow.tv_usec) - last_scrub_time;
|
|
||||||
last_scrub_frame = drag_info.current_pointer_frame;
|
|
||||||
last_scrub_time = (tmnow.tv_sec * 1000000.0) + tmnow.tv_usec;
|
|
||||||
speed = ((double)distance/session->frame_rate()) / (time/1000000.0); // frames/sec
|
|
||||||
|
|
||||||
add_mouse_speed (speed, dir);
|
|
||||||
|
|
||||||
if (mouse_speed_update < 0) {
|
|
||||||
mouse_speed_update = g_timeout_add (10, _update_mouse_speed, this);
|
|
||||||
update_mouse_speed ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_scrub_x = drag_info.current_pointer_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -2607,8 +2634,7 @@ Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
|
||||||
drag_info.grab_x = control_point->get_x();
|
drag_info.grab_x = control_point->get_x();
|
||||||
drag_info.grab_y = control_point->get_y();
|
drag_info.grab_y = control_point->get_y();
|
||||||
control_point->line().parent_group().i2w(drag_info.grab_x, drag_info.grab_y);
|
control_point->line().parent_group().i2w(drag_info.grab_x, drag_info.grab_y);
|
||||||
track_canvas.w2c(drag_info.grab_x, drag_info.grab_y,
|
track_canvas.w2c(drag_info.grab_x, drag_info.grab_y, drag_info.grab_x, drag_info.grab_y);
|
||||||
drag_info.grab_x, drag_info.grab_y);
|
|
||||||
|
|
||||||
drag_info.grab_frame = pixel_to_frame(drag_info.grab_x);
|
drag_info.grab_frame = pixel_to_frame(drag_info.grab_x);
|
||||||
|
|
||||||
|
|
@ -3757,12 +3783,13 @@ Editor::create_region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent
|
||||||
snap_to (start, -1);
|
snap_to (start, -1);
|
||||||
const Meter& m = session->tempo_map().meter_at(start);
|
const Meter& m = session->tempo_map().meter_at(start);
|
||||||
const Tempo& t = session->tempo_map().tempo_at(start);
|
const Tempo& t = session->tempo_map().tempo_at(start);
|
||||||
double length = m.frames_per_bar(t, session->frame_rate());
|
double length = floor (m.frames_per_bar(t, session->frame_rate()));
|
||||||
|
|
||||||
boost::shared_ptr<Source> src = session->create_midi_source_for_session(*diskstream.get());
|
boost::shared_ptr<Source> src = session->create_midi_source_for_session(*diskstream.get());
|
||||||
|
|
||||||
mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>(RegionFactory::create(
|
mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion>
|
||||||
src, 0, length, PBD::basename_nosuffix(src->name()))), start);
|
(RegionFactory::create(src, 0, (nframes_t) length,
|
||||||
|
PBD::basename_nosuffix(src->name()))), start);
|
||||||
XMLNode &after = mtv->playlist()->get_state();
|
XMLNode &after = mtv->playlist()->get_state();
|
||||||
session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
|
session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after));
|
||||||
commit_reversible_command();
|
commit_reversible_command();
|
||||||
|
|
@ -3788,17 +3815,22 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
|
||||||
speed = rtv->get_diskstream()->speed();
|
speed = rtv->get_diskstream()->speed();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
|
nframes64_t where = get_preferred_edit_position();
|
||||||
|
|
||||||
align_region (rv.region(), SyncPoint, (nframes_t) (edit_cursor->current_frame * speed));
|
if (where >= 0) {
|
||||||
|
|
||||||
} else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
|
if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
|
||||||
|
|
||||||
align_region (rv.region(), End, (nframes_t) (edit_cursor->current_frame * speed));
|
align_region (rv.region(), SyncPoint, (nframes_t) (where * speed));
|
||||||
|
|
||||||
} else {
|
} else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
|
||||||
|
|
||||||
align_region (rv.region(), Start, (nframes_t) (edit_cursor->current_frame * speed));
|
align_region (rv.region(), End, (nframes_t) (where * speed));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
align_region (rv.region(), Start, (nframes_t) (where * speed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5197,90 +5229,3 @@ Editor::track_height_step_timeout ()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
Editor::add_mouse_speed (double speed, double dir)
|
|
||||||
{
|
|
||||||
size_t index;
|
|
||||||
|
|
||||||
mouse_direction = dir;
|
|
||||||
|
|
||||||
index = mouse_speed_entries;
|
|
||||||
|
|
||||||
if (++index >= mouse_speed_size) {
|
|
||||||
index = 0;
|
|
||||||
have_full_mouse_speed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mouse_speed[index] = speed;
|
|
||||||
mouse_speed_entries = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
Editor::compute_mouse_speed ()
|
|
||||||
{
|
|
||||||
double total = 0;
|
|
||||||
|
|
||||||
if (!have_full_mouse_speed) {
|
|
||||||
|
|
||||||
/* partial speed buffer, just use whatever we have so far */
|
|
||||||
|
|
||||||
if (mouse_speed_entries == 0 ) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t n = 0; n < mouse_speed_entries; ++n) {
|
|
||||||
total += mouse_speed[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
return mouse_direction * total/mouse_speed_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* compute the average (effectively low-pass filtering) mouse speed
|
|
||||||
across the entire buffer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (size_t n = 0; n < mouse_speed_size; ++n) {
|
|
||||||
total += mouse_speed[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return mouse_direction * total/mouse_speed_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Editor::update_mouse_speed ()
|
|
||||||
{
|
|
||||||
double speed;
|
|
||||||
|
|
||||||
if (!_scrubbing) {
|
|
||||||
session->request_transport_speed (0.0);
|
|
||||||
mouse_speed_update = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
speed = compute_mouse_speed ();
|
|
||||||
|
|
||||||
struct timeval tmnow;
|
|
||||||
|
|
||||||
gettimeofday (&tmnow, 0);
|
|
||||||
double now = (tmnow.tv_sec * 1000000.0) + tmnow.tv_usec;
|
|
||||||
|
|
||||||
if (now - last_scrub_time > 250000) {
|
|
||||||
|
|
||||||
// 0.25 seconds since last mouse motion, start to brake
|
|
||||||
|
|
||||||
if (fabs (speed) < 0.1) {
|
|
||||||
/* don't asymptotically approach zero */
|
|
||||||
memset (mouse_speed, 0, sizeof (double) * mouse_speed_size);
|
|
||||||
speed = 0.0;
|
|
||||||
} else if (fabs (speed) < 0.25) {
|
|
||||||
add_mouse_speed (fabs (speed * 0.2), mouse_direction);
|
|
||||||
} else {
|
|
||||||
add_mouse_speed (fabs (speed * 0.6), mouse_direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
session->request_transport_speed (speed);
|
|
||||||
return _scrubbing;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -95,17 +95,10 @@ Editor::redo (uint32_t n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
Editor::ensure_cursor (nframes_t *pos)
|
|
||||||
{
|
|
||||||
*pos = edit_cursor->current_frame;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::split_region ()
|
Editor::split_region ()
|
||||||
{
|
{
|
||||||
split_region_at (edit_cursor->current_frame);
|
split_region_at (get_preferred_edit_position());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -137,8 +130,21 @@ Editor::split_regions_at (nframes_t where, RegionSelection& regions)
|
||||||
snap_to (where);
|
snap_to (where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
|
||||||
|
|
||||||
for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ++a) {
|
RegionSelection::iterator tmp;
|
||||||
|
|
||||||
|
/* XXX this test needs to be more complicated, to make sure we really
|
||||||
|
have something to split.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!(*a)->region()->covers (where)) {
|
||||||
|
++a;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = a;
|
||||||
|
++tmp;
|
||||||
|
|
||||||
boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
|
boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
|
||||||
|
|
||||||
|
|
@ -161,6 +167,7 @@ Editor::split_regions_at (nframes_t where, RegionSelection& regions)
|
||||||
session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
|
session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a = tmp;
|
||||||
}
|
}
|
||||||
while (used_playlists.size() > 0) {
|
while (used_playlists.size() > 0) {
|
||||||
|
|
||||||
|
|
@ -883,7 +890,7 @@ Editor::cursor_align (bool playhead_to_edit)
|
||||||
{
|
{
|
||||||
if (playhead_to_edit) {
|
if (playhead_to_edit) {
|
||||||
if (session) {
|
if (session) {
|
||||||
session->request_locate (edit_cursor->current_frame);
|
session->request_locate (get_preferred_edit_position());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
edit_cursor->set_position (playhead_cursor->current_frame);
|
edit_cursor->set_position (playhead_cursor->current_frame);
|
||||||
|
|
@ -893,8 +900,8 @@ Editor::cursor_align (bool playhead_to_edit)
|
||||||
void
|
void
|
||||||
Editor::edit_cursor_backward ()
|
Editor::edit_cursor_backward ()
|
||||||
{
|
{
|
||||||
nframes_t pos;
|
nframes64_t pos;
|
||||||
nframes_t cnt;
|
nframes64_t cnt;
|
||||||
float prefix;
|
float prefix;
|
||||||
bool was_floating;
|
bool was_floating;
|
||||||
|
|
||||||
|
|
@ -908,9 +915,11 @@ Editor::edit_cursor_backward ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = edit_cursor->current_frame;
|
if ((pos = get_preferred_edit_position()) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((nframes_t) pos < cnt) {
|
if (pos < cnt) {
|
||||||
pos = 0;
|
pos = 0;
|
||||||
} else {
|
} else {
|
||||||
pos -= cnt;
|
pos -= cnt;
|
||||||
|
|
@ -1099,12 +1108,14 @@ Editor::temporal_zoom (gdouble fpu)
|
||||||
{
|
{
|
||||||
if (!session) return;
|
if (!session) return;
|
||||||
|
|
||||||
nframes_t current_page = current_page_frames();
|
nframes64_t current_page = current_page_frames();
|
||||||
nframes_t current_leftmost = leftmost_frame;
|
nframes64_t current_leftmost = leftmost_frame;
|
||||||
nframes_t current_rightmost;
|
nframes64_t current_rightmost;
|
||||||
nframes_t current_center;
|
nframes64_t current_center;
|
||||||
nframes_t new_page;
|
nframes64_t new_page;
|
||||||
nframes_t leftmost_after_zoom = 0;
|
nframes64_t leftmost_after_zoom = 0;
|
||||||
|
nframes64_t where;
|
||||||
|
bool in_track_canvas;
|
||||||
double nfpu;
|
double nfpu;
|
||||||
|
|
||||||
nfpu = fpu;
|
nfpu = fpu;
|
||||||
|
|
@ -1143,10 +1154,38 @@ Editor::temporal_zoom (gdouble fpu)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ZoomFocusMouse:
|
||||||
|
/* try to keep the mouse over the same point in the display */
|
||||||
|
|
||||||
|
if (!mouse_frame (where, in_track_canvas)) {
|
||||||
|
/* use playhead instead */
|
||||||
|
where = playhead_cursor->current_frame;
|
||||||
|
|
||||||
|
if (where > new_page/2) {
|
||||||
|
leftmost_after_zoom = where - (new_page/2);
|
||||||
|
} else {
|
||||||
|
leftmost_after_zoom = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
double l = - ((new_page * ((where - current_leftmost)/(double)current_page)) - where);
|
||||||
|
|
||||||
|
if (l < 0) {
|
||||||
|
leftmost_after_zoom = 0;
|
||||||
|
} else if (l > max_frames) {
|
||||||
|
leftmost_after_zoom = max_frames - new_page;
|
||||||
|
} else {
|
||||||
|
leftmost_after_zoom = (nframes64_t) l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case ZoomFocusEdit:
|
case ZoomFocusEdit:
|
||||||
/* try to keep the edit cursor in the center */
|
/* try to keep the edit cursor in the center */
|
||||||
if (edit_cursor->current_frame > new_page/2) {
|
if (get_preferred_edit_position() > new_page/2) {
|
||||||
leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
|
leftmost_after_zoom = get_preferred_edit_position() - (new_page/2);
|
||||||
} else {
|
} else {
|
||||||
leftmost_after_zoom = 0;
|
leftmost_after_zoom = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1160,6 +1199,8 @@ Editor::temporal_zoom (gdouble fpu)
|
||||||
// session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
|
// session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
|
||||||
// session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
|
// session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
|
||||||
// commit_reversible_command ();
|
// commit_reversible_command ();
|
||||||
|
|
||||||
|
// cerr << "repos & zoom to " << leftmost_after_zoom << " @ " << nfpu << endl;
|
||||||
|
|
||||||
reposition_and_zoom (leftmost_after_zoom, nfpu);
|
reposition_and_zoom (leftmost_after_zoom, nfpu);
|
||||||
}
|
}
|
||||||
|
|
@ -1579,7 +1620,7 @@ Editor::insert_region_list_selection (float times)
|
||||||
|
|
||||||
begin_reversible_command (_("insert region"));
|
begin_reversible_command (_("insert region"));
|
||||||
XMLNode &before = playlist->get_state();
|
XMLNode &before = playlist->get_state();
|
||||||
playlist->add_region ((RegionFactory::create (region)), edit_cursor->current_frame, times);
|
playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
|
||||||
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
|
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
|
||||||
commit_reversible_command ();
|
commit_reversible_command ();
|
||||||
}
|
}
|
||||||
|
|
@ -1666,7 +1707,7 @@ Editor::play_from_start ()
|
||||||
void
|
void
|
||||||
Editor::play_from_edit_cursor ()
|
Editor::play_from_edit_cursor ()
|
||||||
{
|
{
|
||||||
session->request_locate (edit_cursor->current_frame, true);
|
session->request_locate (get_preferred_edit_position(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2275,7 +2316,8 @@ Editor::set_region_sync_from_edit_cursor ()
|
||||||
{
|
{
|
||||||
/* Check that at the edit cursor is in at least one of the selected regions */
|
/* Check that at the edit cursor is in at least one of the selected regions */
|
||||||
RegionSelection::const_iterator i = selection->regions.begin();
|
RegionSelection::const_iterator i = selection->regions.begin();
|
||||||
while (i != selection->regions.end() && !(*i)->region()->covers (edit_cursor->current_frame)) {
|
|
||||||
|
while (i != selection->regions.end() && !(*i)->region()->covers (get_preferred_edit_position())) {
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2290,11 +2332,11 @@ Editor::set_region_sync_from_edit_cursor ()
|
||||||
for (RegionSelection::iterator j = selection->regions.begin(); j != selection->regions.end(); ++j) {
|
for (RegionSelection::iterator j = selection->regions.begin(); j != selection->regions.end(); ++j) {
|
||||||
boost::shared_ptr<Region> r = (*j)->region();
|
boost::shared_ptr<Region> r = (*j)->region();
|
||||||
XMLNode &before = r->playlist()->get_state();
|
XMLNode &before = r->playlist()->get_state();
|
||||||
r->set_sync_position (edit_cursor->current_frame);
|
r->set_sync_position (get_preferred_edit_position());
|
||||||
XMLNode &after = r->playlist()->get_state();
|
XMLNode &after = r->playlist()->get_state();
|
||||||
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
|
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
|
||||||
}
|
}
|
||||||
|
|
||||||
commit_reversible_command ();
|
commit_reversible_command ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2334,13 +2376,13 @@ Editor::naturalize ()
|
||||||
void
|
void
|
||||||
Editor::align (RegionPoint what)
|
Editor::align (RegionPoint what)
|
||||||
{
|
{
|
||||||
align_selection (what, edit_cursor->current_frame);
|
align_selection (what, get_preferred_edit_position());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::align_relative (RegionPoint what)
|
Editor::align_relative (RegionPoint what)
|
||||||
{
|
{
|
||||||
align_selection_relative (what, edit_cursor->current_frame);
|
align_selection_relative (what, get_preferred_edit_position());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegionSortByTime {
|
struct RegionSortByTime {
|
||||||
|
|
@ -2481,7 +2523,7 @@ Editor::trim_region_to_edit_cursor ()
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode &before = region->playlist()->get_state();
|
XMLNode &before = region->playlist()->get_state();
|
||||||
region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
|
region->trim_end( session_frame_to_track_frame(get_preferred_edit_position(), speed), this);
|
||||||
XMLNode &after = region->playlist()->get_state();
|
XMLNode &after = region->playlist()->get_state();
|
||||||
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
|
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
|
||||||
}
|
}
|
||||||
|
|
@ -2513,12 +2555,10 @@ Editor::trim_region_from_edit_cursor ()
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode &before = region->playlist()->get_state();
|
XMLNode &before = region->playlist()->get_state();
|
||||||
region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
|
region->trim_front ( session_frame_to_track_frame(get_preferred_edit_position(), speed), this);
|
||||||
XMLNode &after = region->playlist()->get_state();
|
XMLNode &after = region->playlist()->get_state();
|
||||||
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
|
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
|
||||||
}
|
}
|
||||||
|
|
||||||
commit_reversible_command ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Unfreeze selected routes */
|
/** Unfreeze selected routes */
|
||||||
|
|
@ -2945,26 +2985,19 @@ Editor::cut_copy_ranges (CutCopyOp op)
|
||||||
void
|
void
|
||||||
Editor::paste (float times)
|
Editor::paste (float times)
|
||||||
{
|
{
|
||||||
paste_internal (edit_cursor->current_frame, times);
|
paste_internal (get_preferred_edit_position(), times);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::mouse_paste ()
|
Editor::mouse_paste ()
|
||||||
{
|
{
|
||||||
int x, y;
|
nframes64_t where;
|
||||||
double wx, wy;
|
bool ignored;
|
||||||
|
|
||||||
track_canvas.get_pointer (x, y);
|
if (!mouse_frame (where, ignored)) {
|
||||||
track_canvas.window_to_world (x, y, wx, wy);
|
return;
|
||||||
wx += horizontal_adjustment.get_value();
|
}
|
||||||
wy += vertical_adjustment.get_value();
|
|
||||||
|
|
||||||
GdkEvent event;
|
|
||||||
event.type = GDK_BUTTON_RELEASE;
|
|
||||||
event.button.x = wx;
|
|
||||||
event.button.y = wy;
|
|
||||||
|
|
||||||
nframes_t where = event_frame (&event, 0, 0);
|
|
||||||
snap_to (where);
|
snap_to (where);
|
||||||
paste_internal (where, 1);
|
paste_internal (where, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -2979,7 +3012,7 @@ Editor::paste_internal (nframes_t position, float times)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position == max_frames) {
|
if (position == max_frames) {
|
||||||
position = edit_cursor->current_frame;
|
position = get_preferred_edit_position();
|
||||||
}
|
}
|
||||||
|
|
||||||
begin_reversible_command (_("paste"));
|
begin_reversible_command (_("paste"));
|
||||||
|
|
@ -3050,7 +3083,7 @@ Editor::paste_named_selection (float times)
|
||||||
++tmp;
|
++tmp;
|
||||||
|
|
||||||
XMLNode &before = apl->get_state();
|
XMLNode &before = apl->get_state();
|
||||||
apl->paste (*chunk, edit_cursor->current_frame, times);
|
apl->paste (*chunk, get_preferred_edit_position(), times);
|
||||||
session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
|
session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
|
||||||
|
|
||||||
if (tmp != ns->playlists.end()) {
|
if (tmp != ns->playlists.end()) {
|
||||||
|
|
@ -3162,7 +3195,7 @@ Editor::center_edit_cursor ()
|
||||||
{
|
{
|
||||||
float page = canvas_width * frames_per_unit;
|
float page = canvas_width * frames_per_unit;
|
||||||
|
|
||||||
center_screen_internal (edit_cursor->current_frame, page);
|
center_screen_internal (get_preferred_edit_position(), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -3185,7 +3218,7 @@ Editor::nudge_selected_tracks (bool use_edit_cursor, bool forwards)
|
||||||
nframes_t start;
|
nframes_t start;
|
||||||
|
|
||||||
if (use_edit_cursor) {
|
if (use_edit_cursor) {
|
||||||
start = edit_cursor->current_frame;
|
start = get_preferred_edit_position();
|
||||||
} else {
|
} else {
|
||||||
start = 0;
|
start = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -616,16 +616,10 @@ Editor::track_selection_changed ()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
||||||
(*i)->set_selected (false);
|
if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
|
||||||
if (mouse_mode == MouseRange) {
|
(*i)->set_selected (true);
|
||||||
(*i)->hide_selection ();
|
} else {
|
||||||
}
|
(*i)->set_selected (false);
|
||||||
}
|
|
||||||
|
|
||||||
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
||||||
(*i)->set_selected (true);
|
|
||||||
if (mouse_mode == MouseRange) {
|
|
||||||
(*i)->show_selection (selection->time);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -652,6 +646,7 @@ Editor::time_selection_changed ()
|
||||||
} else {
|
} else {
|
||||||
ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
|
ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#include <ardour/audio_track.h>
|
#include <ardour/audio_track.h>
|
||||||
#include <ardour/audioregion.h>
|
#include <ardour/audioregion.h>
|
||||||
#include <ardour/audio_diskstream.h>
|
#include <ardour/audio_diskstream.h>
|
||||||
|
#include <ardour/stretch.h>
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
@ -87,29 +88,29 @@ gint
|
||||||
Editor::TimeStretchDialog::update_progress ()
|
Editor::TimeStretchDialog::update_progress ()
|
||||||
{
|
{
|
||||||
progress_bar.set_fraction (request.progress);
|
progress_bar.set_fraction (request.progress);
|
||||||
return request.running;
|
return !request.done;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::TimeStretchDialog::cancel_timestretch_in_progress ()
|
Editor::TimeStretchDialog::cancel_timestretch_in_progress ()
|
||||||
{
|
{
|
||||||
status = -2;
|
status = -2;
|
||||||
request.running = false;
|
request.cancel = true;
|
||||||
|
first_cancel.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
gint
|
gint
|
||||||
Editor::TimeStretchDialog::delete_timestretch_in_progress (GdkEventAny* ev)
|
Editor::TimeStretchDialog::delete_timestretch_in_progress (GdkEventAny* ev)
|
||||||
{
|
{
|
||||||
status = -2;
|
status = -2;
|
||||||
request.running = false;
|
request.cancel = true;
|
||||||
|
first_delete.disconnect();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Editor::run_timestretch (RegionSelection& regions, float fraction)
|
Editor::run_timestretch (RegionSelection& regions, float fraction)
|
||||||
{
|
{
|
||||||
pthread_t thread;
|
|
||||||
|
|
||||||
if (current_timestretch == 0) {
|
if (current_timestretch == 0) {
|
||||||
current_timestretch = new TimeStretchDialog (*this);
|
current_timestretch = new TimeStretchDialog (*this);
|
||||||
}
|
}
|
||||||
|
|
@ -130,27 +131,30 @@ Editor::run_timestretch (RegionSelection& regions, float fraction)
|
||||||
current_timestretch->request.quick_seek = current_timestretch->quick_button.get_active();
|
current_timestretch->request.quick_seek = current_timestretch->quick_button.get_active();
|
||||||
current_timestretch->request.antialias = !current_timestretch->antialias_button.get_active();
|
current_timestretch->request.antialias = !current_timestretch->antialias_button.get_active();
|
||||||
current_timestretch->request.progress = 0.0f;
|
current_timestretch->request.progress = 0.0f;
|
||||||
current_timestretch->request.running = true;
|
current_timestretch->request.done = false;
|
||||||
|
current_timestretch->request.cancel = false;
|
||||||
|
|
||||||
/* re-connect the cancel button and delete events */
|
/* re-connect the cancel button and delete events */
|
||||||
|
|
||||||
current_timestretch->first_cancel.disconnect();
|
current_timestretch->first_cancel.disconnect();
|
||||||
current_timestretch->first_delete.disconnect();
|
current_timestretch->first_delete.disconnect();
|
||||||
|
|
||||||
current_timestretch->cancel_button->signal_clicked().connect (mem_fun (current_timestretch, &TimeStretchDialog::cancel_timestretch_in_progress));
|
current_timestretch->first_cancel = current_timestretch->cancel_button->signal_clicked().connect
|
||||||
current_timestretch->signal_delete_event().connect (mem_fun (current_timestretch, &TimeStretchDialog::delete_timestretch_in_progress));
|
(mem_fun (current_timestretch, &TimeStretchDialog::cancel_timestretch_in_progress));
|
||||||
|
current_timestretch->first_delete = current_timestretch->signal_delete_event().connect
|
||||||
|
(mem_fun (current_timestretch, &TimeStretchDialog::delete_timestretch_in_progress));
|
||||||
|
|
||||||
if (pthread_create_and_store ("timestretch", &thread, 0, timestretch_thread, current_timestretch)) {
|
if (pthread_create_and_store ("timestretch", ¤t_timestretch->request.thread, 0, timestretch_thread, current_timestretch)) {
|
||||||
current_timestretch->hide ();
|
current_timestretch->hide ();
|
||||||
error << _("timestretch cannot be started - thread creation error") << endmsg;
|
error << _("timestretch cannot be started - thread creation error") << endmsg;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_detach (thread);
|
pthread_detach (current_timestretch->request.thread);
|
||||||
|
|
||||||
sigc::connection c = Glib::signal_timeout().connect (mem_fun (current_timestretch, &TimeStretchDialog::update_progress), 100);
|
sigc::connection c = Glib::signal_timeout().connect (mem_fun (current_timestretch, &TimeStretchDialog::update_progress), 100);
|
||||||
|
|
||||||
while (current_timestretch->request.running) {
|
while (!current_timestretch->request.done) {
|
||||||
gtk_main_iteration ();
|
gtk_main_iteration ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,31 +199,34 @@ Editor::do_timestretch (TimeStretchDialog& dialog)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.request.region = region;
|
if (dialog.request.cancel) {
|
||||||
|
|
||||||
if (!dialog.request.running) {
|
|
||||||
/* we were cancelled */
|
/* we were cancelled */
|
||||||
dialog.status = 1;
|
dialog.status = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((new_region = session->tempoize_region (dialog.request)) == 0) {
|
Stretch stretch (*session, dialog.request);
|
||||||
|
|
||||||
|
if (stretch.run (region)) {
|
||||||
dialog.status = -1;
|
dialog.status = -1;
|
||||||
dialog.request.running = false;
|
dialog.request.done = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode &before = playlist->get_state();
|
if (!stretch.results.empty()) {
|
||||||
playlist->replace_region (region, new_region, region->position());
|
new_region = stretch.results.front();
|
||||||
XMLNode &after = playlist->get_state();
|
|
||||||
session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
|
XMLNode &before = playlist->get_state();
|
||||||
|
playlist->replace_region (region, new_region, region->position());
|
||||||
|
XMLNode &after = playlist->get_state();
|
||||||
|
session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
|
||||||
|
}
|
||||||
|
|
||||||
i = tmp;
|
i = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.status = 0;
|
dialog.status = 0;
|
||||||
dialog.request.running = false;
|
dialog.request.done = true;
|
||||||
dialog.request.region.reset ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ setup_gtk_ardour_enums ()
|
||||||
AudioClock::Mode clock_mode;
|
AudioClock::Mode clock_mode;
|
||||||
Width width;
|
Width width;
|
||||||
ImportMode import_mode;
|
ImportMode import_mode;
|
||||||
|
EditPoint edit_point;
|
||||||
|
|
||||||
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
|
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||||
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
|
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||||
|
|
@ -60,4 +61,9 @@ setup_gtk_ardour_enums ()
|
||||||
REGISTER_ENUM (ImportAsRegion);
|
REGISTER_ENUM (ImportAsRegion);
|
||||||
REGISTER_ENUM (ImportAsTapeTrack);
|
REGISTER_ENUM (ImportAsTapeTrack);
|
||||||
REGISTER (import_mode);
|
REGISTER (import_mode);
|
||||||
|
|
||||||
|
REGISTER_ENUM (EditAtPlayhead);
|
||||||
|
REGISTER_ENUM (EditAtMouse);
|
||||||
|
REGISTER_ENUM (EditAtSelectedMarker);
|
||||||
|
REGISTER (edit_point);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
gtk2_ardour/marker_selection.h
Normal file
31
gtk2_ardour/marker_selection.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2000-2007 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ardour_gtk_marker_selection_h__
|
||||||
|
#define __ardour_gtk_marker_selection_h__
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "marker.h"
|
||||||
|
|
||||||
|
struct MarkerSelection : public std::list<Marker*>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __ardour_gtk_marker_selection_h__ */
|
||||||
|
|
@ -185,11 +185,11 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
|
||||||
|
|
||||||
virtual void toggle_playback (bool with_abort) = 0;
|
virtual void toggle_playback (bool with_abort) = 0;
|
||||||
virtual void transition_to_rolling (bool fwd) = 0;
|
virtual void transition_to_rolling (bool fwd) = 0;
|
||||||
virtual nframes_t unit_to_frame (double unit) = 0;
|
virtual nframes_t unit_to_frame (double unit) const = 0;
|
||||||
virtual double frame_to_unit (nframes_t frame) = 0;
|
virtual double frame_to_unit (nframes_t frame) const = 0;
|
||||||
virtual double frame_to_unit (double frame) = 0;
|
virtual double frame_to_unit (double frame) const = 0;
|
||||||
virtual nframes_t pixel_to_frame (double pixel) = 0;
|
virtual nframes64_t pixel_to_frame (double pixel) const = 0;
|
||||||
virtual gulong frame_to_pixel (nframes_t frame) = 0;
|
virtual gulong frame_to_pixel (nframes64_t frame) const = 0;
|
||||||
virtual Selection& get_selection () const = 0;
|
virtual Selection& get_selection () const = 0;
|
||||||
virtual Selection& get_cut_buffer () const = 0;
|
virtual Selection& get_cut_buffer () const = 0;
|
||||||
virtual bool extend_selection_to_track (TimeAxisView&) = 0;
|
virtual bool extend_selection_to_track (TimeAxisView&) = 0;
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,15 @@ Selection::clear_lines ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Selection::clear_markers ()
|
||||||
|
{
|
||||||
|
if (!markers.empty()) {
|
||||||
|
markers.clear ();
|
||||||
|
MarkersChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Selection::toggle (boost::shared_ptr<Playlist> pl)
|
Selection::toggle (boost::shared_ptr<Playlist> pl)
|
||||||
{
|
{
|
||||||
|
|
@ -575,7 +584,8 @@ Selection::empty ()
|
||||||
playlists.empty () &&
|
playlists.empty () &&
|
||||||
lines.empty () &&
|
lines.empty () &&
|
||||||
time.empty () &&
|
time.empty () &&
|
||||||
playlists.empty ()
|
playlists.empty () &&
|
||||||
|
markers.empty()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -700,3 +710,43 @@ Selection::select_edit_group_regions ()
|
||||||
add (*i);
|
add (*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Selection::set (Marker* m)
|
||||||
|
{
|
||||||
|
clear_markers ();
|
||||||
|
add (m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Selection::toggle (Marker* m)
|
||||||
|
{
|
||||||
|
MarkerSelection::iterator i;
|
||||||
|
|
||||||
|
if ((i = find (markers.begin(), markers.end(), m)) == markers.end()) {
|
||||||
|
add (m);
|
||||||
|
} else {
|
||||||
|
remove (m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Selection::remove (Marker* m)
|
||||||
|
{
|
||||||
|
MarkerSelection::iterator i;
|
||||||
|
|
||||||
|
if ((i = find (markers.begin(), markers.end(), m)) != markers.end()) {
|
||||||
|
markers.erase (i);
|
||||||
|
MarkersChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Selection::add (Marker* m)
|
||||||
|
{
|
||||||
|
if (find (markers.begin(), markers.end(), m) == markers.end()) {
|
||||||
|
markers.push_back (m);
|
||||||
|
MarkersChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include "playlist_selection.h"
|
#include "playlist_selection.h"
|
||||||
#include "processor_selection.h"
|
#include "processor_selection.h"
|
||||||
#include "point_selection.h"
|
#include "point_selection.h"
|
||||||
|
#include "marker_selection.h"
|
||||||
|
|
||||||
class TimeAxisView;
|
class TimeAxisView;
|
||||||
class RegionView;
|
class RegionView;
|
||||||
|
|
@ -71,6 +72,7 @@ class Selection : public sigc::trackable
|
||||||
AutomationSelection lines;
|
AutomationSelection lines;
|
||||||
PlaylistSelection playlists;
|
PlaylistSelection playlists;
|
||||||
PointSelection points;
|
PointSelection points;
|
||||||
|
MarkerSelection markers;
|
||||||
|
|
||||||
Selection (PublicEditor const * e) : editor (e), next_time_id (0) {
|
Selection (PublicEditor const * e) : editor (e), next_time_id (0) {
|
||||||
clear();
|
clear();
|
||||||
|
|
@ -84,6 +86,7 @@ class Selection : public sigc::trackable
|
||||||
sigc::signal<void> LinesChanged;
|
sigc::signal<void> LinesChanged;
|
||||||
sigc::signal<void> PlaylistsChanged;
|
sigc::signal<void> PlaylistsChanged;
|
||||||
sigc::signal<void> PointsChanged;
|
sigc::signal<void> PointsChanged;
|
||||||
|
sigc::signal<void> MarkersChanged;
|
||||||
|
|
||||||
void clear ();
|
void clear ();
|
||||||
bool empty();
|
bool empty();
|
||||||
|
|
@ -106,6 +109,7 @@ class Selection : public sigc::trackable
|
||||||
void set (boost::shared_ptr<ARDOUR::Playlist>);
|
void set (boost::shared_ptr<ARDOUR::Playlist>);
|
||||||
void set (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
|
void set (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
|
||||||
void set (AutomationSelectable*);
|
void set (AutomationSelectable*);
|
||||||
|
void set (Marker*);
|
||||||
|
|
||||||
void toggle (TimeAxisView*);
|
void toggle (TimeAxisView*);
|
||||||
void toggle (const std::list<TimeAxisView*>&);
|
void toggle (const std::list<TimeAxisView*>&);
|
||||||
|
|
@ -116,6 +120,7 @@ class Selection : public sigc::trackable
|
||||||
void toggle (boost::shared_ptr<ARDOUR::Playlist>);
|
void toggle (boost::shared_ptr<ARDOUR::Playlist>);
|
||||||
void toggle (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
|
void toggle (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
|
||||||
void toggle (const std::vector<AutomationSelectable*>&);
|
void toggle (const std::vector<AutomationSelectable*>&);
|
||||||
|
void toggle (Marker*);
|
||||||
|
|
||||||
void add (TimeAxisView*);
|
void add (TimeAxisView*);
|
||||||
void add (const std::list<TimeAxisView*>&);
|
void add (const std::list<TimeAxisView*>&);
|
||||||
|
|
@ -125,7 +130,8 @@ class Selection : public sigc::trackable
|
||||||
void add (ARDOUR::AutomationList*);
|
void add (ARDOUR::AutomationList*);
|
||||||
void add (boost::shared_ptr<ARDOUR::Playlist>);
|
void add (boost::shared_ptr<ARDOUR::Playlist>);
|
||||||
void add (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
|
void add (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
|
||||||
|
void add (Marker*);
|
||||||
|
|
||||||
void remove (TimeAxisView*);
|
void remove (TimeAxisView*);
|
||||||
void remove (const std::list<TimeAxisView*>&);
|
void remove (const std::list<TimeAxisView*>&);
|
||||||
void remove (RegionView*);
|
void remove (RegionView*);
|
||||||
|
|
@ -135,6 +141,7 @@ class Selection : public sigc::trackable
|
||||||
void remove (boost::shared_ptr<ARDOUR::Playlist>);
|
void remove (boost::shared_ptr<ARDOUR::Playlist>);
|
||||||
void remove (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
|
void remove (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
|
||||||
void remove (const list<Selectable*>&);
|
void remove (const list<Selectable*>&);
|
||||||
|
void remove (Marker*);
|
||||||
|
|
||||||
void replace (uint32_t time_index, nframes_t start, nframes_t end);
|
void replace (uint32_t time_index, nframes_t start, nframes_t end);
|
||||||
|
|
||||||
|
|
@ -144,6 +151,7 @@ class Selection : public sigc::trackable
|
||||||
void clear_lines ();
|
void clear_lines ();
|
||||||
void clear_playlists ();
|
void clear_playlists ();
|
||||||
void clear_points ();
|
void clear_points ();
|
||||||
|
void clear_markers ();
|
||||||
|
|
||||||
void foreach_region (void (ARDOUR::Region::*method)(void));
|
void foreach_region (void (ARDOUR::Region::*method)(void));
|
||||||
void foreach_regionview (void (RegionView::*method)(void));
|
void foreach_regionview (void (RegionView::*method)(void));
|
||||||
|
|
|
||||||
|
|
@ -545,12 +545,16 @@ TimeAxisView::popup_size_menu (guint32 when)
|
||||||
void
|
void
|
||||||
TimeAxisView::set_selected (bool yn)
|
TimeAxisView::set_selected (bool yn)
|
||||||
{
|
{
|
||||||
AxisView::set_selected (yn);
|
if (yn == _selected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Selectable::set_selected (yn);
|
||||||
|
|
||||||
if (_selected) {
|
if (_selected) {
|
||||||
controls_ebox.set_name (controls_base_selected_name);
|
controls_ebox.set_name (controls_base_selected_name);
|
||||||
controls_frame.set_name (controls_base_selected_name);
|
controls_frame.set_name (controls_base_selected_name);
|
||||||
|
|
||||||
/* propagate any existing selection, if the mode is right */
|
/* propagate any existing selection, if the mode is right */
|
||||||
|
|
||||||
if (editor.current_mouse_mode() == Editing::MouseRange && !editor.get_selection().time.empty()) {
|
if (editor.current_mouse_mode() == Editing::MouseRange && !editor.get_selection().time.empty()) {
|
||||||
|
|
@ -571,8 +575,6 @@ TimeAxisView::set_selected (bool yn)
|
||||||
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
||||||
(*i)->set_selected (false);
|
(*i)->set_selected (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <libart_lgpl/art_misc.h>
|
#include <libart_lgpl/art_misc.h>
|
||||||
|
#include <gtkmm/rc.h>
|
||||||
#include <gtkmm/window.h>
|
#include <gtkmm/window.h>
|
||||||
#include <gtkmm/combo.h>
|
#include <gtkmm/combo.h>
|
||||||
#include <gtkmm/label.h>
|
#include <gtkmm/label.h>
|
||||||
|
|
@ -325,6 +326,61 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Gdk::Color
|
||||||
|
color_from_style (string widget_style_name, int state, string attr)
|
||||||
|
{
|
||||||
|
GtkStyle* style;
|
||||||
|
|
||||||
|
style = gtk_rc_get_style_by_paths (gtk_settings_get_default(),
|
||||||
|
widget_style_name.c_str(),
|
||||||
|
0, G_TYPE_NONE);
|
||||||
|
|
||||||
|
if (!style) {
|
||||||
|
error << string_compose (_("no style found for %1, using red"), style) << endmsg;
|
||||||
|
return Gdk::Color ("red");
|
||||||
|
}
|
||||||
|
|
||||||
|
cerr << "got style for " << widget_style_name << endl;
|
||||||
|
|
||||||
|
if (attr == "fg") {
|
||||||
|
return Gdk::Color (&style->fg[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr == "bg") {
|
||||||
|
cerr << "returning color from bg\n";
|
||||||
|
return Gdk::Color (&style->bg[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr == "light") {
|
||||||
|
return Gdk::Color (&style->light[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr == "dark") {
|
||||||
|
return Gdk::Color (&style->dark[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr == "mid") {
|
||||||
|
return Gdk::Color (&style->mid[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr == "text") {
|
||||||
|
return Gdk::Color (&style->text[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr == "base") {
|
||||||
|
return Gdk::Color (&style->base[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr == "text_aa") {
|
||||||
|
return Gdk::Color (&style->text_aa[state]);
|
||||||
|
}
|
||||||
|
|
||||||
|
error << string_compose (_("unknown style attribute %1 requested for color; using \"red\""), attr) << endmsg;
|
||||||
|
return Gdk::Color ("red");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
canvas_item_visible (ArdourCanvas::Item* item)
|
canvas_item_visible (ArdourCanvas::Item* item)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@ Pango::FontDescription* get_font_for_style (std::string widgetname);
|
||||||
|
|
||||||
uint32_t rgba_from_style (std::string, uint32_t, uint32_t, uint32_t, uint32_t, std::string = "fg", int = Gtk::STATE_NORMAL, bool = true);
|
uint32_t rgba_from_style (std::string, uint32_t, uint32_t, uint32_t, uint32_t, std::string = "fg", int = Gtk::STATE_NORMAL, bool = true);
|
||||||
|
|
||||||
|
Gdk::Color color_from_style (std::string widget_style_name, int state, std::string attr);
|
||||||
|
|
||||||
void decorate (Gtk::Window& w, Gdk::WMDecoration d);
|
void decorate (Gtk::Window& w, Gdk::WMDecoration d);
|
||||||
|
|
||||||
bool canvas_item_visible (ArdourCanvas::Item* item);
|
bool canvas_item_visible (ArdourCanvas::Item* item);
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,6 @@ session_process.cc
|
||||||
session_state.cc
|
session_state.cc
|
||||||
session_state_utils.cc
|
session_state_utils.cc
|
||||||
session_time.cc
|
session_time.cc
|
||||||
session_timefx.cc
|
|
||||||
session_transport.cc
|
session_transport.cc
|
||||||
session_utils.cc
|
session_utils.cc
|
||||||
silentfilesource.cc
|
silentfilesource.cc
|
||||||
|
|
@ -130,6 +129,7 @@ sndfile_helpers.cc
|
||||||
sndfilesource.cc
|
sndfilesource.cc
|
||||||
source.cc
|
source.cc
|
||||||
source_factory.cc
|
source_factory.cc
|
||||||
|
stretch.cc
|
||||||
tape_file_matcher.cc
|
tape_file_matcher.cc
|
||||||
template_utils.cc
|
template_utils.cc
|
||||||
tempo.cc
|
tempo.cc
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ class Filter {
|
||||||
protected:
|
protected:
|
||||||
Filter (ARDOUR::Session& s) : session(s) {}
|
Filter (ARDOUR::Session& s) : session(s) {}
|
||||||
|
|
||||||
int make_new_sources (boost::shared_ptr<ARDOUR::Region>, ARDOUR::SourceList&);
|
int make_new_sources (boost::shared_ptr<ARDOUR::Region>, ARDOUR::SourceList&, std::string suffix = "");
|
||||||
int finish (boost::shared_ptr<ARDOUR::Region>, ARDOUR::SourceList&);
|
int finish (boost::shared_ptr<ARDOUR::Region>, ARDOUR::SourceList&, std::string region_name = "");
|
||||||
|
|
||||||
ARDOUR::Session& session;
|
ARDOUR::Session& session;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,13 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
||||||
nframes_t start () const { return _start; }
|
nframes_t start () const { return _start; }
|
||||||
nframes_t length() const { return _length; }
|
nframes_t length() const { return _length; }
|
||||||
layer_t layer () const { return _layer; }
|
layer_t layer () const { return _layer; }
|
||||||
|
|
||||||
|
nframes64_t ancestral_start () const { return _ancestral_start; }
|
||||||
|
nframes64_t ancestral_length () const { return _ancestral_length; }
|
||||||
|
float stretch() const { return _stretch; }
|
||||||
|
|
||||||
|
void set_ancestral_data (nframes64_t start, nframes64_t length, float stretch);
|
||||||
|
|
||||||
nframes_t sync_offset(int& dir) const;
|
nframes_t sync_offset(int& dir) const;
|
||||||
nframes_t sync_position() const;
|
nframes_t sync_position() const;
|
||||||
|
|
||||||
|
|
@ -177,11 +183,12 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
||||||
boost::shared_ptr<Source> source (uint32_t n=0) const { return _sources[ (n < _sources.size()) ? n : 0 ]; }
|
boost::shared_ptr<Source> source (uint32_t n=0) const { return _sources[ (n < _sources.size()) ? n : 0 ]; }
|
||||||
uint32_t n_channels() const { return _sources.size(); }
|
uint32_t n_channels() const { return _sources.size(); }
|
||||||
|
|
||||||
std::vector<string> master_source_names();
|
|
||||||
|
|
||||||
const SourceList& sources() const { return _sources; }
|
const SourceList& sources() const { return _sources; }
|
||||||
const SourceList& master_sources() const { return _master_sources; }
|
const SourceList& master_sources() const { return _master_sources; }
|
||||||
|
|
||||||
|
std::vector<string> master_source_names();
|
||||||
|
void set_master_sources (SourceList&);
|
||||||
|
|
||||||
/* serialization */
|
/* serialization */
|
||||||
|
|
||||||
XMLNode& get_state ();
|
XMLNode& get_state ();
|
||||||
|
|
@ -241,6 +248,9 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
||||||
layer_t _layer;
|
layer_t _layer;
|
||||||
mutable RegionEditState _first_edit;
|
mutable RegionEditState _first_edit;
|
||||||
int _frozen;
|
int _frozen;
|
||||||
|
nframes64_t _ancestral_start;
|
||||||
|
nframes64_t _ancestral_length;
|
||||||
|
float _stretch;
|
||||||
mutable uint32_t _read_data_count; ///< modified in read()
|
mutable uint32_t _read_data_count; ///< modified in read()
|
||||||
Change _pending_changed;
|
Change _pending_changed;
|
||||||
uint64_t _last_layer_op; ///< timestamp
|
uint64_t _last_layer_op; ///< timestamp
|
||||||
|
|
|
||||||
|
|
@ -860,21 +860,6 @@ class Session : public PBD::StatefulDestructible
|
||||||
|
|
||||||
boost::shared_ptr<IO> click_io() { return _click_io; }
|
boost::shared_ptr<IO> click_io() { return _click_io; }
|
||||||
|
|
||||||
/* tempo FX */
|
|
||||||
|
|
||||||
struct TimeStretchRequest {
|
|
||||||
boost::shared_ptr<ARDOUR::AudioRegion> region;
|
|
||||||
float fraction; /* session: read ; GUI: write */
|
|
||||||
float progress; /* session: write ; GUI: read */
|
|
||||||
bool running; /* read/write */
|
|
||||||
bool quick_seek; /* GUI: write */
|
|
||||||
bool antialias; /* GUI: write */
|
|
||||||
|
|
||||||
TimeStretchRequest () {}
|
|
||||||
};
|
|
||||||
|
|
||||||
boost::shared_ptr<AudioRegion> tempoize_region (TimeStretchRequest&);
|
|
||||||
|
|
||||||
/* disk, buffer loads */
|
/* disk, buffer loads */
|
||||||
|
|
||||||
uint32_t playback_load ();
|
uint32_t playback_load ();
|
||||||
|
|
|
||||||
51
libs/ardour/ardour/stretch.h
Normal file
51
libs/ardour/ardour/stretch.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2007 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ardour_stretch_h__
|
||||||
|
#define __ardour_stretch_h__
|
||||||
|
|
||||||
|
#include <ardour/filter.h>
|
||||||
|
#include <soundtouch/SoundTouch.h>
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
class AudioRegion;
|
||||||
|
|
||||||
|
struct TimeStretchRequest : public InterThreadInfo {
|
||||||
|
float fraction;
|
||||||
|
bool quick_seek;
|
||||||
|
bool antialias;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Stretch : public Filter {
|
||||||
|
public:
|
||||||
|
Stretch (ARDOUR::Session&, TimeStretchRequest&);
|
||||||
|
~Stretch ();
|
||||||
|
|
||||||
|
int run (boost::shared_ptr<ARDOUR::Region>);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeStretchRequest& tsr;
|
||||||
|
soundtouch::SoundTouch st;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace */
|
||||||
|
|
||||||
|
#endif /* __ardour_stretch_h__ */
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include <pbd/xml++.h>
|
#include <pbd/xml++.h>
|
||||||
#include <pbd/stacktrace.h>
|
#include <pbd/stacktrace.h>
|
||||||
#include <pbd/enumwriter.h>
|
#include <pbd/enumwriter.h>
|
||||||
|
#include <pbd/convert.h>
|
||||||
|
|
||||||
#include <ardour/audioregion.h>
|
#include <ardour/audioregion.h>
|
||||||
#include <ardour/session.h>
|
#include <ardour/session.h>
|
||||||
|
|
@ -47,6 +48,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
|
using namespace PBD;
|
||||||
|
|
||||||
/* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
|
/* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
|
||||||
|
|
||||||
|
|
@ -127,6 +129,23 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
|
||||||
, _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
|
, _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
|
||||||
, _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
|
, _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
|
||||||
{
|
{
|
||||||
|
set<boost::shared_ptr<Source> > unique_srcs;
|
||||||
|
|
||||||
|
for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
|
||||||
|
_sources.push_back (*i);
|
||||||
|
|
||||||
|
pair<set<boost::shared_ptr<Source> >::iterator,bool> result;
|
||||||
|
|
||||||
|
result = unique_srcs.insert (*i);
|
||||||
|
|
||||||
|
if (result.second) {
|
||||||
|
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i);
|
||||||
|
if (afs) {
|
||||||
|
afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* return to default fades if the existing ones are too long */
|
/* return to default fades if the existing ones are too long */
|
||||||
init ();
|
init ();
|
||||||
|
|
||||||
|
|
@ -494,12 +513,20 @@ AudioRegion::state (bool full)
|
||||||
snprintf (buf, sizeof(buf), "%.12g", _scale_amplitude);
|
snprintf (buf, sizeof(buf), "%.12g", _scale_amplitude);
|
||||||
node.add_property ("scale-gain", buf);
|
node.add_property ("scale-gain", buf);
|
||||||
|
|
||||||
|
// XXX these should move into Region
|
||||||
|
|
||||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||||
snprintf (buf2, sizeof(buf2), "source-%d", n);
|
snprintf (buf2, sizeof(buf2), "source-%d", n);
|
||||||
_sources[n]->id().print (buf, sizeof (buf));
|
_sources[n]->id().print (buf, sizeof (buf));
|
||||||
node.add_property (buf2, buf);
|
node.add_property (buf2, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint32_t n=0; n < _master_sources.size(); ++n) {
|
||||||
|
snprintf (buf2, sizeof(buf2), "master-source-%d", n);
|
||||||
|
_master_sources[n]->id().print (buf, sizeof (buf));
|
||||||
|
node.add_property (buf2, buf);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
|
snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
|
||||||
node.add_property ("channels", buf);
|
node.add_property ("channels", buf);
|
||||||
|
|
||||||
|
|
@ -973,6 +1000,7 @@ AudioRegion::read_raw_internal (Sample* buf, nframes_t pos, nframes_t cnt) const
|
||||||
return audio_source()->read (buf, pos, cnt);
|
return audio_source()->read (buf, pos, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
|
AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,25 @@ using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
int
|
int
|
||||||
Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs)
|
Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs, string suffix)
|
||||||
{
|
{
|
||||||
vector<string> names = region->master_source_names();
|
vector<string> names = region->master_source_names();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < region->n_channels(); ++i) {
|
for (uint32_t i = 0; i < region->n_channels(); ++i) {
|
||||||
|
|
||||||
|
string name = PBD::basename_nosuffix (names[i]);
|
||||||
|
|
||||||
|
/* remove any existing version of suffix by assuming it starts
|
||||||
|
with some kind of "special" character.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!suffix.empty()) {
|
||||||
|
string::size_type pos = name.find (suffix[0]);
|
||||||
|
if (pos != string::npos && pos > 2) {
|
||||||
|
name = name.substr (0, pos - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string path = session.path_from_region_name (region->data_type(),
|
string path = session.path_from_region_name (region->data_type(),
|
||||||
PBD::basename_nosuffix (names[i]), string (""));
|
PBD::basename_nosuffix (names[i]), string (""));
|
||||||
|
|
||||||
|
|
@ -65,10 +78,8 @@ Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Filter::finish (boost::shared_ptr<Region> region, SourceList& nsrcs)
|
Filter::finish (boost::shared_ptr<Region> region, SourceList& nsrcs, string region_name)
|
||||||
{
|
{
|
||||||
string region_name;
|
|
||||||
|
|
||||||
/* update headers on new sources */
|
/* update headers on new sources */
|
||||||
|
|
||||||
time_t xnow;
|
time_t xnow;
|
||||||
|
|
@ -94,7 +105,9 @@ Filter::finish (boost::shared_ptr<Region> region, SourceList& nsrcs)
|
||||||
|
|
||||||
/* create a new region */
|
/* create a new region */
|
||||||
|
|
||||||
region_name = session.new_region_name (region->name());
|
if (region_name.empty()) {
|
||||||
|
region_name = session.new_region_name (region->name());
|
||||||
|
}
|
||||||
results.clear ();
|
results.clear ();
|
||||||
results.push_back (RegionFactory::create (nsrcs, 0, region->length(), region_name, 0,
|
results.push_back (RegionFactory::create (nsrcs, 0, region->length(), region_name, 0,
|
||||||
Region::Flag (Region::WholeFile|Region::DefaultFlags)));
|
Region::Flag (Region::WholeFile|Region::DefaultFlags)));
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,8 @@ MidiRegion::state (bool full)
|
||||||
LocaleGuard lg (X_("POSIX"));
|
LocaleGuard lg (X_("POSIX"));
|
||||||
|
|
||||||
node.add_property ("flags", enum_2_string (_flags));
|
node.add_property ("flags", enum_2_string (_flags));
|
||||||
|
|
||||||
|
// XXX these should move into Region
|
||||||
|
|
||||||
for (uint32_t n=0; n < _sources.size(); ++n) {
|
for (uint32_t n=0; n < _sources.size(); ++n) {
|
||||||
snprintf (buf2, sizeof(buf2), "source-%d", n);
|
snprintf (buf2, sizeof(buf2), "source-%d", n);
|
||||||
|
|
@ -196,6 +198,12 @@ MidiRegion::state (bool full)
|
||||||
node.add_property (buf2, buf);
|
node.add_property (buf2, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint32_t n=0; n < _master_sources.size(); ++n) {
|
||||||
|
snprintf (buf2, sizeof(buf2), "master-source-%d", n);
|
||||||
|
_master_sources[n]->id().print (buf, sizeof (buf));
|
||||||
|
node.add_property (buf2, buf);
|
||||||
|
}
|
||||||
|
|
||||||
if (full && _extra_xml) {
|
if (full && _extra_xml) {
|
||||||
node.add_child_copy (*_extra_xml);
|
node.add_child_copy (*_extra_xml);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,9 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
|
||||||
, _layer(layer)
|
, _layer(layer)
|
||||||
, _first_edit(EditChangesNothing)
|
, _first_edit(EditChangesNothing)
|
||||||
, _frozen(0)
|
, _frozen(0)
|
||||||
|
, _ancestral_start (start)
|
||||||
|
, _ancestral_length (length)
|
||||||
|
, _stretch (1.0)
|
||||||
, _read_data_count(0)
|
, _read_data_count(0)
|
||||||
, _pending_changed(Change (0))
|
, _pending_changed(Change (0))
|
||||||
, _last_layer_op(0)
|
, _last_layer_op(0)
|
||||||
|
|
@ -142,6 +145,9 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
|
||||||
, _layer(layer)
|
, _layer(layer)
|
||||||
, _first_edit(EditChangesNothing)
|
, _first_edit(EditChangesNothing)
|
||||||
, _frozen(0)
|
, _frozen(0)
|
||||||
|
, _ancestral_start (other->_ancestral_start + offset)
|
||||||
|
, _ancestral_length (length)
|
||||||
|
, _stretch (1.0)
|
||||||
, _read_data_count(0)
|
, _read_data_count(0)
|
||||||
, _pending_changed(Change (0))
|
, _pending_changed(Change (0))
|
||||||
, _last_layer_op(0)
|
, _last_layer_op(0)
|
||||||
|
|
@ -183,6 +189,9 @@ Region::Region (boost::shared_ptr<const Region> other)
|
||||||
, _layer(other->_layer)
|
, _layer(other->_layer)
|
||||||
, _first_edit(EditChangesID)
|
, _first_edit(EditChangesID)
|
||||||
, _frozen(0)
|
, _frozen(0)
|
||||||
|
, _ancestral_start (_start)
|
||||||
|
, _ancestral_length (_length)
|
||||||
|
, _stretch (1.0)
|
||||||
, _read_data_count(0)
|
, _read_data_count(0)
|
||||||
, _pending_changed(Change(0))
|
, _pending_changed(Change(0))
|
||||||
, _last_layer_op(other->_last_layer_op)
|
, _last_layer_op(other->_last_layer_op)
|
||||||
|
|
@ -517,6 +526,14 @@ Region::nudge_position (long n, void *src)
|
||||||
send_change (PositionChanged);
|
send_change (PositionChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st)
|
||||||
|
{
|
||||||
|
_ancestral_length = l;
|
||||||
|
_ancestral_start = s;
|
||||||
|
_stretch = st;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Region::set_start (nframes_t pos, void *src)
|
Region::set_start (nframes_t pos, void *src)
|
||||||
{
|
{
|
||||||
|
|
@ -922,6 +939,12 @@ Region::state (bool full_state)
|
||||||
node->add_property ("length", buf);
|
node->add_property ("length", buf);
|
||||||
snprintf (buf, sizeof (buf), "%u", _position);
|
snprintf (buf, sizeof (buf), "%u", _position);
|
||||||
node->add_property ("position", buf);
|
node->add_property ("position", buf);
|
||||||
|
snprintf (buf, sizeof (buf), "%lu", _ancestral_start);
|
||||||
|
node->add_property ("ancestral-start", buf);
|
||||||
|
snprintf (buf, sizeof (buf), "%lu", _ancestral_length);
|
||||||
|
node->add_property ("ancestral-length", buf);
|
||||||
|
snprintf (buf, sizeof (buf), "%.12g", _stretch);
|
||||||
|
node->add_property ("stretch", buf);
|
||||||
|
|
||||||
switch (_first_edit) {
|
switch (_first_edit) {
|
||||||
case EditChangesNothing:
|
case EditChangesNothing:
|
||||||
|
|
@ -1033,6 +1056,26 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
|
||||||
|
|
||||||
/* XXX FIRST EDIT !!! */
|
/* XXX FIRST EDIT !!! */
|
||||||
|
|
||||||
|
/* these 3 properties never change as a result of any editing */
|
||||||
|
|
||||||
|
if ((prop = node.property ("ancestral-start")) != 0) {
|
||||||
|
_ancestral_start = atoi (prop->value());
|
||||||
|
} else {
|
||||||
|
_ancestral_start = _start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property ("ancestral-length")) != 0) {
|
||||||
|
_ancestral_length = atoi (prop->value());
|
||||||
|
} else {
|
||||||
|
_ancestral_length = _length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prop = node.property ("stretch")) != 0) {
|
||||||
|
_stretch = atof (prop->value());
|
||||||
|
} else {
|
||||||
|
_stretch = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
/* note: derived classes set flags */
|
/* note: derived classes set flags */
|
||||||
|
|
||||||
if (_extra_xml) {
|
if (_extra_xml) {
|
||||||
|
|
@ -1185,6 +1228,12 @@ Region::master_source_names ()
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Region::set_master_sources (SourceList& srcs)
|
||||||
|
{
|
||||||
|
_master_sources = srcs;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Region::source_equivalent (boost::shared_ptr<const Region> other) const
|
Region::source_equivalent (boost::shared_ptr<const Region> other) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2113,8 +2113,13 @@ Session::remove_route (shared_ptr<Route> route)
|
||||||
|
|
||||||
/* try to cause everyone to drop their references */
|
/* try to cause everyone to drop their references */
|
||||||
|
|
||||||
|
cerr << "pre drop, Route now has " << route.use_count() << " refs\n";
|
||||||
|
cerr << "sig has " << route->GoingAway.size() << endl;
|
||||||
|
|
||||||
route->drop_references ();
|
route->drop_references ();
|
||||||
|
|
||||||
|
cerr << "route dangling refs = " << route.use_count() << endl;
|
||||||
|
|
||||||
/* save the new state of the world */
|
/* save the new state of the world */
|
||||||
|
|
||||||
if (save_state (_current_snapshot_name)) {
|
if (save_state (_current_snapshot_name)) {
|
||||||
|
|
|
||||||
|
|
@ -1373,6 +1373,7 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full)
|
||||||
boost::shared_ptr<Source> source;
|
boost::shared_ptr<Source> source;
|
||||||
boost::shared_ptr<AudioSource> as;
|
boost::shared_ptr<AudioSource> as;
|
||||||
SourceList sources;
|
SourceList sources;
|
||||||
|
SourceList master_sources;
|
||||||
uint32_t nchans = 1;
|
uint32_t nchans = 1;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
|
|
||||||
|
|
@ -1432,7 +1433,27 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full)
|
||||||
sources.push_back (as);
|
sources.push_back (as);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint32_t n=1; n < nchans; ++n) {
|
||||||
|
snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
|
||||||
|
if ((prop = node.property (buf)) != 0) {
|
||||||
|
|
||||||
|
PBD::ID id2 (prop->value());
|
||||||
|
|
||||||
|
if ((source = source_by_id (id2)) == 0) {
|
||||||
|
error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
|
||||||
|
return boost::shared_ptr<AudioRegion>();
|
||||||
|
}
|
||||||
|
|
||||||
|
as = boost::dynamic_pointer_cast<AudioSource>(source);
|
||||||
|
if (!as) {
|
||||||
|
error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
|
||||||
|
return boost::shared_ptr<AudioRegion>();
|
||||||
|
}
|
||||||
|
master_sources.push_back (as);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
|
boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
|
||||||
|
|
||||||
|
|
@ -1447,6 +1468,14 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!master_sources.empty()) {
|
||||||
|
if (master_sources.size() == nchans) {
|
||||||
|
error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
|
||||||
|
} else {
|
||||||
|
region->set_master_sources (master_sources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return region;
|
return region;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,236 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (C) 2003 Paul Davis
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cerrno>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include <pbd/basename.h>
|
|
||||||
|
|
||||||
#include <soundtouch/SoundTouch.h>
|
|
||||||
|
|
||||||
#include <ardour/session.h>
|
|
||||||
#include <ardour/audioregion.h>
|
|
||||||
#include <ardour/sndfilesource.h>
|
|
||||||
#include <ardour/region_factory.h>
|
|
||||||
#include <ardour/source_factory.h>
|
|
||||||
|
|
||||||
#include "i18n.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace ARDOUR;
|
|
||||||
using namespace PBD;
|
|
||||||
using namespace soundtouch;
|
|
||||||
|
|
||||||
boost::shared_ptr<AudioRegion>
|
|
||||||
Session::tempoize_region (TimeStretchRequest& tsr)
|
|
||||||
{
|
|
||||||
SourceList sources;
|
|
||||||
SourceList::iterator it;
|
|
||||||
boost::shared_ptr<AudioRegion> r;
|
|
||||||
SoundTouch st;
|
|
||||||
string region_name;
|
|
||||||
string ident = X_("-TIMEFX-");
|
|
||||||
float percentage;
|
|
||||||
nframes_t total_frames;
|
|
||||||
nframes_t done;
|
|
||||||
int c;
|
|
||||||
char buf[64];
|
|
||||||
string::size_type len;
|
|
||||||
|
|
||||||
/* the soundtouch code wants a *tempo* change percentage, which is
|
|
||||||
of opposite sign to the length change.
|
|
||||||
*/
|
|
||||||
|
|
||||||
percentage = -tsr.fraction;
|
|
||||||
|
|
||||||
st.setSampleRate (frame_rate());
|
|
||||||
st.setChannels (1);
|
|
||||||
st.setTempoChange (percentage);
|
|
||||||
st.setPitchSemiTones (0);
|
|
||||||
st.setRateChange (0);
|
|
||||||
|
|
||||||
st.setSetting(SETTING_USE_QUICKSEEK, tsr.quick_seek);
|
|
||||||
st.setSetting(SETTING_USE_AA_FILTER, tsr.antialias);
|
|
||||||
|
|
||||||
vector<string> names = tsr.region->master_source_names();
|
|
||||||
|
|
||||||
tsr.progress = 0.0f;
|
|
||||||
total_frames = tsr.region->length() * tsr.region->n_channels();
|
|
||||||
done = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < tsr.region->n_channels(); ++i) {
|
|
||||||
|
|
||||||
string rstr;
|
|
||||||
string::size_type existing_ident;
|
|
||||||
|
|
||||||
if ((existing_ident = names[i].find (ident)) != string::npos) {
|
|
||||||
rstr = names[i].substr (0, existing_ident);
|
|
||||||
} else {
|
|
||||||
rstr = names[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
string path = path_from_region_name (DataType::AUDIO, PBD::basename_nosuffix (rstr), ident);
|
|
||||||
|
|
||||||
if (path.length() == 0) {
|
|
||||||
error << string_compose (_("tempoize: error creating name for new audio file based on %1"), tsr.region->name())
|
|
||||||
<< endmsg;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
sources.push_back (boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *this, path, false, frame_rate())));
|
|
||||||
|
|
||||||
} catch (failed_constructor& err) {
|
|
||||||
error << string_compose (_("tempoize: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const nframes_t bufsize = 16384;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sources.size(); ++i) {
|
|
||||||
gain_t gain_buffer[bufsize];
|
|
||||||
Sample buffer[bufsize];
|
|
||||||
nframes_t pos = 0;
|
|
||||||
nframes_t this_read = 0;
|
|
||||||
|
|
||||||
boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(sources[i]);
|
|
||||||
if (!asrc) {
|
|
||||||
cerr << "FIXME: TimeFX for non-audio" << endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
st.clear();
|
|
||||||
while (tsr.running && pos < tsr.region->length()) {
|
|
||||||
nframes_t this_time;
|
|
||||||
|
|
||||||
this_time = min (bufsize, tsr.region->length() - pos);
|
|
||||||
|
|
||||||
/* read from the master (original) sources for the region,
|
|
||||||
not the ones currently in use, in case it's already been
|
|
||||||
subject to timefx. */
|
|
||||||
|
|
||||||
if ((this_read = tsr.region->master_read_at (buffer, buffer, gain_buffer, pos + tsr.region->position(), this_time)) != this_time) {
|
|
||||||
error << string_compose (_("tempoize: error reading data from %1"), sources[i]->name()) << endmsg;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += this_read;
|
|
||||||
done += this_read;
|
|
||||||
|
|
||||||
tsr.progress = (float) done / total_frames;
|
|
||||||
|
|
||||||
st.putSamples (buffer, this_read);
|
|
||||||
|
|
||||||
while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && tsr.running) {
|
|
||||||
if (asrc->write (buffer, this_read) != this_read) {
|
|
||||||
error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tsr.running) {
|
|
||||||
st.flush ();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (tsr.running && (this_read = st.receiveSamples (buffer, bufsize)) > 0) {
|
|
||||||
if (asrc->write (buffer, this_read) != this_read) {
|
|
||||||
error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (runtime_error& err) {
|
|
||||||
error << _("timefx code failure. please notify ardour-developers.") << endmsg;
|
|
||||||
error << err.what() << endmsg;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t now;
|
|
||||||
struct tm* xnow;
|
|
||||||
time (&now);
|
|
||||||
xnow = localtime (&now);
|
|
||||||
|
|
||||||
for (it = sources.begin(); it != sources.end(); ++it) {
|
|
||||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*it);
|
|
||||||
if (afs) {
|
|
||||||
afs->update_header (tsr.region->position(), *xnow, now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
len = tsr.region->name().length();
|
|
||||||
|
|
||||||
while (--len) {
|
|
||||||
if (!isdigit (tsr.region->name()[len])) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
|
|
||||||
region_name = tsr.region->name() + ".t000";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (tsr.region->name()[len] == 't') {
|
|
||||||
c = atoi (tsr.region->name().substr(len+1).c_str());
|
|
||||||
|
|
||||||
snprintf (buf, sizeof (buf), "t%03d", ++c);
|
|
||||||
region_name = tsr.region->name().substr (0, len) + buf;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* not sure what this is, just tack the suffix on to it */
|
|
||||||
|
|
||||||
region_name = tsr.region->name() + ".t000";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
r = (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, 0, sources.front()->length(), region_name,
|
|
||||||
0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile))));
|
|
||||||
|
|
||||||
out:
|
|
||||||
|
|
||||||
if (sources.size()) {
|
|
||||||
|
|
||||||
/* if we failed to complete for any reason, mark the new file
|
|
||||||
for deletion.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ((!r || !tsr.running)) {
|
|
||||||
for (it = sources.begin(); it != sources.end(); ++it) {
|
|
||||||
(*it)->mark_for_remove ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sources.clear ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the process was cancelled, delete the region */
|
|
||||||
|
|
||||||
if (!tsr.running) {
|
|
||||||
r.reset ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
227
libs/ardour/stretch.cc
Normal file
227
libs/ardour/stretch.cc
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2004-2007 Paul Davis
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <pbd/error.h>
|
||||||
|
|
||||||
|
#include <ardour/types.h>
|
||||||
|
#include <ardour/stretch.h>
|
||||||
|
#include <ardour/audiofilesource.h>
|
||||||
|
#include <ardour/session.h>
|
||||||
|
#include <ardour/audioregion.h>
|
||||||
|
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace ARDOUR;
|
||||||
|
using namespace PBD;
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
Stretch::Stretch (Session& s, TimeStretchRequest& req)
|
||||||
|
: Filter (s)
|
||||||
|
, tsr (req)
|
||||||
|
{
|
||||||
|
float percentage;
|
||||||
|
|
||||||
|
/* the soundtouch code wants a *tempo* change percentage, which is
|
||||||
|
of opposite sign to the length change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
percentage = -tsr.fraction;
|
||||||
|
|
||||||
|
st.setSampleRate (s.frame_rate());
|
||||||
|
st.setChannels (1);
|
||||||
|
st.setTempoChange (percentage);
|
||||||
|
st.setPitchSemiTones (0);
|
||||||
|
st.setRateChange (0);
|
||||||
|
|
||||||
|
st.setSetting(SETTING_USE_QUICKSEEK, tsr.quick_seek);
|
||||||
|
st.setSetting(SETTING_USE_AA_FILTER, tsr.antialias);
|
||||||
|
|
||||||
|
tsr.progress = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stretch::~Stretch ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Stretch::run (boost::shared_ptr<Region> r)
|
||||||
|
{
|
||||||
|
boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
|
||||||
|
|
||||||
|
if (!region) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceList nsrcs;
|
||||||
|
nframes_t total_frames;
|
||||||
|
nframes_t done;
|
||||||
|
int ret = -1;
|
||||||
|
const nframes_t bufsize = 16384;
|
||||||
|
gain_t *gain_buffer = 0;
|
||||||
|
Sample *buffer = 0;
|
||||||
|
char suffix[32];
|
||||||
|
string new_name;
|
||||||
|
string::size_type at;
|
||||||
|
|
||||||
|
tsr.progress = 0.0f;
|
||||||
|
tsr.done = false;
|
||||||
|
|
||||||
|
total_frames = region->length() * region->n_channels();
|
||||||
|
done = 0;
|
||||||
|
|
||||||
|
/* the name doesn't need to be super-precise, but allow for 2 fractional
|
||||||
|
digits just to disambiguate close but not identical stretches.
|
||||||
|
*/
|
||||||
|
|
||||||
|
snprintf (suffix, sizeof (suffix), "@%d", (int) floor (tsr.fraction * 100.0f));
|
||||||
|
|
||||||
|
/* create new sources */
|
||||||
|
|
||||||
|
if (make_new_sources (region, nsrcs, suffix)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
gain_buffer = new gain_t[bufsize];
|
||||||
|
buffer = new Sample[bufsize];
|
||||||
|
|
||||||
|
// soundtouch throws runtime_error on error
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (uint32_t i = 0; i < nsrcs.size(); ++i) {
|
||||||
|
|
||||||
|
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (nsrcs[i]);
|
||||||
|
|
||||||
|
if (!afs) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nframes_t pos = 0;
|
||||||
|
nframes_t this_read = 0;
|
||||||
|
|
||||||
|
st.clear();
|
||||||
|
|
||||||
|
while (!tsr.cancel && pos < region->length()) {
|
||||||
|
nframes_t this_time;
|
||||||
|
|
||||||
|
this_time = min (bufsize, region->length() - pos);
|
||||||
|
|
||||||
|
/* read from the master (original) sources for the region,
|
||||||
|
not the ones currently in use, in case it's already been
|
||||||
|
subject to timefx.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((this_read = region->master_read_at (buffer, buffer, gain_buffer, pos + region->position(), this_time)) != this_time) {
|
||||||
|
error << string_compose (_("tempoize: error reading data from %1"), afs->name()) << endmsg;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += this_read;
|
||||||
|
done += this_read;
|
||||||
|
|
||||||
|
tsr.progress = (float) done / total_frames;
|
||||||
|
|
||||||
|
st.putSamples (buffer, this_read);
|
||||||
|
|
||||||
|
while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && !tsr.cancel) {
|
||||||
|
if (afs->write (buffer, this_read) != this_read) {
|
||||||
|
error << string_compose (_("error writing tempo-adjusted data to %1"), afs->name()) << endmsg;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tsr.cancel) {
|
||||||
|
st.flush ();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!tsr.cancel && (this_read = st.receiveSamples (buffer, bufsize)) > 0) {
|
||||||
|
if (afs->write (buffer, this_read) != this_read) {
|
||||||
|
error << string_compose (_("error writing tempo-adjusted data to %1"), afs->name()) << endmsg;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (runtime_error& err) {
|
||||||
|
error << _("timefx code failure. please notify ardour-developers.") << endmsg;
|
||||||
|
error << err.what() << endmsg;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_name = region->name();
|
||||||
|
at = new_name.find ('@');
|
||||||
|
|
||||||
|
// remove any existing stretch indicator
|
||||||
|
|
||||||
|
if (at != string::npos && at > 2) {
|
||||||
|
new_name = new_name.substr (0, at - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_name += suffix;
|
||||||
|
|
||||||
|
ret = finish (region, nsrcs, new_name);
|
||||||
|
|
||||||
|
/* now reset ancestral data for each new region */
|
||||||
|
|
||||||
|
for (vector<boost::shared_ptr<Region> >::iterator x = results.begin(); x != results.end(); ++x) {
|
||||||
|
|
||||||
|
boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (*x);
|
||||||
|
|
||||||
|
assert (region != 0);
|
||||||
|
|
||||||
|
nframes64_t astart = region->ancestral_start();
|
||||||
|
nframes64_t alength = region->ancestral_length();
|
||||||
|
nframes_t start;
|
||||||
|
nframes_t length;
|
||||||
|
|
||||||
|
// note: tsr.fraction is a percentage of original length. 100 = no change,
|
||||||
|
// 50 is half as long, 200 is twice as long, etc.
|
||||||
|
|
||||||
|
float stretch = region->stretch() * (tsr.fraction/100.0);
|
||||||
|
|
||||||
|
start = (nframes_t) floor (astart + ((astart - region->start()) / stretch));
|
||||||
|
length = (nframes_t) floor (alength / stretch);
|
||||||
|
|
||||||
|
region->set_ancestral_data (start, length, stretch);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
if (gain_buffer) {
|
||||||
|
delete [] gain_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
delete [] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret || tsr.cancel) {
|
||||||
|
for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
|
||||||
|
(*si)->mark_for_remove ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tsr.done = true;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue