mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-29 16:33:14 +01:00
Merge branch 'cairocanvas' into recfolder
Conflicts: libs/ardour/session.cc
This commit is contained in:
commit
07d31cc2da
72 changed files with 1205 additions and 756 deletions
|
|
@ -12,6 +12,11 @@
|
|||
<accelerator action='track-mute-toggle'/>
|
||||
<accelerator action='toggle-edit-mode'/>
|
||||
<accelerator action='toggle-midi-input-active'/>
|
||||
<accelerator action='escape'/>
|
||||
|
||||
<accelerator action='alt-start-range'/>
|
||||
<accelerator action='alt-finish-range'/>
|
||||
|
||||
#ifdef GTKOSX
|
||||
<accelerator action='Quit'/>
|
||||
#endif
|
||||
|
|
@ -190,7 +195,6 @@
|
|||
<menuitem action='move-range-end-to-next-region-boundary'/>
|
||||
<menuitem action='start-range'/>
|
||||
<menuitem action='finish-range'/>
|
||||
<menuitem action='finish-add-range'/>
|
||||
<separator/>
|
||||
<menuitem action='select-next-route'/>
|
||||
<menuitem action='select-prev-route'/>
|
||||
|
|
@ -250,8 +254,6 @@
|
|||
<menuitem action='combine-regions'/>
|
||||
<menuitem action='uncombine-regions'/>
|
||||
<menuitem action='analyze-region'/>
|
||||
<menuitem action='toggle-opaque-region'/>
|
||||
<menuitem action='toggle-region-mute'/>
|
||||
<menuitem action='pitch-shift-region'/>
|
||||
<menuitem action='split-region'/>
|
||||
<menuitem action='split-multichannel-region'/>
|
||||
|
|
@ -275,6 +277,8 @@
|
|||
<menuitem action='show-region-list-editor'/>
|
||||
</menu>
|
||||
<menu action='RegionMenuGain'>
|
||||
<menuitem action='toggle-opaque-region'/>
|
||||
<menuitem action='toggle-region-mute'/>
|
||||
<menuitem action='normalize-region'/>
|
||||
<menuitem action='boost-region-gain'/>
|
||||
<menuitem action='cut-region-gain'/>
|
||||
|
|
@ -625,8 +629,6 @@
|
|||
<menuitem action='uncombine-regions'/>
|
||||
<menuitem action='split-region'/>
|
||||
<menuitem action='split-multichannel-region'/>
|
||||
<menuitem action='toggle-opaque-region'/>
|
||||
<menuitem action='toggle-region-mute'/>
|
||||
<menuitem action='pitch-shift-region'/>
|
||||
<menuitem action='reverse-region'/>
|
||||
<menuitem action='close-region-gaps'/>
|
||||
|
|
@ -677,6 +679,8 @@
|
|||
<menuitem action='set-selection-from-region'/>
|
||||
</menu>
|
||||
<menu action='RegionMenuGain'>
|
||||
<menuitem action='toggle-opaque-region'/>
|
||||
<menuitem action='toggle-region-mute'/>
|
||||
<menuitem action='normalize-region'/>
|
||||
<menuitem action='boost-region-gain'/>
|
||||
<menuitem action='cut-region-gain'/>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<Option name="ui-rc-file" value="ardour3_ui_dark.rc"/>
|
||||
<Option name="flat-buttons" value="00000000"/>
|
||||
<Option name="waveform-gradient-depth" value="0"/>
|
||||
<Option name="timeline-item-gradient-depth" value="00000.95"/>
|
||||
<Option name="timeline-item-gradient-depth" value="00000.5"/>
|
||||
<Option name="all-floating-windows-are-dialogs" value="00000000"/>
|
||||
<Option name="color-regions-using-track-color" value="00000000"/>
|
||||
<Option name="show-waveform-clipping" value="00000001"/>
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
<Option name="image track" value="ddddd8ff"/>
|
||||
<Option name="inactive crossfade" value="e8ed3d77"/>
|
||||
<Option name="inactive fade handle" value="bbbbbbaa"/>
|
||||
<Option name="inactive group tab" value="434343ff"/>
|
||||
<Option name="location cd marker" value="1ee8c4ff"/>
|
||||
<Option name="location loop" value="35964fff"/>
|
||||
<Option name="location marker" value="c4f411ff"/>
|
||||
|
|
@ -172,7 +173,7 @@
|
|||
<Option name="verbose canvas cursor" value="fffd2ebc"/>
|
||||
<Option name="vestigial frame" value="0000000f"/>
|
||||
<Option name="video timeline bar" value="303030ff"/>
|
||||
<Option name="region base" value="99a7b5a0"/>
|
||||
<Option name="region base" value="b1c9b1ff"/>
|
||||
<Option name="region area covered by another region" value="505050b0"/>
|
||||
<Option name="waveform outline" value="000000ff"/>
|
||||
<Option name="clipped waveform" value="ff0000e5"/>
|
||||
|
|
|
|||
|
|
@ -104,6 +104,11 @@ AudioTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
|||
create_automation_child (GainAutomation, false);
|
||||
}
|
||||
|
||||
/* if set_state above didn't create a mute automation child, we need to make one */
|
||||
if (automation_child (MuteAutomation) == 0) {
|
||||
create_automation_child (MuteAutomation, false);
|
||||
}
|
||||
|
||||
if (_route->panner_shell()) {
|
||||
_route->panner_shell()->Changed.connect (*this, invalidator (*this),
|
||||
boost::bind (&AudioTimeAxisView::ensure_pan_views, this, false), gui_context());
|
||||
|
|
@ -202,6 +207,11 @@ AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
|
|||
|
||||
/* handled elsewhere */
|
||||
|
||||
} else if (param.type() == MuteAutomation) {
|
||||
|
||||
create_mute_automation_child (param, show);
|
||||
|
||||
|
||||
} else {
|
||||
error << "AudioTimeAxisView: unknown automation child " << EventTypeMap::instance().to_symbol(param) << endmsg;
|
||||
}
|
||||
|
|
@ -283,6 +293,22 @@ AudioTimeAxisView::update_gain_track_visibility ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioTimeAxisView::update_mute_track_visibility ()
|
||||
{
|
||||
bool const showit = mute_automation_item->get_active();
|
||||
|
||||
if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) {
|
||||
mute_track->set_marked_for_display (showit);
|
||||
|
||||
/* now trigger a redisplay */
|
||||
|
||||
if (!no_redraw) {
|
||||
_route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioTimeAxisView::update_pan_track_visibility ()
|
||||
{
|
||||
|
|
@ -404,6 +430,13 @@ AudioTimeAxisView::build_automation_action_menu (bool for_selection)
|
|||
|
||||
_main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
|
||||
|
||||
automation_items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &AudioTimeAxisView::update_mute_track_visibility)));
|
||||
mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
|
||||
mute_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
|
||||
(mute_track && string_is_affirmative (mute_track->gui_property ("visible"))));
|
||||
|
||||
_main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
|
||||
|
||||
if (!pan_tracks.empty()) {
|
||||
automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &AudioTimeAxisView::update_pan_track_visibility)));
|
||||
pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
|
||||
|
|
|
|||
|
|
@ -105,9 +105,11 @@ class AudioTimeAxisView : public RouteTimeAxisView
|
|||
void update_control_names ();
|
||||
|
||||
void update_gain_track_visibility ();
|
||||
void update_mute_track_visibility ();
|
||||
void update_pan_track_visibility ();
|
||||
|
||||
Gtk::CheckMenuItem* gain_automation_item;
|
||||
Gtk::CheckMenuItem* mute_automation_item;
|
||||
std::list<boost::shared_ptr<AutomationTimeAxisView> > pan_tracks;
|
||||
Gtk::CheckMenuItem* pan_automation_item;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ CANVAS_VARIABLE(canvasvar_GhostTrackZeroLine, "ghost track zero line")
|
|||
CANVAS_VARIABLE(canvasvar_ImageTrack, "image track")
|
||||
CANVAS_VARIABLE(canvasvar_InactiveCrossfade, "inactive crossfade")
|
||||
CANVAS_VARIABLE(canvasvar_InactiveFadeHandle, "inactive fade handle")
|
||||
CANVAS_VARIABLE(canvasvar_InactiveGroupTab, "inactive group tab")
|
||||
CANVAS_VARIABLE(canvasvar_LocationCDMarker, "location cd marker")
|
||||
CANVAS_VARIABLE(canvasvar_LocationLoop, "location loop")
|
||||
CANVAS_VARIABLE(canvasvar_LocationMarker, "location marker")
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@
|
|||
#include "tempo_lines.h"
|
||||
#include "time_axis_view.h"
|
||||
#include "utils.h"
|
||||
#include "verbose_cursor.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
|
@ -263,7 +264,6 @@ Editor::Editor ()
|
|||
|
||||
/* tool bar related */
|
||||
|
||||
, zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
|
||||
, toolbar_selection_clock_table (2,3)
|
||||
, _mouse_mode_tearoff (0)
|
||||
, automation_mode_button (_("mode"))
|
||||
|
|
@ -393,8 +393,6 @@ Editor::Editor ()
|
|||
|
||||
_scroll_callbacks = 0;
|
||||
|
||||
zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
|
||||
|
||||
bbt_label.set_name ("EditorRulerLabel");
|
||||
bbt_label.set_size_request (-1, (int)timebar_height);
|
||||
bbt_label.set_alignment (1.0, 0.5);
|
||||
|
|
@ -760,9 +758,14 @@ Editor::Editor ()
|
|||
}
|
||||
|
||||
constructed = true;
|
||||
instant_save ();
|
||||
|
||||
/* grab current parameter state */
|
||||
boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
|
||||
ARDOUR_UI::config()->map_parameters (pc);
|
||||
|
||||
setup_fade_images ();
|
||||
|
||||
instant_save ();
|
||||
}
|
||||
|
||||
Editor::~Editor()
|
||||
|
|
@ -914,23 +917,6 @@ Editor::instant_save ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::zoom_adjustment_changed ()
|
||||
{
|
||||
if (_session == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
|
||||
bool clamped = clamp_samples_per_pixel (fpu);
|
||||
|
||||
if (clamped) {
|
||||
zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
|
||||
}
|
||||
|
||||
temporal_zoom (fpu);
|
||||
}
|
||||
|
||||
void
|
||||
Editor::control_vertical_zoom_in_all ()
|
||||
{
|
||||
|
|
@ -1248,7 +1234,6 @@ Editor::set_session (Session *t)
|
|||
return;
|
||||
}
|
||||
|
||||
zoom_range_clock->set_session (_session);
|
||||
_playlist_selector->set_session (_session);
|
||||
nudge_clock->set_session (_session);
|
||||
_summary->set_session (_session);
|
||||
|
|
@ -2819,12 +2804,6 @@ Editor::setup_toolbar ()
|
|||
|
||||
mouse_mode_box->pack_start (*mouse_mode_align, false, false);
|
||||
|
||||
edit_mode_strings.push_back (edit_mode_to_string (Slide));
|
||||
if (!Profile->get_sae()) {
|
||||
edit_mode_strings.push_back (edit_mode_to_string (Splice));
|
||||
}
|
||||
edit_mode_strings.push_back (edit_mode_to_string (Lock));
|
||||
|
||||
edit_mode_selector.set_name ("mouse mode button");
|
||||
edit_mode_selector.set_size_request (65, -1);
|
||||
edit_mode_selector.add_elements (ArdourButton::Inset);
|
||||
|
|
@ -3040,7 +3019,8 @@ Editor::build_edit_mode_menu ()
|
|||
using namespace Menu_Helpers;
|
||||
|
||||
edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
|
||||
edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
|
||||
// edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
|
||||
edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Ripple), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
|
||||
edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
|
||||
}
|
||||
|
||||
|
|
@ -3352,10 +3332,11 @@ Editor::cycle_edit_mode ()
|
|||
if (Profile->get_sae()) {
|
||||
Config->set_edit_mode (Lock);
|
||||
} else {
|
||||
Config->set_edit_mode (Splice);
|
||||
Config->set_edit_mode (Ripple);
|
||||
}
|
||||
break;
|
||||
case Splice:
|
||||
case Ripple:
|
||||
Config->set_edit_mode (Lock);
|
||||
break;
|
||||
case Lock:
|
||||
|
|
@ -4075,8 +4056,6 @@ Editor::reset_y_origin (double y)
|
|||
void
|
||||
Editor::reset_zoom (framecnt_t spp)
|
||||
{
|
||||
clamp_samples_per_pixel (spp);
|
||||
|
||||
if (spp == samples_per_pixel) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -4188,26 +4167,32 @@ Editor::use_visual_state (VisualState& vs)
|
|||
|
||||
/** This is the core function that controls the zoom level of the canvas. It is called
|
||||
* whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
|
||||
* @param fpu New frames per unit; should already have been clamped so that it is sensible.
|
||||
* @param spp new number of samples per pixel
|
||||
*/
|
||||
void
|
||||
Editor::set_samples_per_pixel (framecnt_t spp)
|
||||
{
|
||||
clamp_samples_per_pixel (spp);
|
||||
if (spp < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
|
||||
const framecnt_t lots_of_pixels = 4000;
|
||||
|
||||
/* if the zoom level is greater than what you'd get trying to display 3
|
||||
* days of audio on a really big screen, then it's too big.
|
||||
*/
|
||||
|
||||
if (spp * lots_of_pixels > three_days) {
|
||||
return;
|
||||
}
|
||||
|
||||
samples_per_pixel = spp;
|
||||
|
||||
if (tempo_lines) {
|
||||
tempo_lines->tempo_map_changed();
|
||||
}
|
||||
|
||||
/* convert fpu to frame count */
|
||||
|
||||
framepos_t frames = samples_per_pixel * _visible_canvas_width;
|
||||
|
||||
if (samples_per_pixel != zoom_range_clock->current_duration()) {
|
||||
zoom_range_clock->set (frames);
|
||||
}
|
||||
|
||||
bool const showing_time_selection = selection->time.length() > 0;
|
||||
|
||||
if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
|
||||
|
|
@ -4561,11 +4546,8 @@ Editor::get_regions_from_selection_and_edit_point ()
|
|||
|
||||
if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
|
||||
regions.add (entered_regionview);
|
||||
} else {
|
||||
regions = selection->regions;
|
||||
}
|
||||
|
||||
|
||||
if (regions.empty() && _edit_point != EditAtMouse) {
|
||||
TrackViewList tracks = selection->tracks;
|
||||
|
||||
|
|
@ -4874,6 +4856,10 @@ Editor::add_routes (RouteList& routes)
|
|||
void
|
||||
Editor::timeaxisview_deleted (TimeAxisView *tv)
|
||||
{
|
||||
if (tv == entered_track) {
|
||||
entered_track = 0;
|
||||
}
|
||||
|
||||
if (_session && _session->deletion_in_progress()) {
|
||||
/* the situation is under control */
|
||||
return;
|
||||
|
|
@ -4885,10 +4871,6 @@ Editor::timeaxisview_deleted (TimeAxisView *tv)
|
|||
|
||||
_routes->route_removed (tv);
|
||||
|
||||
if (tv == entered_track) {
|
||||
entered_track = 0;
|
||||
}
|
||||
|
||||
TimeAxisView::Children c = tv->get_child_list ();
|
||||
for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
|
||||
if (entered_track == i->get()) {
|
||||
|
|
@ -5320,7 +5302,6 @@ Editor::session_going_away ()
|
|||
}
|
||||
track_views.clear ();
|
||||
|
||||
zoom_range_clock->set_session (0);
|
||||
nudge_clock->set_session (0);
|
||||
|
||||
editor_list_button.set_active(false);
|
||||
|
|
@ -5506,5 +5487,9 @@ Editor::ui_parameter_changed (string parameter)
|
|||
_cursor_stack.pop();
|
||||
}
|
||||
_cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
|
||||
} else if (parameter == "draggable-playhead") {
|
||||
if (_verbose_cursor) {
|
||||
playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -520,7 +520,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
Editing::ZoomFocus zoom_focus;
|
||||
|
||||
void set_samples_per_pixel (framecnt_t);
|
||||
bool clamp_samples_per_pixel (framecnt_t &) const;
|
||||
|
||||
Editing::MouseMode mouse_mode;
|
||||
Editing::MouseMode pre_internal_mouse_mode;
|
||||
|
|
@ -1251,7 +1250,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
int target_regions, int target_tracks, boost::shared_ptr<ARDOUR::Track>&, bool add_channel_suffix);
|
||||
|
||||
int finish_bringing_in_material (boost::shared_ptr<ARDOUR::Region> region, uint32_t, uint32_t, framepos_t& pos, Editing::ImportMode mode,
|
||||
boost::shared_ptr<ARDOUR::Track>& existing_track);
|
||||
boost::shared_ptr<ARDOUR::Track>& existing_track, const std::string& new_track_name);
|
||||
|
||||
boost::shared_ptr<ARDOUR::AudioTrack> get_nth_selected_audio_track (int nth) const;
|
||||
boost::shared_ptr<ARDOUR::MidiTrack> get_nth_selected_midi_track (int nth) const;
|
||||
|
|
@ -1578,8 +1577,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
void editor_mixer_button_toggled ();
|
||||
void editor_list_button_toggled ();
|
||||
|
||||
AudioClock* zoom_range_clock;
|
||||
|
||||
ArdourButton zoom_in_button;
|
||||
ArdourButton zoom_out_button;
|
||||
ArdourButton zoom_out_full_button;
|
||||
|
|
@ -1626,7 +1623,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
void edit_mode_selection_done ( ARDOUR::EditMode m );
|
||||
void build_edit_mode_menu ();
|
||||
Gtk::VBox edit_mode_box;
|
||||
std::vector<std::string> edit_mode_strings;
|
||||
|
||||
void set_edit_mode (ARDOUR::EditMode);
|
||||
void cycle_edit_mode ();
|
||||
|
|
@ -2102,6 +2098,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
friend class RegionDrag;
|
||||
friend class RegionMoveDrag;
|
||||
friend class RegionSpliceDrag;
|
||||
friend class RegionRippleDrag;
|
||||
friend class TrimDrag;
|
||||
friend class MeterMarkerDrag;
|
||||
friend class TempoMarkerDrag;
|
||||
|
|
|
|||
|
|
@ -333,7 +333,11 @@ Editor::register_actions ()
|
|||
|
||||
reg_sens (editor_actions, "start-range", _("Start Range"), sigc::mem_fun(*this, &Editor::keyboard_selection_begin));
|
||||
reg_sens (editor_actions, "finish-range", _("Finish Range"), sigc::bind (sigc::mem_fun(*this, &Editor::keyboard_selection_finish), false));
|
||||
reg_sens (editor_actions, "finish-add-range", _("Finish Add Range"), sigc::bind (sigc::mem_fun(*this, &Editor::keyboard_selection_finish), true));
|
||||
|
||||
reg_sens (editor_actions, "alt-start-range", _("Start Range"), sigc::mem_fun(*this, &Editor::keyboard_selection_begin));
|
||||
reg_sens (editor_actions, "alt-finish-range", _("Finish Range"), sigc::bind (sigc::mem_fun(*this, &Editor::keyboard_selection_finish), false));
|
||||
|
||||
// reg_sens (editor_actions, "finish-add-range", _("Finish Add Range"), sigc::bind (sigc::mem_fun(*this, &Editor::keyboard_selection_finish), true));
|
||||
|
||||
reg_sens (
|
||||
editor_actions,
|
||||
|
|
@ -480,9 +484,9 @@ Editor::register_actions ()
|
|||
|
||||
ActionManager::register_action (editor_actions, "cycle-edit-point", _("Change Edit Point"), sigc::bind (sigc::mem_fun (*this, &Editor::cycle_edit_point), false));
|
||||
ActionManager::register_action (editor_actions, "cycle-edit-point-with-marker", _("Change Edit Point Including Marker"), sigc::bind (sigc::mem_fun (*this, &Editor::cycle_edit_point), true));
|
||||
if (!Profile->get_sae()) {
|
||||
ActionManager::register_action (editor_actions, "set-edit-splice", _("Splice"), sigc::bind (sigc::mem_fun (*this, &Editor::set_edit_mode), Splice));
|
||||
}
|
||||
|
||||
// ActionManager::register_action (editor_actions, "set-edit-splice", _("Splice"), sigc::bind (sigc::mem_fun (*this, &Editor::set_edit_mode), Splice));
|
||||
ActionManager::register_action (editor_actions, "set-edit-ripple", _("Ripple"), bind (mem_fun (*this, &Editor::set_edit_mode), Ripple));
|
||||
ActionManager::register_action (editor_actions, "set-edit-slide", _("Slide"), sigc::bind (sigc::mem_fun (*this, &Editor::set_edit_mode), Slide));
|
||||
ActionManager::register_action (editor_actions, "set-edit-lock", _("Lock"), sigc::bind (sigc::mem_fun (*this, &Editor::set_edit_mode), Lock));
|
||||
ActionManager::register_action (editor_actions, "toggle-edit-mode", _("Toggle Edit Mode"), sigc::mem_fun (*this, &Editor::cycle_edit_mode));
|
||||
|
|
|
|||
|
|
@ -654,7 +654,8 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
uint32_t input_chan = 0;
|
||||
uint32_t output_chan = 0;
|
||||
bool use_timestamp;
|
||||
|
||||
vector<string> track_names;
|
||||
|
||||
use_timestamp = (pos == -1);
|
||||
|
||||
// kludge (for MIDI we're abusing "channel" for "track" here)
|
||||
|
|
@ -691,6 +692,11 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
|
||||
regions.push_back (r);
|
||||
|
||||
/* if we're creating a new track, name it after the cleaned-up
|
||||
* and "merged" region name.
|
||||
*/
|
||||
|
||||
track_names.push_back (region_name);
|
||||
|
||||
} else if (target_regions == -1 || target_regions > 1) {
|
||||
|
||||
|
|
@ -721,29 +727,26 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
region_name = (*x)->name();
|
||||
}
|
||||
|
||||
switch (sources.size()) {
|
||||
/* zero and one channel handled
|
||||
by previous if() condition
|
||||
*/
|
||||
case 2:
|
||||
if (sources.size() == 2) {
|
||||
if (n == 0) {
|
||||
region_name += "-L";
|
||||
} else {
|
||||
region_name += "-R";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
region_name += (char) '-';
|
||||
region_name += (char) ('1' + n);
|
||||
break;
|
||||
} else if (sources.size() > 2) {
|
||||
region_name += string_compose ("-%1", n+1);
|
||||
}
|
||||
|
||||
track_names.push_back (region_name);
|
||||
|
||||
} else {
|
||||
if (fs) {
|
||||
region_name = region_name_from_path (fs->path(), false, false, sources.size(), n);
|
||||
} else{
|
||||
} else {
|
||||
region_name = (*x)->name();
|
||||
}
|
||||
|
||||
track_names.push_back (PBD::basename_nosuffix (paths[n]));
|
||||
}
|
||||
|
||||
PropertyList plist;
|
||||
|
|
@ -795,6 +798,12 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
framepos_t rlen = 0;
|
||||
|
||||
begin_reversible_command (Operations::insert_file);
|
||||
|
||||
/* we only use tracks names when importing to new tracks, but we
|
||||
* require that one is defined for every region, just to keep
|
||||
* the API simpler.
|
||||
*/
|
||||
assert (regions.size() == track_names.size());
|
||||
|
||||
for (vector<boost::shared_ptr<Region> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
|
||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (*r);
|
||||
|
|
@ -827,9 +836,8 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
pos = get_preferred_edit_position ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
finish_bringing_in_material (*r, input_chan, output_chan, pos, mode, track);
|
||||
|
||||
finish_bringing_in_material (*r, input_chan, output_chan, pos, mode, track, track_names[n]);
|
||||
|
||||
rlen = (*r)->length();
|
||||
|
||||
|
|
@ -856,7 +864,7 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
|
||||
int
|
||||
Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t in_chans, uint32_t out_chans, framepos_t& pos,
|
||||
ImportMode mode, boost::shared_ptr<Track>& existing_track)
|
||||
ImportMode mode, boost::shared_ptr<Track>& existing_track, const string& new_track_name)
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
|
||||
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
|
||||
|
|
@ -885,6 +893,9 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
|
|||
boost::shared_ptr<Region> copy (RegionFactory::create (region, region->properties()));
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (copy, pos);
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
playlist->ripple (pos, copy->length(), copy);
|
||||
|
||||
_session->add_command (new StatefulDiffCommand (playlist));
|
||||
break;
|
||||
}
|
||||
|
|
@ -913,7 +924,11 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
|
|||
existing_track = mt.front();
|
||||
}
|
||||
|
||||
existing_track->set_name (region->name());
|
||||
if (!new_track_name.empty()) {
|
||||
existing_track->set_name (new_track_name);
|
||||
} else {
|
||||
existing_track->set_name (region->name());
|
||||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<Playlist> playlist = existing_track->playlist();
|
||||
|
|
|
|||
|
|
@ -1182,11 +1182,9 @@ Editor::which_track_cursor () const
|
|||
case JOIN_OBJECT_RANGE_NONE:
|
||||
case JOIN_OBJECT_RANGE_OBJECT:
|
||||
cursor = which_grabber_cursor ();
|
||||
cerr << "region use grabber\n";
|
||||
break;
|
||||
case JOIN_OBJECT_RANGE_RANGE:
|
||||
cursor = _cursors->selector;
|
||||
cerr << "region use selector\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1216,8 +1214,6 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
|
|||
{
|
||||
Gdk::Cursor* cursor = 0;
|
||||
|
||||
cerr << "entered new item type " << enum_2_string (type) << endl;
|
||||
|
||||
if (_drags->active()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1329,6 +1325,7 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
|
|||
case CdMarkerBarItem:
|
||||
case VideoBarItem:
|
||||
case TransportMarkerBarItem:
|
||||
case DropZoneItem:
|
||||
cursor = which_grabber_cursor();
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ Editor::track_canvas_scroll (GdkEventScroll* ev)
|
|||
*/
|
||||
|
||||
Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
|
||||
|
||||
|
||||
retry:
|
||||
switch (direction) {
|
||||
case GDK_SCROLL_UP:
|
||||
|
|
@ -1104,6 +1104,9 @@ Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
|
|||
bool
|
||||
Editor::canvas_drop_zone_event (GdkEvent* event)
|
||||
{
|
||||
GdkEventScroll scroll;
|
||||
ArdourCanvas::Duple winpos;
|
||||
|
||||
switch (event->type) {
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (event->button.button == 1) {
|
||||
|
|
@ -1111,6 +1114,24 @@ Editor::canvas_drop_zone_event (GdkEvent* event)
|
|||
selection->clear_tracks ();
|
||||
}
|
||||
break;
|
||||
|
||||
case GDK_SCROLL:
|
||||
/* convert coordinates back into window space so that
|
||||
we can just call canvas_scroll_event().
|
||||
*/
|
||||
winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
|
||||
scroll = event->scroll;
|
||||
scroll.x = winpos.x;
|
||||
scroll.y = winpos.y;
|
||||
return canvas_scroll_event (&scroll, true);
|
||||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
return typed_event (_canvas_drop_zone, event, DropZoneItem);
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
return typed_event (_canvas_drop_zone, event, DropZoneItem);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,3 +88,9 @@ EditorCursor::set_color (ArdourCanvas::Color color)
|
|||
{
|
||||
_track_canvas_item->set_color (color);
|
||||
}
|
||||
|
||||
void
|
||||
EditorCursor::set_sensitive (bool yn)
|
||||
{
|
||||
_track_canvas_item->set_ignore_events (!yn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class EditorCursor {
|
|||
void show ();
|
||||
void hide ();
|
||||
void set_color (ArdourCanvas::Color);
|
||||
void set_sensitive (bool);
|
||||
|
||||
framepos_t current_frame () const {
|
||||
return _current_frame;
|
||||
|
|
|
|||
|
|
@ -595,7 +595,6 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, framepos_t* pending_r
|
|||
}
|
||||
}
|
||||
|
||||
_last_frame_position = *pending_region_position;
|
||||
}
|
||||
|
||||
return dx;
|
||||
|
|
@ -668,6 +667,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
|
|||
/* Work out the change in x */
|
||||
framepos_t pending_region_position;
|
||||
double const x_delta = compute_x_delta (event, &pending_region_position);
|
||||
_last_frame_position = pending_region_position;
|
||||
|
||||
/* Verify change in y */
|
||||
if (!y_movement_allowed (delta_time_axis_view, delta_layer)) {
|
||||
|
|
@ -1281,7 +1281,7 @@ RegionMoveDrag::remove_region_from_playlist (
|
|||
playlist->clear_changes ();
|
||||
}
|
||||
|
||||
playlist->remove_region (region);
|
||||
playlist->remove_region (region); // should be no need to ripple; we better already have rippled the playlist in RegionRippleDrag
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1451,6 +1451,12 @@ RegionInsertDrag::finished (GdkEvent *, bool)
|
|||
_editor->begin_reversible_command (Operations::insert_region);
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (_primary->region (), _last_frame_position);
|
||||
|
||||
// Mixbus doesn't seem to ripple when inserting regions from the list: should we? yes, probably
|
||||
if (Config->get_edit_mode() == Ripple) {
|
||||
playlist->ripple (_last_frame_position, _primary->region()->length(), _primary->region());
|
||||
}
|
||||
|
||||
_editor->session()->add_command (new StatefulDiffCommand (playlist));
|
||||
_editor->commit_reversible_command ();
|
||||
|
||||
|
|
@ -1493,7 +1499,7 @@ RegionSpliceDrag::motion (GdkEvent* event, bool)
|
|||
|
||||
if (!tv || !tv->is_track()) {
|
||||
/* To make sure we hide the verbose canvas cursor when the mouse is
|
||||
not held over and audiotrack.
|
||||
not held over an audio track.
|
||||
*/
|
||||
_editor->verbose_cursor()->hide ();
|
||||
return;
|
||||
|
|
@ -1509,10 +1515,8 @@ RegionSpliceDrag::motion (GdkEvent* event, bool)
|
|||
dir = -1;
|
||||
}
|
||||
|
||||
RegionSelection copy (_editor->selection->regions);
|
||||
|
||||
RegionSelectionByPosition cmp;
|
||||
copy.sort (cmp);
|
||||
RegionSelection copy;
|
||||
_editor->selection->regions.by_position(copy);
|
||||
|
||||
framepos_t const pf = adjusted_current_frame (event);
|
||||
|
||||
|
|
@ -1561,6 +1565,281 @@ RegionSpliceDrag::aborted (bool)
|
|||
/* XXX: TODO */
|
||||
}
|
||||
|
||||
/***
|
||||
* ripple mode...
|
||||
*/
|
||||
|
||||
void
|
||||
RegionRippleDrag::add_all_after_to_views(TimeAxisView *tav, framepos_t where, const RegionSelection &exclude, bool drag_in_progress)
|
||||
{
|
||||
|
||||
boost::shared_ptr<RegionList> rl = tav->playlist()->regions_with_start_within (Evoral::Range<framepos_t>(where, max_framepos));
|
||||
|
||||
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(tav);
|
||||
RegionSelection to_ripple;
|
||||
for (RegionList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
||||
if ((*i)->position() >= where) {
|
||||
to_ripple.push_back (rtv->view()->find_view(*i));
|
||||
}
|
||||
}
|
||||
|
||||
for (RegionSelection::iterator i = to_ripple.begin(); i != to_ripple.end(); ++i) {
|
||||
if (!exclude.contains (*i)) {
|
||||
// the selection has already been added to _views
|
||||
|
||||
if (drag_in_progress) {
|
||||
// do the same things that RegionMotionDrag::motion does when
|
||||
// first_move is true, for the region views that we're adding
|
||||
// to _views this time
|
||||
|
||||
(*i)->drag_start();
|
||||
ArdourCanvas::Item* rvg = (*i)->get_canvas_group();
|
||||
Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0));
|
||||
Duple dmg_canvas_offset = _editor->_drag_motion_group->canvas_origin ();
|
||||
rvg->reparent (_editor->_drag_motion_group);
|
||||
|
||||
// we only need to move in the y direction
|
||||
Duple fudge = rv_canvas_offset - dmg_canvas_offset;
|
||||
fudge.x = 0;
|
||||
rvg->move (fudge);
|
||||
|
||||
}
|
||||
_views.push_back (DraggingView (*i, this, tav));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegionRippleDrag::remove_unselected_from_views(framecnt_t amount, bool move_regions)
|
||||
{
|
||||
|
||||
for (std::list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ) {
|
||||
// we added all the regions after the selection
|
||||
|
||||
std::list<DraggingView>::iterator to_erase = i++;
|
||||
if (!_editor->selection->regions.contains (to_erase->view)) {
|
||||
// restore the non-selected regions to their original playlist & positions,
|
||||
// and then ripple them back by the length of the regions that were dragged away
|
||||
// do the same things as RegionMotionDrag::aborted
|
||||
|
||||
RegionView *rv = to_erase->view;
|
||||
TimeAxisView* tv = &(rv->get_time_axis_view ());
|
||||
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
|
||||
assert (rtv);
|
||||
|
||||
// plonk them back onto their own track
|
||||
rv->get_canvas_group()->reparent(rtv->view()->canvas_item());
|
||||
rv->get_canvas_group()->set_y_position (0);
|
||||
rv->drag_end ();
|
||||
|
||||
if (move_regions) {
|
||||
// move the underlying region to match the view
|
||||
rv->region()->set_position (rv->region()->position() + amount);
|
||||
} else {
|
||||
// restore the view to match the underlying region's original position
|
||||
rv->move(-amount, 0); // second parameter is y delta - seems 0 is OK
|
||||
}
|
||||
|
||||
rv->set_height (rtv->view()->child_height ());
|
||||
_views.erase (to_erase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RegionRippleDrag::y_movement_allowed (int delta_track, double delta_layer) const
|
||||
{
|
||||
if (RegionMotionDrag::y_movement_allowed (delta_track, delta_layer)) {
|
||||
if (delta_track) {
|
||||
return allow_moves_across_tracks;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RegionRippleDrag::RegionRippleDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
|
||||
: RegionMoveDrag (e, i, p, v, false, false)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::Drags, "New RegionRippleDrag\n");
|
||||
// compute length of selection
|
||||
RegionSelection selected_regions = _editor->selection->regions;
|
||||
selection_length = selected_regions.end_frame() - selected_regions.start();
|
||||
|
||||
// we'll only allow dragging to another track in ripple mode if all the regions
|
||||
// being dragged start off on the same track
|
||||
allow_moves_across_tracks = (selected_regions.playlists().size() == 1);
|
||||
prev_tav = NULL;
|
||||
prev_amount = 0;
|
||||
exclude = new RegionList;
|
||||
for (RegionSelection::iterator i =selected_regions.begin(); i != selected_regions.end(); ++i) {
|
||||
exclude->push_back((*i)->region());
|
||||
}
|
||||
|
||||
// also add regions before start of selection to exclude, to be consistent with how Mixbus does ripple
|
||||
RegionSelection copy;
|
||||
selected_regions.by_position(copy); // get selected regions sorted by position into copy
|
||||
|
||||
std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists = copy.playlists();
|
||||
std::set<boost::shared_ptr<ARDOUR::Playlist> >::const_iterator pi;
|
||||
|
||||
for (pi = playlists.begin(); pi != playlists.end(); ++pi) {
|
||||
// find ripple start point on each applicable playlist
|
||||
RegionView *first_selected_on_this_track = NULL;
|
||||
for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
|
||||
if ((*i)->region()->playlist() == (*pi)) {
|
||||
// region is on this playlist - it's the first, because they're sorted
|
||||
first_selected_on_this_track = *i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert (first_selected_on_this_track); // we should always find the region in one of the playlists...
|
||||
add_all_after_to_views (
|
||||
&first_selected_on_this_track->get_time_axis_view(),
|
||||
first_selected_on_this_track->region()->position(),
|
||||
selected_regions, false);
|
||||
}
|
||||
|
||||
if (allow_moves_across_tracks) {
|
||||
orig_tav = &(*selected_regions.begin())->get_time_axis_view();
|
||||
} else {
|
||||
orig_tav = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
RegionRippleDrag::motion (GdkEvent* event, bool first_move)
|
||||
{
|
||||
/* Which trackview is this ? */
|
||||
|
||||
pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
|
||||
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
|
||||
|
||||
/* The region motion is only processed if the pointer is over
|
||||
an audio track.
|
||||
*/
|
||||
|
||||
if (!tv || !tv->is_track()) {
|
||||
/* To make sure we hide the verbose canvas cursor when the mouse is
|
||||
not held over an audiotrack.
|
||||
*/
|
||||
_editor->verbose_cursor()->hide ();
|
||||
return;
|
||||
}
|
||||
|
||||
framepos_t where = adjusted_current_frame (event);
|
||||
assert (where >= 0);
|
||||
framepos_t after;
|
||||
double delta = compute_x_delta (event, &after);
|
||||
|
||||
framecnt_t amount = _editor->pixel_to_sample (delta);
|
||||
|
||||
if (allow_moves_across_tracks) {
|
||||
// all the originally selected regions were on the same track
|
||||
|
||||
framecnt_t adjust = 0;
|
||||
if (prev_tav && tv != prev_tav) {
|
||||
// dragged onto a different track
|
||||
// remove the unselected regions from _views, restore them to their original positions
|
||||
// and add the regions after the drop point on the new playlist to _views instead.
|
||||
// undo the effect of rippling the previous playlist, and include the effect of removing
|
||||
// the dragged region(s) from this track
|
||||
|
||||
remove_unselected_from_views (prev_amount, false);
|
||||
// ripple previous playlist according to the regions that have been removed onto the new playlist
|
||||
prev_tav->playlist()->ripple(prev_position, -selection_length, exclude);
|
||||
prev_amount = 0;
|
||||
|
||||
// move just the selected regions
|
||||
RegionMoveDrag::motion(event, first_move);
|
||||
|
||||
// ensure that the ripple operation on the new playlist inserts selection_length time
|
||||
adjust = selection_length;
|
||||
// ripple the new current playlist
|
||||
tv->playlist()->ripple (where, amount+adjust, exclude);
|
||||
|
||||
// add regions after point where drag entered this track to subsequent ripples
|
||||
add_all_after_to_views (tv, where, _editor->selection->regions, true);
|
||||
|
||||
} else {
|
||||
// motion on same track
|
||||
RegionMoveDrag::motion(event, first_move);
|
||||
}
|
||||
prev_tav = tv;
|
||||
|
||||
// remember what we've done to this playlist so we can undo it if the selection is dragged to another track
|
||||
prev_position = where;
|
||||
} else {
|
||||
// selection encompasses multiple tracks - just drag
|
||||
// cross-track drags are forbidden
|
||||
RegionMoveDrag::motion(event, first_move);
|
||||
}
|
||||
|
||||
if (!_x_constrained) {
|
||||
prev_amount += amount;
|
||||
}
|
||||
|
||||
_last_frame_position = after;
|
||||
}
|
||||
|
||||
void
|
||||
RegionRippleDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
{
|
||||
if (!movement_occurred) {
|
||||
return;
|
||||
}
|
||||
|
||||
_editor->begin_reversible_command(_("Ripple drag"));
|
||||
|
||||
// remove the regions being rippled from the dragging view, updating them to
|
||||
// their new positions
|
||||
remove_unselected_from_views (prev_amount, true);
|
||||
|
||||
if (allow_moves_across_tracks) {
|
||||
if (orig_tav) {
|
||||
// if regions were dragged across tracks, we've rippled any later
|
||||
// regions on the track the regions were dragged off, so we need
|
||||
// to add the original track to the undo record
|
||||
orig_tav->playlist()->clear_changes();
|
||||
vector<Command*> cmds;
|
||||
orig_tav->playlist()->rdiff (cmds);
|
||||
_editor->session()->add_commands (cmds);
|
||||
}
|
||||
if (prev_tav && prev_tav != orig_tav) {
|
||||
prev_tav->playlist()->clear_changes();
|
||||
vector<Command*> cmds;
|
||||
prev_tav->playlist()->rdiff (cmds);
|
||||
_editor->session()->add_commands (cmds);
|
||||
}
|
||||
} else {
|
||||
// selection spanned multiple tracks - all will need adding to undo record
|
||||
|
||||
std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists = _editor->selection->regions.playlists();
|
||||
std::set<boost::shared_ptr<ARDOUR::Playlist> >::const_iterator pi;
|
||||
|
||||
for (pi = playlists.begin(); pi != playlists.end(); ++pi) {
|
||||
(*pi)->clear_changes();
|
||||
vector<Command*> cmds;
|
||||
(*pi)->rdiff (cmds);
|
||||
_editor->session()->add_commands (cmds);
|
||||
}
|
||||
}
|
||||
|
||||
// other modified playlists are added to undo by RegionMoveDrag::finished()
|
||||
RegionMoveDrag::finished (event, movement_occurred);
|
||||
_editor->commit_reversible_command();
|
||||
}
|
||||
|
||||
void
|
||||
RegionRippleDrag::aborted (bool movement_occurred)
|
||||
{
|
||||
RegionMoveDrag::aborted (movement_occurred);
|
||||
_views.clear ();
|
||||
}
|
||||
|
||||
|
||||
RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
|
||||
: Drag (e, i),
|
||||
_view (dynamic_cast<MidiTimeAxisView*> (v))
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ public:
|
|||
protected:
|
||||
|
||||
double compute_x_delta (GdkEvent const *, ARDOUR::framepos_t *);
|
||||
bool y_movement_allowed (int, double) const;
|
||||
virtual bool y_movement_allowed (int, double) const;
|
||||
|
||||
bool _brushing;
|
||||
ARDOUR::framepos_t _last_frame_position; ///< last position of the thing being dragged
|
||||
|
|
@ -349,9 +349,11 @@ public:
|
|||
|
||||
void setup_pointer_frame_offset ();
|
||||
|
||||
private:
|
||||
protected:
|
||||
typedef std::set<boost::shared_ptr<ARDOUR::Playlist> > PlaylistSet;
|
||||
void add_stateful_diff_commands_for_playlists (PlaylistSet const &);
|
||||
|
||||
private:
|
||||
void finished_no_copy (
|
||||
bool const,
|
||||
bool const,
|
||||
|
|
@ -378,7 +380,6 @@ private:
|
|||
PlaylistSet& modified_playlists
|
||||
);
|
||||
|
||||
void add_stateful_diff_commands_for_playlists (PlaylistSet const &);
|
||||
|
||||
void collect_new_region_view (RegionView *);
|
||||
RouteTimeAxisView* create_destination_time_axis (boost::shared_ptr<ARDOUR::Region>, TimeAxisView* original);
|
||||
|
|
@ -412,6 +413,33 @@ public:
|
|||
void aborted (bool);
|
||||
};
|
||||
|
||||
/** Region drag in ripple mode */
|
||||
|
||||
class RegionRippleDrag : public RegionMoveDrag
|
||||
{
|
||||
public:
|
||||
RegionRippleDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
|
||||
~RegionRippleDrag () { delete exclude; }
|
||||
|
||||
void motion (GdkEvent *, bool);
|
||||
void finished (GdkEvent *, bool);
|
||||
void aborted (bool);
|
||||
protected:
|
||||
bool y_movement_allowed (int delta_track, double delta_layer) const;
|
||||
|
||||
private:
|
||||
TimeAxisView *prev_tav; // where regions were most recently dragged from
|
||||
TimeAxisView *orig_tav; // where drag started
|
||||
framecnt_t prev_amount;
|
||||
framepos_t prev_position;
|
||||
framecnt_t selection_length;
|
||||
bool allow_moves_across_tracks; // only if all selected regions are on one track
|
||||
ARDOUR::RegionList *exclude;
|
||||
void add_all_after_to_views (TimeAxisView *tav, framepos_t where, const RegionSelection &exclude, bool drag_in_progress);
|
||||
void remove_unselected_from_views (framecnt_t amount, bool move_regions);
|
||||
|
||||
};
|
||||
|
||||
/** Drags to create regions */
|
||||
class RegionCreateDrag : public Drag
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "canvas/utils.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "editor.h"
|
||||
#include "editor_group_tabs.h"
|
||||
#include "editor_route_groups.h"
|
||||
|
|
@ -94,9 +95,7 @@ EditorGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const
|
|||
if (tab.group && tab.group->is_active()) {
|
||||
ArdourCanvas::color_to_rgba (tab.color, r, g, b, a);
|
||||
} else {
|
||||
r = 0.0;
|
||||
g = 0.0;
|
||||
b = 0.0;
|
||||
ArdourCanvas::color_to_rgba (ARDOUR_UI::config()->get_canvasvar_InactiveGroupTab(), r, g, b, a);
|
||||
}
|
||||
|
||||
a = 1.0;
|
||||
|
|
@ -115,7 +114,7 @@ EditorGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const
|
|||
cairo_text_extents_t ext;
|
||||
cairo_text_extents (cr, tab.group->name().c_str(), &ext);
|
||||
|
||||
ArdourCanvas::Color c = contrasting_text_color (ArdourCanvas::rgba_to_color (r, g, b, a));
|
||||
ArdourCanvas::Color c = ArdourCanvas::contrasting_text_color (ArdourCanvas::rgba_to_color (r, g, b, a));
|
||||
ArdourCanvas::color_to_rgba (c, r, g, b, a);
|
||||
|
||||
cairo_set_source_rgb (cr, r, g, b);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ enum ItemType {
|
|||
MinsecRulerItem,
|
||||
BBTRulerItem,
|
||||
SamplesRulerItem,
|
||||
|
||||
DropZoneItem,
|
||||
|
||||
/* don't remove this */
|
||||
|
||||
NoItem
|
||||
|
|
|
|||
|
|
@ -37,30 +37,35 @@
|
|||
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Editing;
|
||||
|
||||
void
|
||||
Editor::keyboard_selection_finish (bool add)
|
||||
{
|
||||
if (_session && have_pending_keyboard_selection) {
|
||||
if (_session) {
|
||||
|
||||
framepos_t start = selection->time.start();
|
||||
framepos_t end;
|
||||
bool ignored;
|
||||
|
||||
if (_session->transport_rolling()) {
|
||||
|
||||
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
|
||||
end = _session->audible_frame();
|
||||
} else {
|
||||
if (!mouse_frame (end, ignored)) {
|
||||
return;
|
||||
}
|
||||
end = get_preferred_edit_position();
|
||||
}
|
||||
|
||||
if (add) {
|
||||
selection->add (pending_keyboard_selection_start, end);
|
||||
} else {
|
||||
selection->set (pending_keyboard_selection_start, end);
|
||||
}
|
||||
//snap the selection start/end
|
||||
snap_to(start);
|
||||
|
||||
//if no tracks are selected and we're working from the keyboard, enable all tracks (_something_ has to be selected for any range selection)
|
||||
if ( (_edit_point == EditAtPlayhead) && selection->tracks.empty() )
|
||||
select_all_tracks();
|
||||
|
||||
selection->set (start, end);
|
||||
|
||||
//if session is playing a range, cancel that
|
||||
if (_session->get_play_range())
|
||||
_session->request_cancel_play_range();
|
||||
|
||||
have_pending_keyboard_selection = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,19 +73,33 @@ void
|
|||
Editor::keyboard_selection_begin ()
|
||||
{
|
||||
if (_session) {
|
||||
if (_session->transport_rolling()) {
|
||||
pending_keyboard_selection_start = _session->audible_frame();
|
||||
have_pending_keyboard_selection = true;
|
||||
|
||||
framepos_t start;
|
||||
framepos_t end = selection->time.end_frame(); //0 if no current selection
|
||||
|
||||
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
|
||||
start = _session->audible_frame();
|
||||
} else {
|
||||
bool ignored;
|
||||
framepos_t where; // XXX fix me
|
||||
|
||||
if (mouse_frame (where, ignored)) {
|
||||
pending_keyboard_selection_start = where;
|
||||
have_pending_keyboard_selection = true;
|
||||
}
|
||||
|
||||
start = get_preferred_edit_position();
|
||||
}
|
||||
|
||||
//snap the selection start/end
|
||||
snap_to(start);
|
||||
|
||||
//if there's not already a sensible selection endpoint, go "forever"
|
||||
if ( start > end ) {
|
||||
end = max_framepos;
|
||||
}
|
||||
|
||||
//if no tracks are selected and we're working from the keyboard, enable all tracks (_something_ has to be selected for any range selection)
|
||||
if ( selection->tracks.empty() )
|
||||
select_all_tracks();
|
||||
|
||||
selection->set (start, end);
|
||||
|
||||
//if session is playing a range, cancel that
|
||||
if (_session->get_play_range())
|
||||
_session->request_cancel_play_range();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -490,7 +490,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
|
|||
to cut notes or regions.
|
||||
*/
|
||||
|
||||
MouseMode eff_mouse_mode = mouse_mode;
|
||||
MouseMode eff_mouse_mode = effective_mouse_mode ();
|
||||
|
||||
if (get_smart_mode() && eff_mouse_mode == MouseRange && event->button.button == 3 && item_type == RegionItem) {
|
||||
/* context clicks are always about object properties, even if
|
||||
|
|
@ -499,6 +499,20 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
|
|||
eff_mouse_mode = MouseObject;
|
||||
}
|
||||
|
||||
/* special case: allow drag of region fade in/out in object mode with join object/range enabled */
|
||||
if (get_smart_mode()) {
|
||||
switch (item_type) {
|
||||
case FadeInHandleItem:
|
||||
case FadeInTrimHandleItem:
|
||||
case FadeOutHandleItem:
|
||||
case FadeOutTrimHandleItem:
|
||||
eff_mouse_mode = MouseObject;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (((mouse_mode != MouseObject) &&
|
||||
(mouse_mode != MouseAudition || item_type != RegionItem) &&
|
||||
(mouse_mode != MouseTimeFX || item_type != RegionItem) &&
|
||||
|
|
@ -551,13 +565,6 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
|
|||
case RegionViewName:
|
||||
case LeftFrameHandle:
|
||||
case RightFrameHandle:
|
||||
if (eff_mouse_mode != MouseRange) {
|
||||
set_selected_regionview_from_click (press, op);
|
||||
} else if (event->type == GDK_BUTTON_PRESS) {
|
||||
set_selected_track_as_side_effect (op);
|
||||
}
|
||||
break;
|
||||
|
||||
case FadeInHandleItem:
|
||||
case FadeInTrimHandleItem:
|
||||
case FadeInItem:
|
||||
|
|
@ -566,8 +573,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
|
|||
case FadeOutItem:
|
||||
case StartCrossFadeItem:
|
||||
case EndCrossFadeItem:
|
||||
if (eff_mouse_mode != MouseRange) {
|
||||
cerr << "Should be setting selected regionview\n";
|
||||
if (get_smart_mode() || eff_mouse_mode != MouseRange) {
|
||||
set_selected_regionview_from_click (press, op);
|
||||
} else if (event->type == GDK_BUTTON_PRESS) {
|
||||
set_selected_track_as_side_effect (op);
|
||||
|
|
@ -717,8 +723,17 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
Editing::MouseMode eff = effective_mouse_mode ();
|
||||
|
||||
/* special case: allow drag of region fade in/out in object mode with join object/range enabled */
|
||||
if (item_type == FadeInHandleItem || item_type == FadeOutHandleItem) {
|
||||
eff = MouseObject;
|
||||
if (get_smart_mode()) {
|
||||
switch (item_type) {
|
||||
case FadeInHandleItem:
|
||||
case FadeInTrimHandleItem:
|
||||
case FadeOutHandleItem:
|
||||
case FadeOutTrimHandleItem:
|
||||
eff = MouseObject;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* there is no Range mode when in internal edit mode */
|
||||
|
|
@ -1432,6 +1447,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
case FadeInHandleItem:
|
||||
case FadeInTrimHandleItem:
|
||||
case StartCrossFadeItem:
|
||||
case LeftFrameHandle:
|
||||
popup_xfade_in_context_menu (1, event->button.time, item, item_type);
|
||||
break;
|
||||
|
||||
|
|
@ -1439,6 +1455,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
case FadeOutHandleItem:
|
||||
case FadeOutTrimHandleItem:
|
||||
case EndCrossFadeItem:
|
||||
case RightFrameHandle:
|
||||
popup_xfade_out_context_menu (1, event->button.time, item, item_type);
|
||||
break;
|
||||
|
||||
|
|
@ -1448,8 +1465,6 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
|
||||
case RegionItem:
|
||||
case RegionViewNameHighlight:
|
||||
case LeftFrameHandle:
|
||||
case RightFrameHandle:
|
||||
case RegionViewName:
|
||||
popup_track_context_menu (1, event->button.time, item_type, false);
|
||||
break;
|
||||
|
|
@ -2385,10 +2400,17 @@ Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region
|
|||
return;
|
||||
}
|
||||
|
||||
if (Config->get_edit_mode() == Splice) {
|
||||
_drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer()));
|
||||
} else {
|
||||
_drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, false));
|
||||
switch (Config->get_edit_mode()) {
|
||||
case Splice:
|
||||
_drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer()));
|
||||
break;
|
||||
case Ripple:
|
||||
_drags->add (new RegionRippleDrag (this, item, region_view, selection->regions.by_layer()));
|
||||
break;
|
||||
default:
|
||||
_drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, false));
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2413,7 +2435,7 @@ Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView*
|
|||
return;
|
||||
}
|
||||
|
||||
if (Config->get_edit_mode() == Splice) {
|
||||
if (Config->get_edit_mode() == Splice || Config->get_edit_mode() == Ripple) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2557,7 +2579,6 @@ Editor::update_join_object_range_location (double y)
|
|||
_join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
|
||||
}
|
||||
|
||||
|
||||
if (entered_regionview) {
|
||||
|
||||
ArdourCanvas::Duple const item_space = entered_regionview->get_canvas_group()->canvas_to_item (ArdourCanvas::Duple (0, y));
|
||||
|
|
@ -2574,17 +2595,32 @@ Editor::update_join_object_range_location (double y)
|
|||
RouteTimeAxisView* entered_route_view = dynamic_cast<RouteTimeAxisView*> (entered_track);
|
||||
|
||||
if (entered_route_view) {
|
||||
/* track/bus ... but not in a region ... use range mode */
|
||||
_join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
|
||||
if (_join_object_range_state != old) {
|
||||
set_canvas_cursor (which_track_cursor ());
|
||||
|
||||
double cx = 0;
|
||||
double cy = y;
|
||||
|
||||
entered_route_view->canvas_display()->canvas_to_item (cx, cy);
|
||||
|
||||
double track_height = entered_route_view->view()->child_height();
|
||||
if (Config->get_show_name_highlight()) {
|
||||
track_height -= TimeAxisViewItem::NAME_HIGHLIGHT_SIZE;
|
||||
}
|
||||
double const c = cy / track_height;
|
||||
|
||||
|
||||
if (c <= 0.5) {
|
||||
_join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
|
||||
} else {
|
||||
_join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Other kinds of tracks use object mode */
|
||||
_join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
|
||||
if (_join_object_range_state != old) {
|
||||
set_canvas_cursor (which_track_cursor ());
|
||||
}
|
||||
}
|
||||
|
||||
if (_join_object_range_state != old) {
|
||||
set_canvas_cursor (which_track_cursor ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1448,38 +1448,6 @@ Editor::tav_zoom_smooth (bool coarser, bool force_all)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Editor::clamp_samples_per_pixel (framecnt_t& fpp) const
|
||||
{
|
||||
bool clamped = false;
|
||||
|
||||
if (fpp < 1) {
|
||||
fpp = 1;
|
||||
clamped = true;
|
||||
}
|
||||
|
||||
framecnt_t sr;
|
||||
|
||||
if (_session) {
|
||||
sr = _session->frame_rate ();
|
||||
} else {
|
||||
sr = 48000;
|
||||
}
|
||||
|
||||
const framecnt_t three_days = 3 * 24 * 60 * 60 * sr;
|
||||
const framecnt_t lots_of_pixels = 4000;
|
||||
|
||||
/* if the zoom level is greater than what you'd get trying to display 3
|
||||
* days of audio on a really big screen, scale it down.
|
||||
*/
|
||||
|
||||
if (fpp * lots_of_pixels > three_days) {
|
||||
fpp = three_days / _track_canvas->width();
|
||||
clamped = true;
|
||||
}
|
||||
|
||||
return clamped;
|
||||
}
|
||||
|
||||
void
|
||||
Editor::temporal_zoom_step (bool coarser)
|
||||
|
|
@ -1516,7 +1484,6 @@ Editor::temporal_zoom (framecnt_t fpp)
|
|||
framecnt_t nfpp;
|
||||
double l;
|
||||
|
||||
clamp_samples_per_pixel (fpp);
|
||||
if (fpp == samples_per_pixel) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1806,8 +1773,7 @@ Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
|
|||
new_spp = samples_per_pixel - (samples_per_pixel/2);
|
||||
} else {
|
||||
/* could bail out here since we cannot zoom any finer,
|
||||
but leave that to the clamp_samples_per_pixel() and
|
||||
equality test below
|
||||
but leave that to the equality test below
|
||||
*/
|
||||
new_spp = samples_per_pixel;
|
||||
}
|
||||
|
|
@ -1815,8 +1781,6 @@ Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
|
|||
range_before -= range_before/2;
|
||||
}
|
||||
|
||||
clamp_samples_per_pixel (new_spp);
|
||||
|
||||
if (new_spp == samples_per_pixel) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2110,6 +2074,8 @@ Editor::unhide_ranges ()
|
|||
}
|
||||
}
|
||||
|
||||
/* INSERT/REPLACE */
|
||||
|
||||
void
|
||||
Editor::insert_region_list_selection (float times)
|
||||
{
|
||||
|
|
@ -2142,6 +2108,9 @@ Editor::insert_region_list_selection (float times)
|
|||
begin_reversible_command (_("insert region"));
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
|
||||
|
||||
_session->add_command(new StatefulDiffCommand (playlist));
|
||||
commit_reversible_command ();
|
||||
}
|
||||
|
|
@ -3726,7 +3695,7 @@ Editor::can_cut_copy () const
|
|||
|
||||
|
||||
/** Cut, copy or clear selected regions, automation points or a time range.
|
||||
* @param op Operation (Cut, Copy or Clear)
|
||||
* @param op Operation (Delete, Cut, Copy or Clear)
|
||||
*/
|
||||
void
|
||||
Editor::cut_copy (CutCopyOp op)
|
||||
|
|
@ -3762,7 +3731,7 @@ Editor::cut_copy (CutCopyOp op)
|
|||
}
|
||||
}
|
||||
|
||||
if ( op != Clear ) //"Delete" doesn't change copy/paste buf
|
||||
if ( op != Delete ) //"Delete" doesn't change copy/paste buf
|
||||
cut_buffer->clear ();
|
||||
|
||||
if (entered_marker) {
|
||||
|
|
@ -4002,10 +3971,11 @@ Editor::remove_clicked_region ()
|
|||
|
||||
boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
|
||||
|
||||
begin_reversible_command (_("remove region"));
|
||||
playlist->clear_changes ();
|
||||
playlist->clear_owned_changes ();
|
||||
playlist->remove_region (clicked_regionview->region());
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
|
||||
|
||||
/* We might have removed regions, which alters other regions' layering_index,
|
||||
so we need to do a recursive diff here.
|
||||
|
|
@ -4068,6 +4038,9 @@ Editor::remove_selected_regions ()
|
|||
playlist->clear_owned_changes ();
|
||||
playlist->freeze ();
|
||||
playlist->remove_region (*rl);
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
|
||||
|
||||
}
|
||||
|
||||
vector<boost::shared_ptr<Playlist> >::iterator pl;
|
||||
|
|
@ -4197,12 +4170,16 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
|
|||
switch (op) {
|
||||
case Delete:
|
||||
pl->remove_region (r);
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
|
||||
break;
|
||||
|
||||
case Cut:
|
||||
_xx = RegionFactory::create (r);
|
||||
npl->add_region (_xx, r->position() - first_position);
|
||||
pl->remove_region (r);
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
|
||||
break;
|
||||
|
||||
case Copy:
|
||||
|
|
@ -4211,7 +4188,9 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
|
|||
break;
|
||||
|
||||
case Clear:
|
||||
pl->remove_region (r);
|
||||
pl->remove_region (r);
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1378,17 +1378,7 @@ Editor::select_all (Selection::Operation op)
|
|||
{
|
||||
list<Selectable *> touched;
|
||||
|
||||
TrackViewList ts;
|
||||
|
||||
if (selection->tracks.empty()) {
|
||||
if (entered_track) {
|
||||
ts.push_back (entered_track);
|
||||
} else {
|
||||
ts = track_views;
|
||||
}
|
||||
} else {
|
||||
ts = selection->tracks;
|
||||
}
|
||||
TrackViewList ts = track_views;
|
||||
|
||||
if (_internal_editing) {
|
||||
|
||||
|
|
@ -1418,8 +1408,10 @@ Editor::select_all (Selection::Operation op)
|
|||
continue;
|
||||
}
|
||||
(*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
|
||||
selection->add (*iter);
|
||||
}
|
||||
|
||||
|
||||
begin_reversible_command (_("select all"));
|
||||
switch (op) {
|
||||
case Selection::Add:
|
||||
|
|
@ -1842,98 +1834,102 @@ Editor::select_range_between ()
|
|||
bool
|
||||
Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
|
||||
{
|
||||
framepos_t m;
|
||||
bool ignored;
|
||||
// framepos_t m;
|
||||
// bool ignored;
|
||||
|
||||
/* if an explicit range exists, use it */
|
||||
|
||||
if (!selection->time.empty()) {
|
||||
if ( (mouse_mode == MouseRange || get_smart_mode() ) && !selection->time.empty()) {
|
||||
/* we know that these are ordered */
|
||||
start = selection->time.start();
|
||||
end = selection->time.end_frame();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mouse_frame (m, ignored)) {
|
||||
/* mouse is not in a canvas, try playhead+selected marker.
|
||||
this is probably most true when using menus.
|
||||
*/
|
||||
|
||||
if (selection->markers.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
start = selection->markers.front()->position();
|
||||
end = _session->audible_frame();
|
||||
|
||||
} else {
|
||||
|
||||
switch (_edit_point) {
|
||||
case EditAtPlayhead:
|
||||
if (selection->markers.empty()) {
|
||||
/* use mouse + playhead */
|
||||
start = m;
|
||||
end = _session->audible_frame();
|
||||
} else {
|
||||
/* use playhead + selected marker */
|
||||
start = _session->audible_frame();
|
||||
end = selection->markers.front()->position();
|
||||
}
|
||||
break;
|
||||
|
||||
case EditAtMouse:
|
||||
/* use mouse + selected marker */
|
||||
if (selection->markers.empty()) {
|
||||
start = m;
|
||||
end = _session->audible_frame();
|
||||
} else {
|
||||
start = selection->markers.front()->position();
|
||||
end = m;
|
||||
}
|
||||
break;
|
||||
|
||||
case EditAtSelectedMarker:
|
||||
/* use mouse + selected marker */
|
||||
if (selection->markers.empty()) {
|
||||
|
||||
MessageDialog win (_("No edit range defined"),
|
||||
false,
|
||||
MESSAGE_INFO,
|
||||
BUTTONS_OK);
|
||||
|
||||
win.set_secondary_text (
|
||||
_("the edit point is Selected Marker\nbut there is no selected marker."));
|
||||
|
||||
|
||||
win.set_default_response (RESPONSE_CLOSE);
|
||||
win.set_position (Gtk::WIN_POS_MOUSE);
|
||||
win.show_all();
|
||||
|
||||
win.run ();
|
||||
|
||||
return false; // NO RANGE
|
||||
}
|
||||
start = selection->markers.front()->position();
|
||||
end = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (start == end) {
|
||||
start = 0;
|
||||
end = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if (!mouse_frame (m, ignored)) {
|
||||
// /* mouse is not in a canvas, try playhead+selected marker.
|
||||
// this is probably most true when using menus.
|
||||
// */
|
||||
//
|
||||
// if (selection->markers.empty()) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if (start > end) {
|
||||
swap (start, end);
|
||||
}
|
||||
// start = selection->markers.front()->position();
|
||||
// end = _session->audible_frame();
|
||||
|
||||
// } else {
|
||||
|
||||
// switch (_edit_point) {
|
||||
// case EditAtPlayhead:
|
||||
// if (selection->markers.empty()) {
|
||||
// /* use mouse + playhead */
|
||||
// start = m;
|
||||
// end = _session->audible_frame();
|
||||
// } else {
|
||||
// /* use playhead + selected marker */
|
||||
// start = _session->audible_frame();
|
||||
// end = selection->markers.front()->position();
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case EditAtMouse:
|
||||
// /* use mouse + selected marker */
|
||||
// if (selection->markers.empty()) {
|
||||
// start = m;
|
||||
// end = _session->audible_frame();
|
||||
// } else {
|
||||
// start = selection->markers.front()->position();
|
||||
// end = m;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case EditAtSelectedMarker:
|
||||
// /* use mouse + selected marker */
|
||||
// if (selection->markers.empty()) {
|
||||
|
||||
// MessageDialog win (_("No edit range defined"),
|
||||
// false,
|
||||
// MESSAGE_INFO,
|
||||
// BUTTONS_OK);
|
||||
|
||||
// win.set_secondary_text (
|
||||
// _("the edit point is Selected Marker\nbut there is no selected marker."));
|
||||
|
||||
|
||||
// win.set_default_response (RESPONSE_CLOSE);
|
||||
// win.set_position (Gtk::WIN_POS_MOUSE);
|
||||
// win.show_all();
|
||||
|
||||
// win.run ();
|
||||
|
||||
// return false; // NO RANGE
|
||||
// }
|
||||
// start = selection->markers.front()->position();
|
||||
// end = m;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (start == end) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if (start > end) {
|
||||
// swap (start, end);
|
||||
// }
|
||||
|
||||
/* turn range into one delimited by start...end,
|
||||
not start...end-1
|
||||
*/
|
||||
|
||||
end++;
|
||||
// end++;
|
||||
|
||||
return true;
|
||||
// return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -611,7 +611,8 @@ ExportVideoDialog::encode_pass (int pass)
|
|||
ffs.clear();
|
||||
|
||||
if (fps_checkbox.get_active()) {
|
||||
ffs["-r"] = fps_combo.get_active_text();
|
||||
ffs["-r"] = fps_combo.get_active_text();
|
||||
transcoder->set_fps(atof(fps_combo.get_active_text()));
|
||||
}
|
||||
|
||||
if (scale_checkbox.get_active()) {
|
||||
|
|
@ -731,11 +732,7 @@ ExportVideoDialog::encode_pass (int pass)
|
|||
|
||||
std::ostringstream osstream; osstream << duration_s;
|
||||
ffs["-t"] = osstream.str();
|
||||
if (fps_checkbox.get_active()) {
|
||||
transcoder->set_duration(duration_s * atof(fps_combo.get_active_text()));
|
||||
} else {
|
||||
transcoder->set_duration(duration_s * transcoder->get_fps());
|
||||
}
|
||||
transcoder->set_duration(duration_s * transcoder->get_fps());
|
||||
|
||||
if (insnd_combo.get_active_row_number() == 0 || insnd_combo.get_active_row_number() == 2) {
|
||||
framepos_t start, snend;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "gui_thread.h"
|
||||
#include "route_group_dialog.h"
|
||||
#include "global_signals.h"
|
||||
#include "group_tabs.h"
|
||||
#include "keyboard.h"
|
||||
#include "i18n.h"
|
||||
|
|
@ -45,6 +46,7 @@ GroupTabs::GroupTabs ()
|
|||
, _dragging_new_tab (0)
|
||||
{
|
||||
add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
|
||||
ColorsChanged.connect (sigc::mem_fun (*this, &GroupTabs::queue_draw));
|
||||
}
|
||||
|
||||
GroupTabs::~GroupTabs ()
|
||||
|
|
|
|||
|
|
@ -171,6 +171,11 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
|||
create_automation_child (GainAutomation, false);
|
||||
}
|
||||
|
||||
/* if set_state above didn't create a mute automation child, we need to make one */
|
||||
if (automation_child (MuteAutomation) == 0) {
|
||||
create_automation_child (MuteAutomation, false);
|
||||
}
|
||||
|
||||
if (_route->panner_shell()) {
|
||||
_route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
|
||||
}
|
||||
|
|
@ -1265,6 +1270,10 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
|
|||
create_gain_automation_child (param, show);
|
||||
break;
|
||||
|
||||
case MuteAutomation:
|
||||
create_mute_automation_child (param, show);
|
||||
break;
|
||||
|
||||
case PluginAutomation:
|
||||
/* handled elsewhere */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "canvas/utils.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "mixer_group_tabs.h"
|
||||
#include "mixer_strip.h"
|
||||
#include "mixer_ui.h"
|
||||
|
|
@ -102,9 +103,7 @@ MixerGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const
|
|||
if (tab.group && tab.group->is_active()) {
|
||||
ArdourCanvas::color_to_rgba (tab.color, r, g, b, a);
|
||||
} else {
|
||||
r = 0.0;
|
||||
g = 0.0;
|
||||
b = 0.0;
|
||||
ArdourCanvas::color_to_rgba (ARDOUR_UI::config()->get_canvasvar_InactiveGroupTab(), r, g, b, a);
|
||||
}
|
||||
|
||||
a = 1.0;
|
||||
|
|
@ -122,7 +121,7 @@ MixerGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const
|
|||
cairo_text_extents_t ext;
|
||||
cairo_text_extents (cr, tab.group->name().c_str(), &ext);
|
||||
|
||||
ArdourCanvas::Color c = contrasting_text_color (ArdourCanvas::rgba_to_color (r, g, b, a));
|
||||
ArdourCanvas::Color c = ArdourCanvas::contrasting_text_color (ArdourCanvas::rgba_to_color (r, g, b, a));
|
||||
ArdourCanvas::color_to_rgba (c, r, g, b, a);
|
||||
|
||||
cairo_set_source_rgb (cr, r, g, b);
|
||||
|
|
|
|||
|
|
@ -275,10 +275,10 @@ This mode provides many different operations on both regions and control points,
|
|||
@rop|Region/nudge-forward|KP_Add|nudge forward
|
||||
@-group|Editor/nudge-next-forward|<@PRIMARY@>KP_Add|some text
|
||||
|
||||
@-group|Editor/start-range|<@PRIMARY@>KP_Down|some text
|
||||
|
||||
@-group|Editor/finish-range|<@PRIMARY@>KP_Up|some text
|
||||
@-group|Editor/finish-add-range|<@TERTIARY@><@PRIMARY@>KP_Up|some text
|
||||
@-group|Editor/start-range|comma|some text
|
||||
@-group|Editor/finish-range|period|some text
|
||||
@-group|Editor/alt-start-range|<@PRIMARY@>KP_Down|some text
|
||||
@-group|Editor/alt-finish-range|<@PRIMARY@>KP_Up|some text
|
||||
|
||||
@markers|Editor/add-location-from-playhead|KP_Enter|add mark at playhead
|
||||
@wvis|Transport/focus-on-clock|KP_Divide|focus on main clock
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ FaderOption::FaderOption (string const & i, string const & n, sigc::slot<gain_t>
|
|||
_db_slider = manage (new HSliderController (&_db_adjustment, 115, 18, false));
|
||||
|
||||
_label.set_text (n + ":");
|
||||
_label.set_alignment (0, 0.5);
|
||||
_label.set_name (X_("OptionsLabel"));
|
||||
|
||||
_fader_centering_box.pack_start (*_db_slider, true, false);
|
||||
|
|
@ -466,7 +467,10 @@ DirectoryOption::set_state_from_config ()
|
|||
void
|
||||
DirectoryOption::add_to_page (OptionEditorPage* p)
|
||||
{
|
||||
add_widgets_to_page (p, manage (new Label (_name)), &_file_chooser);
|
||||
Gtk::Label *label = manage (new Label (_name));
|
||||
label->set_alignment (0, 0.5);
|
||||
label->set_name (X_("OptionsLabel"));
|
||||
add_widgets_to_page (p, label, &_file_chooser);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -1540,6 +1540,14 @@ RCOptionEditor::RCOptionEditor ()
|
|||
|
||||
/* EDITOR */
|
||||
|
||||
add_option (S_("Editor"),
|
||||
new BoolOption (
|
||||
"draggable-playhead",
|
||||
_("Allow dragging of playhead"),
|
||||
sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::get_draggable_playhead),
|
||||
sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::set_draggable_playhead)
|
||||
));
|
||||
|
||||
add_option (_("Editor"),
|
||||
new BoolOption (
|
||||
"link-region-and-track-selection",
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ RouteGroupDialog::RouteGroupDialog (RouteGroup* g, bool creating_new)
|
|||
|
||||
main_vbox->pack_start (*top_vbox, false, false);
|
||||
|
||||
_name.set_text (_group->name ());
|
||||
_active.set_active (_group->is_active ());
|
||||
|
||||
Gdk::Color c;
|
||||
|
|
@ -102,8 +101,6 @@ RouteGroupDialog::RouteGroupDialog (RouteGroup* g, bool creating_new)
|
|||
l->set_use_markup ();
|
||||
options_box->pack_start (*l, false, true);
|
||||
|
||||
_name.signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, &Dialog::response), RESPONSE_OK));
|
||||
|
||||
_gain.set_active (_group->is_gain());
|
||||
_relative.set_active (_group->is_relative());
|
||||
_mute.set_active (_group->is_mute());
|
||||
|
|
@ -114,6 +111,18 @@ RouteGroupDialog::RouteGroupDialog (RouteGroup* g, bool creating_new)
|
|||
_share_color.set_active (_group->is_color());
|
||||
_share_monitoring.set_active (_group->is_monitoring());
|
||||
|
||||
if (_group->name ().empty()) {
|
||||
_initial_name = "1";
|
||||
while (!unique_name (_initial_name)) {
|
||||
_initial_name = bump_name_number (_initial_name);
|
||||
}
|
||||
_name.set_text (_initial_name);
|
||||
update();
|
||||
} else {
|
||||
_name.set_text (_initial_name);
|
||||
}
|
||||
|
||||
_name.signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, &Dialog::response), RESPONSE_OK));
|
||||
_name.signal_changed().connect (sigc::mem_fun (*this, &RouteGroupDialog::update));
|
||||
_active.signal_toggled().connect (sigc::mem_fun (*this, &RouteGroupDialog::update));
|
||||
_color.signal_color_set().connect (sigc::mem_fun (*this, &RouteGroupDialog::update));
|
||||
|
|
@ -181,14 +190,14 @@ RouteGroupDialog::do_run ()
|
|||
return Gtk::RESPONSE_CANCEL;
|
||||
}
|
||||
|
||||
if (unique_name ()) {
|
||||
if (unique_name (_name.get_text())) {
|
||||
/* not cancelled and the name is ok, so all is well */
|
||||
return false;
|
||||
}
|
||||
|
||||
_group->set_name (_initial_name);
|
||||
MessageDialog msg (
|
||||
_("A route group of this name already exists. Please use a different name."),
|
||||
_("The group name is not unique. Please use a different name."),
|
||||
false,
|
||||
Gtk::MESSAGE_ERROR,
|
||||
Gtk::BUTTONS_OK,
|
||||
|
|
@ -232,11 +241,12 @@ RouteGroupDialog::gain_toggled ()
|
|||
|
||||
/** @return true if the current group's name is unique accross the session */
|
||||
bool
|
||||
RouteGroupDialog::unique_name () const
|
||||
RouteGroupDialog::unique_name (std::string const name) const
|
||||
{
|
||||
if (name.empty()) return false; // do not allow empty name, empty means unset.
|
||||
list<RouteGroup*> route_groups = _group->session().route_groups ();
|
||||
list<RouteGroup*>::iterator i = route_groups.begin ();
|
||||
while (i != route_groups.end() && ((*i)->name() != _name.get_text() || *i == _group)) {
|
||||
while (i != route_groups.end() && ((*i)->name() != name || *i == _group)) {
|
||||
++i;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ private:
|
|||
|
||||
void gain_toggled ();
|
||||
void update ();
|
||||
bool unique_name () const;
|
||||
bool unique_name (std::string const name) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1413,6 +1413,10 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
|
|||
switch (op) {
|
||||
case Delete:
|
||||
if (playlist->cut (time) != 0) {
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
playlist->ripple(time.start(), -time.length(), NULL);
|
||||
// no need to exclude any regions from rippling here
|
||||
|
||||
vector<Command*> cmds;
|
||||
playlist->rdiff (cmds);
|
||||
_session->add_commands (cmds);
|
||||
|
|
@ -1424,6 +1428,10 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
|
|||
case Cut:
|
||||
if ((what_we_got = playlist->cut (time)) != 0) {
|
||||
_editor.get_cut_buffer().add (what_we_got);
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
playlist->ripple(time.start(), -time.length(), NULL);
|
||||
// no need to exclude any regions from rippling here
|
||||
|
||||
vector<Command*> cmds;
|
||||
playlist->rdiff (cmds);
|
||||
_session->add_commands (cmds);
|
||||
|
|
@ -1439,6 +1447,9 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
|
|||
|
||||
case Clear:
|
||||
if ((what_we_got = playlist->cut (time)) != 0) {
|
||||
if (Config->get_edit_mode() == Ripple)
|
||||
playlist->ripple(time.start(), -time.length(), NULL);
|
||||
// no need to exclude any regions from rippling here
|
||||
|
||||
vector<Command*> cmds;
|
||||
playlist->rdiff (cmds);
|
||||
|
|
@ -1473,8 +1484,18 @@ RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, siz
|
|||
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
|
||||
}
|
||||
|
||||
pl->clear_changes ();
|
||||
pl->clear_changes ();
|
||||
if (Config->get_edit_mode() == Ripple) {
|
||||
std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
|
||||
framecnt_t amount = extent.second - extent.first;
|
||||
pl->ripple(pos, amount * times, boost::shared_ptr<Region>());
|
||||
}
|
||||
pl->paste (*p, pos, times);
|
||||
|
||||
vector<Command*> cmds;
|
||||
pl->rdiff (cmds);
|
||||
_session->add_commands (cmds);
|
||||
|
||||
_session->add_command (new StatefulDiffCommand (pl));
|
||||
|
||||
return true;
|
||||
|
|
@ -2505,6 +2526,30 @@ RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param,
|
|||
add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
|
||||
}
|
||||
|
||||
void
|
||||
RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
|
||||
{
|
||||
boost::shared_ptr<AutomationControl> c = _route->mute_control();
|
||||
if (!c) {
|
||||
error << "Route has no mute automation, unable to add automation track view." << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
mute_track.reset (new AutomationTimeAxisView (_session,
|
||||
_route, _route, c, param,
|
||||
_editor,
|
||||
*this,
|
||||
false,
|
||||
parent_canvas,
|
||||
_route->describe_parameter(param)));
|
||||
|
||||
if (_view) {
|
||||
_view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
|
||||
}
|
||||
|
||||
add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
|
||||
}
|
||||
|
||||
static
|
||||
void add_region_to_list (RegionView* rv, RegionList* l)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -237,11 +237,13 @@ protected:
|
|||
void color_handler ();
|
||||
void region_view_added (RegionView*);
|
||||
void create_gain_automation_child (const Evoral::Parameter &, bool);
|
||||
void create_mute_automation_child (const Evoral::Parameter &, bool);
|
||||
void setup_processor_menu_and_curves ();
|
||||
void route_color_changed ();
|
||||
bool can_edit_name() const;
|
||||
|
||||
boost::shared_ptr<AutomationTimeAxisView> gain_track;
|
||||
boost::shared_ptr<AutomationTimeAxisView> mute_track;
|
||||
|
||||
StreamView* _view;
|
||||
ArdourCanvas::Canvas& parent_canvas;
|
||||
|
|
|
|||
|
|
@ -133,18 +133,6 @@ SessionOptionEditor::SessionOptionEditor (Session* s)
|
|||
|
||||
/* FADES */
|
||||
|
||||
ComboOption<CrossfadeChoice>* cfc = new ComboOption<CrossfadeChoice> (
|
||||
"xfade-choice",
|
||||
_("Default crossfade type"),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::get_xfade_choice),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::set_xfade_choice)
|
||||
);
|
||||
|
||||
cfc->add (ConstantPowerMinus3dB, _("Constant power (-3dB) crossfade"));
|
||||
cfc->add (ConstantPowerMinus6dB, _("Linear (-6dB) crossfade"));
|
||||
|
||||
add_option (_("Fades"), cfc);
|
||||
|
||||
add_option (_("Fades"), new SpinOption<float> (
|
||||
_("destructive-xfade-seconds"),
|
||||
_("Destructive crossfade length"),
|
||||
|
|
|
|||
|
|
@ -699,7 +699,7 @@ TimeAxisViewItem::set_name_text_color ()
|
|||
f = get_fill_color ();
|
||||
}
|
||||
|
||||
name_text->set_color (contrasting_text_color (f));
|
||||
name_text->set_color (ArdourCanvas::contrasting_text_color (f));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
|
|
|||
|
|
@ -46,41 +46,54 @@ public:
|
|||
|
||||
template <typename Function>
|
||||
void foreach_route_ui (Function f) {
|
||||
for (iterator i = begin(); i != end(); ++i) {
|
||||
for (iterator i = begin(); i != end(); ) {
|
||||
iterator tmp = i;
|
||||
++tmp;
|
||||
|
||||
RouteUI* t = dynamic_cast<RouteUI*> (*i);
|
||||
if (t) {
|
||||
f (t);
|
||||
}
|
||||
i = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void foreach_route_time_axis (Function f) {
|
||||
for (iterator i = begin(); i != end(); ++i) {
|
||||
for (iterator i = begin(); i != end(); ) {
|
||||
iterator tmp = i;
|
||||
++tmp;
|
||||
RouteTimeAxisView* t = dynamic_cast<RouteTimeAxisView*> (*i);
|
||||
if (t) {
|
||||
f (t);
|
||||
}
|
||||
i = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void foreach_audio_time_axis (Function f) {
|
||||
for (iterator i = begin(); i != end(); ++i) {
|
||||
for (iterator i = begin(); i != end(); ) {
|
||||
iterator tmp = i;
|
||||
++tmp;
|
||||
AudioTimeAxisView* t = dynamic_cast<AudioTimeAxisView*> (*i);
|
||||
if (t) {
|
||||
f (t);
|
||||
}
|
||||
i = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void foreach_midi_time_axis (Function f) {
|
||||
for (iterator i = begin(); i != end(); ++i) {
|
||||
for (iterator i = begin(); i != end(); ) {
|
||||
iterator tmp = i;
|
||||
++tmp;
|
||||
MidiTimeAxisView* t = dynamic_cast<MidiTimeAxisView*> (*i);
|
||||
if (t) {
|
||||
f (t);
|
||||
}
|
||||
i = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -348,6 +348,12 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf
|
|||
argp[a++] = strdup("-metadata");
|
||||
argp[a++] = format_metadata(it->first.c_str(), it->second.c_str());
|
||||
}
|
||||
|
||||
if (m_fps > 0) {
|
||||
m_lead_in = rint (m_lead_in * m_fps) / m_fps;
|
||||
m_lead_out = rint (m_lead_out * m_fps) / m_fps;
|
||||
}
|
||||
|
||||
if (m_lead_in != 0 && m_lead_out != 0) {
|
||||
std::ostringstream osstream;
|
||||
argp[a++] = strdup("-vf");
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ class TranscodeFfmpeg : public sigc::trackable
|
|||
void set_avoffset(double av_offset) { m_avoffset = av_offset; }
|
||||
void set_leadinout(double lead_in, double lead_out) { m_lead_in = lead_in; m_lead_out = lead_out; }
|
||||
|
||||
void set_fps(double fps) { m_fps = fps; } // on export, used for rounding only.
|
||||
|
||||
#if 1 /* tentative debug mode */
|
||||
void set_debug (bool onoff) { debug_enable = onoff; }
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@
|
|||
UI_CONFIG_VARIABLE(std::string, icon_set, "icon-set", "default")
|
||||
UI_CONFIG_VARIABLE(std::string, ui_rc_file, "ui-rc-file", "ardour3_ui_dark.rc")
|
||||
UI_CONFIG_VARIABLE(bool, flat_buttons, "flat-buttons", false)
|
||||
UI_CONFIG_VARIABLE(float, waveform_gradient_depth, "waveform-gradient-depth", 0.6)
|
||||
UI_CONFIG_VARIABLE(float, timeline_item_gradient_depth, "timeline-item-gradient-depth", 1.3)
|
||||
UI_CONFIG_VARIABLE(float, waveform_gradient_depth, "waveform-gradient-depth", 0)
|
||||
UI_CONFIG_VARIABLE(float, timeline_item_gradient_depth, "timeline-item-gradient-depth", 0.5)
|
||||
UI_CONFIG_VARIABLE(bool, all_floating_windows_are_dialogs, "all-floating-windows-are-dialogs", false)
|
||||
UI_CONFIG_VARIABLE (bool, color_regions_using_track_color, "color-regions-using-track-color", false)
|
||||
UI_CONFIG_VARIABLE (bool, show_waveform_clipping, "show-waveform-clipping", true)
|
||||
UI_CONFIG_VARIABLE (uint32_t, lock_gui_after_seconds, "lock-gui-after-seconds", 0)
|
||||
UI_CONFIG_VARIABLE (bool, draggable_playhead, "draggable-playhead", true)
|
||||
|
||||
|
|
|
|||
|
|
@ -402,38 +402,6 @@ ARDOUR_UI_UTILS::gdk_color_to_rgba (Gdk::Color const& c)
|
|||
return RGBA_TO_UINT (r,g,b,a);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ARDOUR_UI_UTILS::contrasting_text_color (uint32_t c)
|
||||
{
|
||||
double r, g, b, a;
|
||||
ArdourCanvas::color_to_rgba (c, r, g, b, a);
|
||||
|
||||
const double black_r = 0.0;
|
||||
const double black_g = 0.0;
|
||||
const double black_b = 0.0;
|
||||
|
||||
const double white_r = 1.0;
|
||||
const double white_g = 1.0;
|
||||
const double white_b = 1.0;
|
||||
|
||||
/* Use W3C contrast guideline calculation */
|
||||
|
||||
double white_contrast = (max (r, white_r) - min (r, white_r)) +
|
||||
(max (g, white_g) - min (g, white_g)) +
|
||||
(max (b, white_b) - min (b, white_b));
|
||||
|
||||
double black_contrast = (max (r, black_r) - min (r, black_r)) +
|
||||
(max (g, black_g) - min (g, black_g)) +
|
||||
(max (b, black_b) - min (b, black_b));
|
||||
|
||||
if (white_contrast > black_contrast) {
|
||||
/* use white */
|
||||
return ArdourCanvas::rgba_to_color (1.0, 1.0, 1.0, 1.0);
|
||||
} else {
|
||||
/* use black */
|
||||
return ArdourCanvas::rgba_to_color (0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ARDOUR_UI_UTILS::relay_key_press (GdkEventKey* ev, Gtk::Window* win)
|
||||
|
|
@ -618,8 +586,8 @@ ARDOUR_UI_UTILS::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEv
|
|||
/* no special handling or there are modifiers in effect: accelerate first */
|
||||
|
||||
DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
|
||||
DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 string:%4 hardware_keycode:%5 group:%6\n",
|
||||
ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group));
|
||||
DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
|
||||
ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
|
||||
|
||||
if (allow_activating) {
|
||||
DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "audio_clock.h"
|
||||
#include "editor.h"
|
||||
#include "editor_drag.h"
|
||||
#include "global_signals.h"
|
||||
#include "main_clock.h"
|
||||
#include "verbose_cursor.h"
|
||||
|
||||
|
|
@ -44,6 +45,14 @@ VerboseCursor::VerboseCursor (Editor* editor)
|
|||
_canvas_item = new ArdourCanvas::TrackingText (_editor->get_noscroll_group());
|
||||
CANVAS_DEBUG_NAME (_canvas_item, "verbose canvas cursor");
|
||||
_canvas_item->set_font_description (Pango::FontDescription (ARDOUR_UI::config()->get_canvasvar_LargerBoldFont()));
|
||||
color_handler ();
|
||||
|
||||
ARDOUR_UI_UTILS::ColorsChanged.connect (sigc::mem_fun (*this, &VerboseCursor::color_handler));
|
||||
}
|
||||
|
||||
void
|
||||
VerboseCursor::color_handler ()
|
||||
{
|
||||
_canvas_item->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
|
||||
}
|
||||
|
||||
|
|
@ -97,13 +106,9 @@ VerboseCursor::set_time (framepos_t frame)
|
|||
return;
|
||||
}
|
||||
|
||||
AudioClock::Mode m;
|
||||
/* Take clock mode from the primary clock */
|
||||
|
||||
if (Profile->get_sae() || Profile->get_small_screen() || Profile->get_trx()) {
|
||||
m = ARDOUR_UI::instance()->primary_clock->mode();
|
||||
} else {
|
||||
m = ARDOUR_UI::instance()->secondary_clock->mode();
|
||||
}
|
||||
AudioClock::Mode m = ARDOUR_UI::instance()->primary_clock->mode();
|
||||
|
||||
switch (m) {
|
||||
case AudioClock::BBT:
|
||||
|
|
|
|||
|
|
@ -41,8 +41,10 @@ public:
|
|||
|
||||
void show ();
|
||||
void hide ();
|
||||
|
||||
|
||||
private:
|
||||
Editor* _editor;
|
||||
ArdourCanvas::TrackingText* _canvas_item;
|
||||
|
||||
void color_handler ();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -85,6 +85,10 @@ public:
|
|||
void existence_check ();
|
||||
virtual void prevent_deletion ();
|
||||
|
||||
/** Rename the file on disk referenced by this source to \param newname
|
||||
*/
|
||||
int rename (const std::string& name);
|
||||
|
||||
protected:
|
||||
FileSource (Session& session, DataType type,
|
||||
const std::string& path,
|
||||
|
|
|
|||
|
|
@ -144,6 +144,14 @@ public:
|
|||
void uncombine (boost::shared_ptr<Region>);
|
||||
|
||||
void shuffle (boost::shared_ptr<Region>, int dir);
|
||||
void ripple (framepos_t at, framecnt_t distance, RegionList *exclude);
|
||||
void ripple (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude) {
|
||||
RegionList el;
|
||||
if (exclude)
|
||||
el.push_back (exclude);
|
||||
ripple (at, distance, &el);
|
||||
}
|
||||
|
||||
void update_after_tempo_map_change ();
|
||||
|
||||
boost::shared_ptr<Playlist> cut (std::list<AudioRange>&, bool result_is_hidden = true);
|
||||
|
|
@ -283,6 +291,7 @@ public:
|
|||
bool first_set_state;
|
||||
bool _hidden;
|
||||
bool _splicing;
|
||||
bool _rippling;
|
||||
bool _shuffling;
|
||||
bool _nudging;
|
||||
uint32_t _refcnt;
|
||||
|
|
@ -337,6 +346,11 @@ public:
|
|||
void splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude);
|
||||
void splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude);
|
||||
|
||||
void core_ripple (framepos_t at, framecnt_t distance, RegionList *exclude);
|
||||
void ripple_locked (framepos_t at, framecnt_t distance, RegionList *exclude);
|
||||
void ripple_unlocked (framepos_t at, framecnt_t distance, RegionList *exclude);
|
||||
|
||||
|
||||
virtual void remove_dependents (boost::shared_ptr<Region> /*region*/) {}
|
||||
|
||||
virtual XMLNode& state (bool);
|
||||
|
|
|
|||
|
|
@ -202,10 +202,10 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
|||
std::string peak_path (std::string) const;
|
||||
|
||||
std::string peak_path_from_audio_path (std::string) const;
|
||||
std::string new_audio_source_name (const std::string&, uint32_t nchans, uint32_t chan, bool destructive);
|
||||
std::string new_midi_source_name (const std::string&);
|
||||
std::string new_source_path_from_name (DataType type, const std::string&);
|
||||
std::string new_audio_source_path (const std::string&, uint32_t nchans, uint32_t chan, bool destructive, bool take_required);
|
||||
std::string new_midi_source_path (const std::string&);
|
||||
RouteList new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name);
|
||||
std::vector<std::string> get_paths_for_new_sources (bool allow_replacing, const std::string& import_file_path, uint32_t channels);
|
||||
|
||||
void process (pframes_t nframes);
|
||||
|
||||
|
|
@ -555,8 +555,6 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
|||
|
||||
boost::shared_ptr<Region> find_whole_file_parent (boost::shared_ptr<Region const>) const;
|
||||
|
||||
std::string path_from_region_name (DataType type, std::string name, std::string identifier);
|
||||
|
||||
boost::shared_ptr<Region> XMLRegionFactory (const XMLNode&, bool full);
|
||||
boost::shared_ptr<AudioRegion> XMLAudioRegionFactory (const XMLNode&, bool full);
|
||||
boost::shared_ptr<MidiRegion> XMLMidiRegionFactory (const XMLNode&, bool full);
|
||||
|
|
@ -771,6 +769,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
|||
/* ranges */
|
||||
|
||||
void request_play_range (std::list<AudioRange>*, bool leave_rolling = false);
|
||||
void request_cancel_play_range ();
|
||||
bool get_play_range () const { return _play_range; }
|
||||
|
||||
void maybe_update_session_range (framepos_t, framepos_t);
|
||||
|
|
@ -1491,7 +1490,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
|||
|
||||
bool no_questions_about_missing_files;
|
||||
|
||||
std::string get_best_session_directory_for_new_source ();
|
||||
std::string get_best_session_directory_for_new_audio ();
|
||||
|
||||
std::string _custom_audio_source_dir;
|
||||
std::string _custom_midi_source_dir;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
the value of the variable.
|
||||
*****************************************************/
|
||||
|
||||
CONFIG_VARIABLE (CrossfadeChoice, xfade_choice, "xfade-choice", ConstantPowerMinus3dB)
|
||||
CONFIG_VARIABLE (uint32_t, destructive_xfade_msecs, "destructive-xfade-msecs", 2)
|
||||
CONFIG_VARIABLE (bool, use_region_fades, "use-region-fades", true)
|
||||
CONFIG_VARIABLE (bool, show_region_fades, "show-region-fades", true)
|
||||
|
|
@ -43,7 +42,7 @@ CONFIG_VARIABLE_SPECIAL(std::string, audio_search_path, "audio-search-path", "",
|
|||
CONFIG_VARIABLE_SPECIAL(std::string, midi_search_path, "midi-search-path", "", PBD::search_path_expand)
|
||||
CONFIG_VARIABLE (bool, track_name_number, "track-name-number", false)
|
||||
CONFIG_VARIABLE (bool, track_name_take, "track-name-take", false)
|
||||
CONFIG_VARIABLE (std::string, take_name, "take-name", "Take")
|
||||
CONFIG_VARIABLE (std::string, take_name, "take-name", "Take1")
|
||||
CONFIG_VARIABLE (bool, jack_time_master, "jack-time-master", true)
|
||||
CONFIG_VARIABLE (bool, use_video_sync, "use-video-sync", false)
|
||||
CONFIG_VARIABLE (float, video_pullup, "video-pullup", 0.0f)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public:
|
|||
Audition,
|
||||
InputConfigurationChange,
|
||||
SetPlayAudioRange,
|
||||
CancelPlayAudioRange,
|
||||
RealTimeOperation,
|
||||
AdjustPlaybackBuffering,
|
||||
AdjustCaptureBuffering,
|
||||
|
|
|
|||
|
|
@ -47,15 +47,6 @@ public:
|
|||
|
||||
virtual ~SMFSource ();
|
||||
|
||||
/** Rename the file on disk referenced by this source to \param newname
|
||||
*
|
||||
* This method exists only for MIDI file sources, not for audio, which
|
||||
* can never be renamed. It exists for MIDI so that we can get
|
||||
* consistent and sane region/source numbering when regions are added
|
||||
* manually (which never happens with audio).
|
||||
*/
|
||||
int rename (const std::string& name);
|
||||
|
||||
bool safe_file_extension (const std::string& path) const {
|
||||
return safe_midi_file_extension(path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ namespace ARDOUR {
|
|||
FadeInAutomation,
|
||||
FadeOutAutomation,
|
||||
EnvelopeAutomation,
|
||||
RecEnableAutomation
|
||||
RecEnableAutomation,
|
||||
};
|
||||
|
||||
enum AutoState {
|
||||
|
|
@ -341,6 +341,7 @@ namespace ARDOUR {
|
|||
enum EditMode {
|
||||
Slide,
|
||||
Splice,
|
||||
Ripple,
|
||||
Lock
|
||||
};
|
||||
|
||||
|
|
@ -419,17 +420,6 @@ namespace ARDOUR {
|
|||
MixerOrdered
|
||||
};
|
||||
|
||||
enum CrossfadeModel {
|
||||
FullCrossfade,
|
||||
ShortCrossfade
|
||||
};
|
||||
|
||||
enum CrossfadeChoice {
|
||||
RegionFades,
|
||||
ConstantPowerMinus3dB,
|
||||
ConstantPowerMinus6dB,
|
||||
};
|
||||
|
||||
enum ListenPosition {
|
||||
AfterFaderListen,
|
||||
PreFaderListen
|
||||
|
|
@ -622,8 +612,6 @@ std::istream& operator>>(std::istream& o, ARDOUR::AFLPosition& sf);
|
|||
std::istream& operator>>(std::istream& o, ARDOUR::RemoteModel& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::ListenPosition& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::InsertMergePolicy& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::CrossfadeModel& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::CrossfadeChoice& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::SyncSource& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::ShuttleBehaviour& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::ShuttleUnits& sf);
|
||||
|
|
@ -646,8 +634,6 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::AFLPosition& sf);
|
|||
std::ostream& operator<<(std::ostream& o, const ARDOUR::RemoteModel& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::ListenPosition& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::InsertMergePolicy& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::CrossfadeModel& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::CrossfadeChoice& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::SyncSource& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::ShuttleBehaviour& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::ShuttleUnits& sf);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "pbd/stl_delete.h"
|
||||
#include "pbd/strsplit.h"
|
||||
#include "pbd/shortpath.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
#include "pbd/enumwriter.h"
|
||||
|
||||
#include <sndfile.h>
|
||||
|
|
|
|||
|
|
@ -156,6 +156,8 @@ Automatable::describe_parameter (Evoral::Parameter param)
|
|||
|
||||
if (param == Evoral::Parameter(GainAutomation)) {
|
||||
return _("Fader");
|
||||
} else if (param.type() == MuteAutomation) {
|
||||
return _("Mute");
|
||||
} else if (param.type() == MidiCCAutomation) {
|
||||
return string_compose("Controller %1 [%2]", param.id(), int(param.channel()) + 1);
|
||||
} else if (param.type() == MidiPgmChangeAutomation) {
|
||||
|
|
|
|||
|
|
@ -744,4 +744,3 @@ Diskstream::disengage_record_enable ()
|
|||
{
|
||||
g_atomic_int_set (&_record_enabled, 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@ setup_enum_writer ()
|
|||
AFLPosition _AFLPosition;
|
||||
RemoteModel _RemoteModel;
|
||||
DenormalModel _DenormalModel;
|
||||
CrossfadeModel _CrossfadeModel;
|
||||
CrossfadeChoice _CrossfadeChoice;
|
||||
InsertMergePolicy _InsertMergePolicy;
|
||||
ListenPosition _ListenPosition;
|
||||
SampleFormat _SampleFormat;
|
||||
|
|
@ -237,8 +235,14 @@ setup_enum_writer ()
|
|||
|
||||
REGISTER_ENUM (Slide);
|
||||
REGISTER_ENUM (Splice);
|
||||
REGISTER_ENUM (Ripple); // XXX do the old enum values have to stay in order?
|
||||
REGISTER_ENUM (Lock);
|
||||
REGISTER (_EditMode);
|
||||
/*
|
||||
* Splice mode is undefined, undocumented, and basically fubar'ed
|
||||
* perhaps someday we will make it work. but for now, avoid it
|
||||
*/
|
||||
enum_writer.add_to_hack_table ("Splice", "Slide");
|
||||
|
||||
REGISTER_ENUM (Start);
|
||||
REGISTER_ENUM (End);
|
||||
|
|
@ -289,15 +293,6 @@ setup_enum_writer ()
|
|||
*/
|
||||
enum_writer.add_to_hack_table ("EditorOrdered", "MixerOrdered");
|
||||
|
||||
REGISTER_ENUM (FullCrossfade);
|
||||
REGISTER_ENUM (ShortCrossfade);
|
||||
REGISTER (_CrossfadeModel);
|
||||
|
||||
REGISTER_ENUM (RegionFades);
|
||||
REGISTER_ENUM (ConstantPowerMinus3dB);
|
||||
REGISTER_ENUM (ConstantPowerMinus6dB);
|
||||
REGISTER (_CrossfadeChoice);
|
||||
|
||||
REGISTER_ENUM (InsertMergeReject);
|
||||
REGISTER_ENUM (InsertMergeRelax);
|
||||
REGISTER_ENUM (InsertMergeReplace);
|
||||
|
|
@ -374,6 +369,7 @@ setup_enum_writer ()
|
|||
REGISTER_CLASS_ENUM (SessionEvent, Audition);
|
||||
REGISTER_CLASS_ENUM (SessionEvent, InputConfigurationChange);
|
||||
REGISTER_CLASS_ENUM (SessionEvent, SetPlayAudioRange);
|
||||
REGISTER_CLASS_ENUM (SessionEvent, CancelPlayAudioRange);
|
||||
REGISTER_CLASS_ENUM (SessionEvent, StopOnce);
|
||||
REGISTER_CLASS_ENUM (SessionEvent, AutoLoop);
|
||||
REGISTER (_SessionEvent_Type);
|
||||
|
|
@ -794,34 +790,6 @@ std::ostream& operator<<(std::ostream& o, const InsertMergePolicy& var)
|
|||
return o << s;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream& o, CrossfadeModel& var)
|
||||
{
|
||||
std::string s;
|
||||
o >> s;
|
||||
var = (CrossfadeModel) string_2_enum (s, var);
|
||||
return o;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const CrossfadeModel& var)
|
||||
{
|
||||
std::string s = enum_2_string (var);
|
||||
return o << s;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream& o, CrossfadeChoice& var)
|
||||
{
|
||||
std::string s;
|
||||
o >> s;
|
||||
var = (CrossfadeChoice) string_2_enum (s, var);
|
||||
return o;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const CrossfadeChoice& var)
|
||||
{
|
||||
std::string s = enum_2_string (var);
|
||||
return o << s;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream& o, SyncSource& var)
|
||||
{
|
||||
std::string s;
|
||||
|
|
|
|||
|
|
@ -163,14 +163,17 @@ EventTypeMap::new_parameter(uint32_t type, uint8_t channel, uint32_t id) const
|
|||
/* default 0.0 - 1.0 is fine */
|
||||
break;
|
||||
case PluginAutomation:
|
||||
case SoloAutomation:
|
||||
case MuteAutomation:
|
||||
case FadeInAutomation:
|
||||
case FadeOutAutomation:
|
||||
case EnvelopeAutomation:
|
||||
max = 2.0f;
|
||||
normal = 1.0f;
|
||||
break;
|
||||
case SoloAutomation:
|
||||
case MuteAutomation:
|
||||
max = 1.0f;
|
||||
normal = 0.0f;
|
||||
break;
|
||||
case MidiCCAutomation:
|
||||
case MidiPgmChangeAutomation:
|
||||
case MidiChannelPressureAutomation:
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ FileSource::move_to_trash (const string& trash_dir_name)
|
|||
|
||||
if (move_dependents_to_trash() != 0) {
|
||||
/* try to back out */
|
||||
rename (newpath.c_str(), _path.c_str());
|
||||
::rename (newpath.c_str(), _path.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -572,3 +572,28 @@ FileSource::is_stub () const
|
|||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
FileSource::rename (const string& newpath)
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_lock);
|
||||
string oldpath = _path;
|
||||
|
||||
// Test whether newpath exists, if yes notify the user but continue.
|
||||
if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
|
||||
error << string_compose (_("Programming error! %1 tried to rename a file over another file! It's safe to continue working, but please report this to the developers."), PROGRAM_NAME) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Glib::file_test (oldpath.c_str(), Glib::FILE_TEST_EXISTS)) {
|
||||
/* rename only needed if file exists on disk */
|
||||
if (::rename (oldpath.c_str(), newpath.c_str()) != 0) {
|
||||
error << string_compose (_("cannot rename file %1 to %2 (%3)"), oldpath, newpath, strerror(errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
_name = Glib::path_get_basename (newpath);
|
||||
_path = newpath;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,10 +59,9 @@ Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs, s
|
|||
}
|
||||
}
|
||||
|
||||
string path = session.path_from_region_name (region->data_type(),
|
||||
PBD::basename_nosuffix (names[i]), string (""));
|
||||
string path = session.new_audio_source_path (name, region->n_channels(), i, false, false);
|
||||
|
||||
if (path.length() == 0) {
|
||||
if (path.empty()) {
|
||||
error << string_compose (_("filter: error creating name for new file based on %1"), region->name())
|
||||
<< endmsg;
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -117,78 +117,31 @@ open_importable_source (const string& path, framecnt_t samplerate, ARDOUR::SrcQu
|
|||
}
|
||||
}
|
||||
|
||||
static std::string
|
||||
get_non_existent_filename (HeaderFormat hf, DataType type, const bool allow_replacing, const std::string& destdir, const std::string& basename, uint32_t channel, uint32_t channels)
|
||||
{
|
||||
char buf[PATH_MAX+1];
|
||||
bool goodfile = false;
|
||||
string base = basename;
|
||||
string ext = native_header_format_extension (hf, type);
|
||||
uint32_t cnt = 1;
|
||||
|
||||
do {
|
||||
|
||||
if (type == DataType::AUDIO && channels == 2) {
|
||||
if (channel == 0) {
|
||||
if (cnt == 1) {
|
||||
snprintf (buf, sizeof(buf), "%s-L%s", base.c_str(), ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%s-%d-L%s", base.c_str(), cnt, ext.c_str());
|
||||
}
|
||||
} else {
|
||||
if (cnt == 1) {
|
||||
snprintf (buf, sizeof(buf), "%s-R%s", base.c_str(), ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%s-%d-R%s", base.c_str(), cnt, ext.c_str());
|
||||
}
|
||||
}
|
||||
} else if (channels > 1) {
|
||||
if (cnt == 1) {
|
||||
snprintf (buf, sizeof(buf), "%s-c%d%s", base.c_str(), channel, ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%s-%d-c%d%s", base.c_str(), cnt, channel, ext.c_str());
|
||||
}
|
||||
} else {
|
||||
if (cnt == 1) {
|
||||
snprintf (buf, sizeof(buf), "%s%s", base.c_str(), ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%s-%d%s", base.c_str(), cnt, ext.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
string tempname = destdir + "/" + buf;
|
||||
|
||||
if (!allow_replacing && Glib::file_test (tempname, Glib::FILE_TEST_EXISTS)) {
|
||||
|
||||
cnt++;
|
||||
|
||||
} else {
|
||||
|
||||
goodfile = true;
|
||||
}
|
||||
|
||||
} while (!goodfile);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static vector<string>
|
||||
get_paths_for_new_sources (HeaderFormat hf, const bool allow_replacing, const string& import_file_path, const string& session_dir, uint32_t channels)
|
||||
vector<string>
|
||||
Session::get_paths_for_new_sources (bool /*allow_replacing*/, const string& import_file_path, uint32_t channels)
|
||||
{
|
||||
vector<string> new_paths;
|
||||
const string basename = basename_nosuffix (import_file_path);
|
||||
|
||||
SessionDirectory sdir(session_dir);
|
||||
|
||||
for (uint32_t n = 0; n < channels; ++n) {
|
||||
|
||||
const DataType type = SMFSource::safe_midi_file_extension (import_file_path) ? DataType::MIDI : DataType::AUDIO;
|
||||
string filepath;
|
||||
|
||||
std::string filepath = (type == DataType::MIDI)
|
||||
? sdir.midi_path() : sdir.sound_path();
|
||||
switch (type) {
|
||||
case DataType::MIDI:
|
||||
filepath = new_midi_source_path (basename);
|
||||
break;
|
||||
case DataType::AUDIO:
|
||||
filepath = new_audio_source_path (basename, channels, n, false, false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (filepath.empty()) {
|
||||
error << string_compose (_("Cannot find new filename for imported file %1"), import_file_path) << endmsg;
|
||||
return vector<string>();
|
||||
}
|
||||
|
||||
filepath = Glib::build_filename (filepath,
|
||||
get_non_existent_filename (hf, type, allow_replacing, filepath, basename, n, channels));
|
||||
new_paths.push_back (filepath);
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +278,7 @@ write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
|
|||
progress_base = 0.5;
|
||||
}
|
||||
|
||||
uint32_t read_count = 0;
|
||||
framecnt_t read_count = 0;
|
||||
|
||||
while (!status.cancel) {
|
||||
|
||||
|
|
@ -521,16 +474,13 @@ Session::import_files (ImportStatus& status)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (channels == 0) {
|
||||
error << _("Import: file contains no channels.") << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
vector<string> new_paths = get_paths_for_new_sources (config.get_native_file_header_format(),
|
||||
status.replace_existing_source, *p,
|
||||
get_best_session_directory_for_new_source (),
|
||||
channels);
|
||||
vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p, channels);
|
||||
Sources newfiles;
|
||||
framepos_t natural_position = source ? source->natural_position() : 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1258,9 +1258,9 @@ MidiDiskstream::steal_write_source_name ()
|
|||
*/
|
||||
|
||||
try {
|
||||
string new_name = _session.new_midi_source_name (name());
|
||||
string new_path = _session.new_midi_source_path (name());
|
||||
|
||||
if (_write_source->rename (new_name)) {
|
||||
if (_write_source->rename (new_path)) {
|
||||
return string();
|
||||
}
|
||||
} catch (...) {
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, boo
|
|||
in_set_state--;
|
||||
|
||||
_splicing = other->_splicing;
|
||||
_rippling = other->_rippling;
|
||||
_nudging = other->_nudging;
|
||||
_edit_mode = other->_edit_mode;
|
||||
|
||||
|
|
@ -302,6 +303,7 @@ Playlist::init (bool hide)
|
|||
_refcnt = 0;
|
||||
_hidden = hide;
|
||||
_splicing = false;
|
||||
_rippling = false;
|
||||
_shuffling = false;
|
||||
_nudging = false;
|
||||
in_set_state = 0;
|
||||
|
|
@ -706,7 +708,7 @@ Playlist::flush_notifications (bool from_undo)
|
|||
}
|
||||
}
|
||||
|
||||
possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
|
||||
possibly_splice_unlocked (position, (pos + length) - position, region);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1399,7 +1401,7 @@ Playlist::flush_notifications (bool from_undo)
|
|||
|
||||
if (_edit_mode == Splice) {
|
||||
splice_locked (at, distance, exclude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1456,12 +1458,63 @@ Playlist::flush_notifications (bool from_undo)
|
|||
_splicing = false;
|
||||
|
||||
notify_contents_changed ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
|
||||
{
|
||||
if (in_set_state || _splicing || _nudging || _shuffling) {
|
||||
void
|
||||
Playlist::ripple_locked (framepos_t at, framecnt_t distance, RegionList *exclude)
|
||||
{
|
||||
{
|
||||
RegionWriteLock rl (this);
|
||||
core_ripple (at, distance, exclude);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::ripple_unlocked (framepos_t at, framecnt_t distance, RegionList *exclude)
|
||||
{
|
||||
core_ripple (at, distance, exclude);
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::core_ripple (framepos_t at, framecnt_t distance, RegionList *exclude)
|
||||
{
|
||||
if (distance == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_rippling = true;
|
||||
RegionListProperty copy = regions;
|
||||
for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
|
||||
assert (i != copy.end());
|
||||
|
||||
if (exclude) {
|
||||
if (std::find(exclude->begin(), exclude->end(), (*i)) != exclude->end()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*i)->position() >= at) {
|
||||
framepos_t new_pos = (*i)->position() + distance;
|
||||
framepos_t limit = max_framepos - (*i)->length();
|
||||
if (new_pos < 0) {
|
||||
new_pos = 0;
|
||||
} else if (new_pos >= limit ) {
|
||||
new_pos = limit;
|
||||
}
|
||||
|
||||
(*i)->set_position (new_pos);
|
||||
}
|
||||
}
|
||||
|
||||
_rippling = false;
|
||||
notify_contents_changed ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
|
||||
{
|
||||
if (in_set_state || _splicing || _rippling || _nudging || _shuffling) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2694,6 +2747,12 @@ Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::ripple (framepos_t at, framecnt_t distance, RegionList *exclude)
|
||||
{
|
||||
ripple_locked (at, distance, exclude);
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::update_after_tempo_map_change ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include <boost/algorithm/string/erase.hpp>
|
||||
|
||||
#include "pbd/convert.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/boost_debug.h"
|
||||
#include "pbd/stl_delete.h"
|
||||
|
|
@ -500,6 +501,14 @@ Session::destroy ()
|
|||
|
||||
clear_clicks ();
|
||||
|
||||
/* need to remove auditioner before monitoring section
|
||||
* otherwise it is re-connected */
|
||||
auditioner.reset ();
|
||||
|
||||
/* drop references to routes held by the monitoring section
|
||||
* specifically _monitor_out aux/listen references */
|
||||
remove_monitor_section();
|
||||
|
||||
/* clear out any pending dead wood from RCU managed objects */
|
||||
|
||||
routes.flush ();
|
||||
|
|
@ -519,7 +528,6 @@ Session::destroy ()
|
|||
|
||||
/* reset these three references to special routes before we do the usual route delete thing */
|
||||
|
||||
auditioner.reset ();
|
||||
_master_out.reset ();
|
||||
_monitor_out.reset ();
|
||||
|
||||
|
|
@ -2603,6 +2611,13 @@ Session::remove_route (boost::shared_ptr<Route> route)
|
|||
}
|
||||
}
|
||||
|
||||
/* if the monitoring section had a pointer to this route, remove it */
|
||||
if (_monitor_out && !route->is_master() && !route->is_monitor()) {
|
||||
Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
|
||||
PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
|
||||
route->remove_aux_or_listen (_monitor_out);
|
||||
}
|
||||
|
||||
boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
|
||||
if (mt && mt->step_editing()) {
|
||||
if (_step_editors > 0) {
|
||||
|
|
@ -3421,38 +3436,6 @@ Session::count_sources_by_origin (const string& path)
|
|||
return cnt;
|
||||
}
|
||||
|
||||
/** Return the full path (in some session directory) for a new within-session source.
|
||||
* \a name must be a session-unique name that does not contain slashes
|
||||
* (e.g. as returned by new_*_source_name)
|
||||
*/
|
||||
string
|
||||
Session::new_source_path_from_name (DataType type, const string& name)
|
||||
{
|
||||
assert(name.find("/") == string::npos);
|
||||
|
||||
std::string p;
|
||||
if (type == DataType::AUDIO) {
|
||||
if (_custom_audio_source_dir.empty()) {
|
||||
SessionDirectory sdir(get_best_session_directory_for_new_source());
|
||||
p = sdir.sound_path();
|
||||
} else {
|
||||
p = _custom_audio_source_dir;
|
||||
}
|
||||
} else if (type == DataType::MIDI) {
|
||||
if (_custom_midi_source_dir.empty()) {
|
||||
SessionDirectory sdir(get_best_session_directory_for_new_source());
|
||||
p = sdir.midi_path();
|
||||
} else {
|
||||
p = _custom_midi_source_dir;
|
||||
}
|
||||
} else {
|
||||
error << "Unknown source type, unable to create file path" << endmsg;
|
||||
return "";
|
||||
}
|
||||
|
||||
return Glib::build_filename (p, name);
|
||||
}
|
||||
|
||||
bool
|
||||
Session::set_audio_source_dir (std::string dir)
|
||||
{
|
||||
|
|
@ -3464,7 +3447,7 @@ Session::set_audio_source_dir (std::string dir)
|
|||
if (dir == _custom_audio_source_dir) {
|
||||
return true;
|
||||
}
|
||||
SessionDirectory sdir(get_best_session_directory_for_new_source ());
|
||||
SessionDirectory sdir(get_best_session_directory_for_new_audio ());
|
||||
if (dir == sdir.sound_path() || dir.empty()) {
|
||||
if (_custom_audio_source_dir.empty()) {
|
||||
changed = false;
|
||||
|
|
@ -3508,7 +3491,7 @@ Session::set_midi_source_dir (std::string dir)
|
|||
return true;
|
||||
}
|
||||
|
||||
SessionDirectory sdir(get_best_session_directory_for_new_source ());
|
||||
SessionDirectory sdir(session_dirs[0].path);
|
||||
if (dir == sdir.midi_path() || dir.empty()) {
|
||||
if (_custom_midi_source_dir.empty()) {
|
||||
changed = false;
|
||||
|
|
@ -3549,74 +3532,60 @@ Session::peak_path (string base) const
|
|||
|
||||
/** Return a unique name based on \a base for a new internal audio source */
|
||||
string
|
||||
Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t chan, bool destructive)
|
||||
Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required)
|
||||
{
|
||||
uint32_t cnt;
|
||||
char buf[PATH_MAX+1];
|
||||
const uint32_t limit = 10000;
|
||||
string possible_name;
|
||||
const uint32_t limit = 9999; // arbitrary limit on number of files with the same basic name
|
||||
string legalized;
|
||||
string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
|
||||
bool some_related_source_name_exists = false;
|
||||
|
||||
buf[0] = '\0';
|
||||
possible_name[0] = '\0';
|
||||
legalized = legalize_for_path (base);
|
||||
|
||||
std::vector<string> sdirs;
|
||||
vector<space_and_path>::iterator i;
|
||||
std::vector<string> sdirs = source_search_path(DataType::AUDIO);
|
||||
|
||||
for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
|
||||
SessionDirectory sdir((*i).path);
|
||||
sdirs.push_back(sdir.sound_path());
|
||||
}
|
||||
if (!_custom_audio_source_dir.empty()) {
|
||||
sdirs.push_back(_custom_audio_source_dir);
|
||||
}
|
||||
|
||||
// Find a "version" of the base name that doesn't exist in any of the possible directories.
|
||||
|
||||
for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
|
||||
|
||||
uint32_t existing = 0;
|
||||
|
||||
for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
|
||||
|
||||
ostringstream sstr;
|
||||
|
||||
if (destructive) {
|
||||
|
||||
if (nchan < 2) {
|
||||
snprintf (buf, sizeof(buf), "T%04d-%s%s",
|
||||
cnt, legalized.c_str(), ext.c_str());
|
||||
} else if (nchan == 2) {
|
||||
if (chan == 0) {
|
||||
snprintf (buf, sizeof(buf), "T%04d-%s%%L%s",
|
||||
cnt, legalized.c_str(), ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "T%04d-%s%%R%s",
|
||||
cnt, legalized.c_str(), ext.c_str());
|
||||
}
|
||||
} else if (nchan < 26) {
|
||||
snprintf (buf, sizeof(buf), "T%04d-%s%%%c%s",
|
||||
cnt, legalized.c_str(), 'a' + chan, ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "T%04d-%s%s",
|
||||
cnt, legalized.c_str(), ext.c_str());
|
||||
}
|
||||
|
||||
sstr << 'T';
|
||||
sstr << setfill ('0') << setw (4) << cnt;
|
||||
sstr << legalized;
|
||||
} else {
|
||||
|
||||
if (nchan < 2) {
|
||||
snprintf (buf, sizeof(buf), "%s-%u%s", legalized.c_str(), cnt, ext.c_str());
|
||||
} else if (nchan == 2) {
|
||||
if (chan == 0) {
|
||||
snprintf (buf, sizeof(buf), "%s-%u%%L%s", legalized.c_str(), cnt, ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%s-%u%%R%s", legalized.c_str(), cnt, ext.c_str());
|
||||
}
|
||||
} else if (nchan < 26) {
|
||||
snprintf (buf, sizeof(buf), "%s-%u%%%c%s", legalized.c_str(), cnt, 'a' + chan, ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%s-%u%s", legalized.c_str(), cnt, ext.c_str());
|
||||
sstr << legalized;
|
||||
|
||||
if (take_required || some_related_source_name_exists) {
|
||||
sstr << '-';
|
||||
sstr << cnt;
|
||||
}
|
||||
}
|
||||
|
||||
if (nchan == 2) {
|
||||
if (chan == 0) {
|
||||
sstr << "%L";
|
||||
} else {
|
||||
sstr << "%R";
|
||||
}
|
||||
} else if (nchan > 2 && nchan < 26) {
|
||||
sstr << '%';
|
||||
sstr << 'a' + chan;
|
||||
}
|
||||
|
||||
string spath = (*i);
|
||||
sstr << ext;
|
||||
possible_name = sstr.str();
|
||||
|
||||
/* note that we search *without* the extension so that
|
||||
we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
|
||||
|
|
@ -3624,7 +3593,7 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
|
|||
a file format change.
|
||||
*/
|
||||
|
||||
if (matching_unsuffixed_filename_exists_in (spath, buf)) {
|
||||
if (matching_unsuffixed_filename_exists_in (*i, possible_name)) {
|
||||
existing++;
|
||||
break;
|
||||
}
|
||||
|
|
@ -3638,7 +3607,7 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
|
|||
* notions of their removability.
|
||||
*/
|
||||
|
||||
string possible_path = Glib::build_filename (spath, buf);
|
||||
string possible_path = Glib::build_filename (*i, possible_name);
|
||||
|
||||
if (audio_source_by_path_and_channel (possible_path, chan)) {
|
||||
existing++;
|
||||
|
|
@ -3650,6 +3619,8 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
|
|||
break;
|
||||
}
|
||||
|
||||
some_related_source_name_exists = true;
|
||||
|
||||
if (cnt > limit) {
|
||||
error << string_compose(
|
||||
_("There are already %1 recordings for %2, which I consider too many."),
|
||||
|
|
@ -3659,56 +3630,59 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
|
|||
}
|
||||
}
|
||||
|
||||
return Glib::path_get_basename (buf);
|
||||
}
|
||||
/* We've established that the new name does not exist in any session
|
||||
* directory, so now find out which one we should use for this new
|
||||
* audio source.
|
||||
*/
|
||||
|
||||
/** Create a new within-session audio source */
|
||||
boost::shared_ptr<AudioFileSource>
|
||||
Session::create_audio_source_for_session (size_t n_chans, string const & n, uint32_t chan, bool destructive)
|
||||
{
|
||||
const string name = new_audio_source_name (n, n_chans, chan, destructive);
|
||||
const string path = new_source_path_from_name(DataType::AUDIO, name);
|
||||
|
||||
return boost::dynamic_pointer_cast<AudioFileSource> (
|
||||
SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate()));
|
||||
std::string s;
|
||||
if (!_custom_audio_source_dir.empty()) {
|
||||
s = Glib::build_filename (_custom_audio_source_dir, possible_name);
|
||||
} else {
|
||||
SessionDirectory sdir(get_best_session_directory_for_new_audio ());
|
||||
s = Glib::build_filename (sdir.sound_path(), possible_name);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/** Return a unique name based on \a owner_name for a new internal MIDI source */
|
||||
string
|
||||
Session::new_midi_source_name (const string& owner_name)
|
||||
Session::new_midi_source_path (const string& base)
|
||||
{
|
||||
uint32_t cnt;
|
||||
char buf[PATH_MAX+1];
|
||||
const uint32_t limit = 10000;
|
||||
string legalized;
|
||||
string possible_path;
|
||||
string possible_name;
|
||||
|
||||
buf[0] = '\0';
|
||||
legalized = legalize_for_path (owner_name);
|
||||
legalized = legalize_for_path (base);
|
||||
|
||||
std::vector<string> sdirs;
|
||||
vector<space_and_path>::iterator i;
|
||||
// Find a "version" of the file name that doesn't exist in any of the possible directories.
|
||||
std::vector<string> sdirs = source_search_path(DataType::MIDI);
|
||||
/* - the main session folder is the first in the vector.
|
||||
* - after checking all locations for file-name uniqueness,
|
||||
* we keep the one from the last iteration as new file name
|
||||
* - midi files are small and should just be kept in the main session-folder
|
||||
*
|
||||
* -> reverse the array, check main session folder last and use that as location
|
||||
* for MIDI files.
|
||||
*/
|
||||
std::reverse(sdirs.begin(), sdirs.end());
|
||||
|
||||
for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
|
||||
SessionDirectory sdir((*i).path);
|
||||
sdirs.push_back(sdir.midi_path());
|
||||
}
|
||||
if (!_custom_midi_source_dir.empty()) {
|
||||
sdirs.push_back(_custom_midi_source_dir);
|
||||
}
|
||||
|
||||
// Find a "version" of the file name that doesn't exist in any of the possible directories.
|
||||
|
||||
for (cnt = 1; cnt <= limit; ++cnt) {
|
||||
|
||||
uint32_t existing = 0;
|
||||
|
||||
|
||||
for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
|
||||
|
||||
snprintf (buf, sizeof(buf), "%s-%u.mid", legalized.c_str(), cnt);
|
||||
possible_name = buf;
|
||||
|
||||
std::string possible_path = Glib::build_filename (*i, possible_name);
|
||||
possible_path = Glib::build_filename (*i, possible_name);
|
||||
|
||||
if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) {
|
||||
existing++;
|
||||
|
|
@ -3726,31 +3700,47 @@ Session::new_midi_source_name (const string& owner_name)
|
|||
if (cnt > limit) {
|
||||
error << string_compose(
|
||||
_("There are already %1 recordings for %2, which I consider too many."),
|
||||
limit, owner_name) << endmsg;
|
||||
limit, base) << endmsg;
|
||||
destroy ();
|
||||
throw failed_constructor();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return possible_name;
|
||||
/* No need to "find best location" for software/app-based RAID, because
|
||||
MIDI is so small that we always put it in the same place.
|
||||
*/
|
||||
|
||||
return possible_path;
|
||||
}
|
||||
|
||||
|
||||
/** Create a new within-session audio source */
|
||||
boost::shared_ptr<AudioFileSource>
|
||||
Session::create_audio_source_for_session (size_t n_chans, string const & base, uint32_t chan, bool destructive)
|
||||
{
|
||||
const string path = new_audio_source_path (base, n_chans, chan, destructive, true);
|
||||
|
||||
if (!path.empty()) {
|
||||
return boost::dynamic_pointer_cast<AudioFileSource> (
|
||||
SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate()));
|
||||
} else {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a new within-session MIDI source */
|
||||
boost::shared_ptr<MidiSource>
|
||||
Session::create_midi_source_for_session (string const & basic_name)
|
||||
{
|
||||
std::string name;
|
||||
|
||||
if (name.empty()) {
|
||||
name = new_midi_source_name (basic_name);
|
||||
const string path = new_midi_source_path (basic_name);
|
||||
|
||||
if (!path.empty()) {
|
||||
return boost::dynamic_pointer_cast<SMFSource> (
|
||||
SourceFactory::createWritable (
|
||||
DataType::MIDI, *this, path, false, frame_rate()));
|
||||
} else {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
const string path = new_source_path_from_name (DataType::MIDI, name);
|
||||
|
||||
return boost::dynamic_pointer_cast<SMFSource> (
|
||||
SourceFactory::createWritable (
|
||||
DataType::MIDI, *this, path, false, frame_rate()));
|
||||
}
|
||||
|
||||
/** Create a new within-session MIDI source */
|
||||
|
|
@ -3784,7 +3774,7 @@ Session::create_midi_source_by_stealing_name (boost::shared_ptr<Track> track)
|
|||
return boost::shared_ptr<MidiSource>();
|
||||
}
|
||||
|
||||
const string path = new_source_path_from_name (DataType::MIDI, name);
|
||||
const string path = new_midi_source_path (name);
|
||||
|
||||
return boost::dynamic_pointer_cast<SMFSource> (
|
||||
SourceFactory::createWritable (
|
||||
|
|
@ -3862,6 +3852,9 @@ Session::audition_region (boost::shared_ptr<Region> r)
|
|||
void
|
||||
Session::cancel_audition ()
|
||||
{
|
||||
if (!auditioner) {
|
||||
return;
|
||||
}
|
||||
if (auditioner->auditioning()) {
|
||||
auditioner->cancel_audition ();
|
||||
AuditionActive (false); /* EMIT SIGNAL */
|
||||
|
|
@ -4290,18 +4283,14 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
|||
boost::shared_ptr<Region> result;
|
||||
boost::shared_ptr<Playlist> playlist;
|
||||
boost::shared_ptr<AudioFileSource> fsource;
|
||||
uint32_t x;
|
||||
ChanCount diskstream_channels (track.n_channels());
|
||||
framepos_t position;
|
||||
framecnt_t this_chunk;
|
||||
framepos_t to_do;
|
||||
framepos_t latency_skip;
|
||||
BufferSet buffers;
|
||||
SessionDirectory sdir(get_best_session_directory_for_new_source ()); // XXX use _custom_audio_source_dir ??
|
||||
const string sound_dir = sdir.sound_path();
|
||||
framepos_t len = end - start;
|
||||
bool need_block_size_reset = false;
|
||||
string ext;
|
||||
ChanCount const max_proc = track.max_processor_streams ();
|
||||
string legal_playlist_name;
|
||||
string possible_path;
|
||||
|
|
@ -4342,29 +4331,22 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
|||
|
||||
legal_playlist_name = legalize_for_path (playlist->name());
|
||||
|
||||
ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
|
||||
|
||||
for (uint32_t chan_n = 0; chan_n < diskstream_channels.n_audio(); ++chan_n) {
|
||||
|
||||
for (x = 0; x < 99999; ++x) {
|
||||
possible_path = Glib::build_filename (sound_dir, string_compose ("%1-%2-bounce-%3%4", legal_playlist_name.c_str(), chan_n, x+1, ext.c_str()));
|
||||
if (!Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x == 99999) {
|
||||
error << string_compose (_("too many bounced versions of playlist \"%1\""), playlist->name()) << endmsg;
|
||||
string base_name = string_compose ("%1-%2-bounce", playlist->name(), chan_n);
|
||||
string path = new_audio_source_path (legal_playlist_name, diskstream_channels.n_audio(), chan_n, false, true);
|
||||
|
||||
if (path.empty()) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
try {
|
||||
fsource = boost::dynamic_pointer_cast<AudioFileSource> (
|
||||
SourceFactory::createWritable (DataType::AUDIO, *this, possible_path, false, frame_rate()));
|
||||
SourceFactory::createWritable (DataType::AUDIO, *this, path, false, frame_rate()));
|
||||
}
|
||||
|
||||
catch (failed_constructor& err) {
|
||||
error << string_compose (_("cannot create new audio file \"%1\" for %2"), possible_path, track.name()) << endmsg;
|
||||
error << string_compose (_("cannot create new audio file \"%1\" for %2"), path, track.name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1142,6 +1142,10 @@ Session::process_event (SessionEvent* ev)
|
|||
set_play_range (ev->audio_range, (ev->speed == 1.0f));
|
||||
break;
|
||||
|
||||
case SessionEvent::CancelPlayAudioRange:
|
||||
unset_play_range();
|
||||
break;
|
||||
|
||||
case SessionEvent::RealTimeOperation:
|
||||
process_rtop (ev);
|
||||
del = false; // other side of RT request needs to clean up
|
||||
|
|
|
|||
|
|
@ -1850,41 +1850,6 @@ Session::get_sources_as_xml ()
|
|||
return *node;
|
||||
}
|
||||
|
||||
string
|
||||
Session::path_from_region_name (DataType type, string name, string identifier)
|
||||
{
|
||||
char buf[PATH_MAX+1];
|
||||
uint32_t n;
|
||||
SessionDirectory sdir(get_best_session_directory_for_new_source());
|
||||
std::string source_dir = ((type == DataType::AUDIO)
|
||||
? sdir.sound_path() : sdir.midi_path());
|
||||
|
||||
string ext = native_header_format_extension (config.get_native_file_header_format(), type);
|
||||
|
||||
for (n = 0; n < 999999; ++n) {
|
||||
if (identifier.length()) {
|
||||
snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(),
|
||||
identifier.c_str(), n, ext.c_str());
|
||||
} else {
|
||||
snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(),
|
||||
n, ext.c_str());
|
||||
}
|
||||
|
||||
std::string source_path = Glib::build_filename (source_dir, buf);
|
||||
|
||||
if (!Glib::file_test (source_path, Glib::FILE_TEST_EXISTS)) {
|
||||
return source_path;
|
||||
}
|
||||
}
|
||||
|
||||
error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
|
||||
name, identifier)
|
||||
<< endmsg;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Session::load_sources (const XMLNode& node)
|
||||
{
|
||||
|
|
@ -2121,7 +2086,7 @@ Session::refresh_disk_space ()
|
|||
}
|
||||
|
||||
string
|
||||
Session::get_best_session_directory_for_new_source ()
|
||||
Session::get_best_session_directory_for_new_audio ()
|
||||
{
|
||||
vector<space_and_path>::iterator i;
|
||||
string result = _session_dir->root_path();
|
||||
|
|
|
|||
|
|
@ -227,6 +227,14 @@ Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
|
|||
queue_event (ev);
|
||||
}
|
||||
|
||||
void
|
||||
Session::request_cancel_play_range ()
|
||||
{
|
||||
SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
|
||||
queue_event (ev);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Session::realtime_stop (bool abort, bool clear_state)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -718,34 +718,3 @@ SMFSource::prevent_deletion ()
|
|||
_flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));
|
||||
}
|
||||
|
||||
int
|
||||
SMFSource::rename (const string& newname)
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_lock);
|
||||
string oldpath = _path;
|
||||
string newpath = _session.new_source_path_from_name (DataType::MIDI, newname);
|
||||
|
||||
if (newpath.empty()) {
|
||||
error << string_compose (_("programming error: %1"), "cannot generate a changed file path") << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test whether newpath exists, if yes notify the user but continue.
|
||||
if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
|
||||
error << string_compose (_("Programming error! %1 tried to rename a file over another file! It's safe to continue working, but please report this to the developers."), PROGRAM_NAME) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Glib::file_test (oldpath.c_str(), Glib::FILE_TEST_EXISTS)) {
|
||||
/* rename only needed if file exists on disk */
|
||||
if (::rename (oldpath.c_str(), newpath.c_str()) != 0) {
|
||||
error << string_compose (_("cannot rename file %1 to %2 (%3)"), oldpath, newpath, strerror(errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
_name = Glib::path_get_basename (newpath);
|
||||
_path = newpath;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,18 +200,19 @@ string
|
|||
ARDOUR::bump_name_number (const std::string& name)
|
||||
{
|
||||
size_t pos = name.length();
|
||||
size_t num = 0;
|
||||
bool have_number = false;
|
||||
while (pos > 0 && isdigit(name.at(--pos))) {
|
||||
have_number = true;
|
||||
num = pos;
|
||||
}
|
||||
|
||||
string newname;
|
||||
if (have_number) {
|
||||
++pos;
|
||||
int32_t num = strtol (name.c_str() + pos, (char **)NULL, 10);
|
||||
int32_t seq = strtol (name.c_str() + num, (char **)NULL, 10);
|
||||
char buf[32];
|
||||
snprintf (buf, sizeof(buf), "%d", num + 1);
|
||||
newname = name.substr (0, pos);
|
||||
snprintf (buf, sizeof(buf), "%d", seq + 1);
|
||||
newname = name.substr (0, num);
|
||||
newname += buf;
|
||||
} else {
|
||||
newname = name;
|
||||
|
|
@ -422,6 +423,8 @@ ARDOUR::string_to_edit_mode (string str)
|
|||
return Splice;
|
||||
} else if (str == _("Slide")) {
|
||||
return Slide;
|
||||
} else if (str == _("Ripple")) {
|
||||
return Ripple;
|
||||
} else if (str == _("Lock")) {
|
||||
return Lock;
|
||||
}
|
||||
|
|
@ -440,6 +443,9 @@ ARDOUR::edit_mode_to_string (EditMode mode)
|
|||
case Lock:
|
||||
return _("Lock");
|
||||
|
||||
case Ripple:
|
||||
return _("Ripple");
|
||||
|
||||
default:
|
||||
case Splice:
|
||||
return _("Splice");
|
||||
|
|
|
|||
|
|
@ -387,9 +387,9 @@ GtkCanvas::pick_current_item (Duple const & point, int state)
|
|||
if (DEBUG_ENABLED(PBD::DEBUG::CanvasEnterLeave)) {
|
||||
for (vector<Item const*>::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
#ifdef CANVAS_DEBUG
|
||||
std::cerr << "\tItem " << (*it)->whatami() << '/' << (*it)->name << std::endl;
|
||||
std::cerr << "\tItem " << (*it)->whatami() << '/' << (*it)->name << " ignore events ? " << (*it)->ignore_events() << " vis ? " << (*it)->visible() << std::endl;
|
||||
#else
|
||||
std::cerr << "\tItem " << (*it)->whatami() << std::endl;
|
||||
std::cerr << "\tItem " << (*it)->whatami() << '/' << " ignore events ? " << (*it)->ignore_events() << " vis ? " << (*it)->visible() << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -416,6 +416,8 @@ GtkCanvas::pick_current_item (Duple const & point, int state)
|
|||
within_items.push_front (possible_item);
|
||||
}
|
||||
|
||||
DEBUG_TRACE (PBD::DEBUG::CanvasEnterLeave, string_compose ("after filtering insensitive + containers, we have %1 items\n", within_items.size()));
|
||||
|
||||
if (within_items.empty()) {
|
||||
|
||||
/* no items at point, just send leave event below */
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
#include "canvas/visibility.h"
|
||||
#include "canvas/item.h"
|
||||
#include "canvas/types.h"
|
||||
#include "canvas/outline.h"
|
||||
#include "canvas/fill.h"
|
||||
|
||||
namespace ArdourCanvas
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,5 +31,7 @@ namespace ArdourCanvas {
|
|||
extern LIBCANVAS_API void set_source_rgba (Cairo::RefPtr<Cairo::Context>, Color);
|
||||
|
||||
Distance LIBCANVAS_API distance_to_segment_squared (Duple const & p, Duple const & p1, Duple const & p2, double& t, Duple& at);
|
||||
|
||||
uint32_t LIBCANVAS_API contrasting_text_color (uint32_t c);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -959,11 +959,14 @@ Item::add_items_at_point (Duple const point, vector<Item const *>& items) const
|
|||
return;
|
||||
}
|
||||
|
||||
/* recurse and add any items within our group that contain point */
|
||||
/* recurse and add any items within our group that contain point.
|
||||
Our children are only considered visible if we are, and similarly
|
||||
only if we do not ignore events.
|
||||
*/
|
||||
|
||||
vector<Item*> our_items;
|
||||
|
||||
if (!_items.empty()) {
|
||||
if (!_items.empty() && visible() && !_ignore_events) {
|
||||
ensure_lut ();
|
||||
our_items = _lut->items_at_point (point);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ Text::Text (Canvas* c)
|
|||
, _need_redraw (false)
|
||||
, _clamped_width (COORD_MAX)
|
||||
{
|
||||
_outline = false;
|
||||
}
|
||||
|
||||
Text::Text (Item* parent)
|
||||
|
|
@ -53,6 +54,7 @@ Text::Text (Item* parent)
|
|||
, _need_redraw (false)
|
||||
, _clamped_width (COORD_MAX)
|
||||
{
|
||||
_outline = false;
|
||||
}
|
||||
|
||||
Text::~Text ()
|
||||
|
|
@ -121,9 +123,17 @@ Text::_redraw (Glib::RefPtr<Pango::Layout> layout) const
|
|||
|
||||
/* and draw, in the appropriate color of course */
|
||||
|
||||
set_source_rgba (img_context, _color);
|
||||
|
||||
layout->show_in_cairo_context (img_context);
|
||||
if (_outline) {
|
||||
set_source_rgba (img_context, _outline_color);
|
||||
layout->update_from_cairo_context (img_context);
|
||||
pango_cairo_layout_path (img_context->cobj(), layout->gobj());
|
||||
img_context->stroke_preserve ();
|
||||
set_source_rgba (img_context, _color);
|
||||
img_context->fill ();
|
||||
} else {
|
||||
set_source_rgba (img_context, _color);
|
||||
layout->show_in_cairo_context (img_context);
|
||||
}
|
||||
|
||||
/* text has now been rendered in _image and is ready for blit in
|
||||
* ::render
|
||||
|
|
@ -211,6 +221,9 @@ Text::set_color (Color color)
|
|||
begin_change ();
|
||||
|
||||
_color = color;
|
||||
if (_outline) {
|
||||
set_outline_color (contrasting_text_color (_color));
|
||||
}
|
||||
_need_redraw = true;
|
||||
|
||||
end_change ();
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ TrackingText::init ()
|
|||
{
|
||||
_canvas->MouseMotion.connect (sigc::mem_fun (*this, &TrackingText::pointer_motion));
|
||||
set_ignore_events (true);
|
||||
set_outline (true);
|
||||
hide ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -220,3 +220,35 @@ ArdourCanvas::distance_to_segment_squared (Duple const & p, Duple const & p1, Du
|
|||
return ((dpqx * dpqx) + (dpqy * dpqy));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ArdourCanvas::contrasting_text_color (uint32_t c)
|
||||
{
|
||||
double r, g, b, a;
|
||||
ArdourCanvas::color_to_rgba (c, r, g, b, a);
|
||||
|
||||
const double black_r = 0.0;
|
||||
const double black_g = 0.0;
|
||||
const double black_b = 0.0;
|
||||
|
||||
const double white_r = 1.0;
|
||||
const double white_g = 1.0;
|
||||
const double white_b = 1.0;
|
||||
|
||||
/* Use W3C contrast guideline calculation */
|
||||
|
||||
double white_contrast = (max (r, white_r) - min (r, white_r)) +
|
||||
(max (g, white_g) - min (g, white_g)) +
|
||||
(max (b, white_b) - min (b, white_b));
|
||||
|
||||
double black_contrast = (max (r, black_r) - min (r, black_r)) +
|
||||
(max (g, black_g) - min (g, black_g)) +
|
||||
(max (b, black_b) - min (b, black_b));
|
||||
|
||||
if (white_contrast > black_contrast) {
|
||||
/* use white */
|
||||
return ArdourCanvas::rgba_to_color (1.0, 1.0, 1.0, 1.0);
|
||||
} else {
|
||||
/* use black */
|
||||
return ArdourCanvas::rgba_to_color (0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -279,6 +279,23 @@ EnumWriter::read_distinct (EnumRegistration& er, string str)
|
|||
vector<int>::iterator i;
|
||||
vector<string>::iterator s;
|
||||
|
||||
/* first, check to see if there a hack for the name we're looking up */
|
||||
|
||||
map<string,string>::iterator x;
|
||||
|
||||
if ((x = hack_table.find (str)) != hack_table.end()) {
|
||||
|
||||
cerr << "found hack for " << str << " = " << x->second << endl;
|
||||
|
||||
str = x->second;
|
||||
|
||||
for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
|
||||
if (str == (*s) || nocase_cmp (str, *s) == 0) {
|
||||
return (*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* catch old-style hex numerics */
|
||||
|
||||
if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
|
||||
|
|
@ -299,23 +316,6 @@ EnumWriter::read_distinct (EnumRegistration& er, string str)
|
|||
}
|
||||
}
|
||||
|
||||
/* failed to find it as-is. check to see if there a hack for the name we're looking up */
|
||||
|
||||
map<string,string>::iterator x;
|
||||
|
||||
if ((x = hack_table.find (str)) != hack_table.end()) {
|
||||
|
||||
cerr << "found hack for " << str << " = " << x->second << endl;
|
||||
|
||||
str = x->second;
|
||||
|
||||
for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
|
||||
if (str == (*s) || nocase_cmp (str, *s) == 0) {
|
||||
return (*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw unknown_enumeration(str);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue