Compare commits

...

13 Commits

Author SHA1 Message Date
Paul Davis 71b378e06a skinny up the lines used to draw the clock cursor 2015-09-24 11:14:53 -04:00
Paul Davis 90e1e37c31 fix clock sizing so that it is always large enough 2015-09-24 10:15:26 -04:00
Paul Davis c1a12a7efd adjust clock cursor position by x and y offsets used to position layout 2015-09-23 07:06:21 -04:00
Paul Davis 594f453093 change the way the audio clock cursor is drawn (somewhat of an experiment but it has some benefits 2015-09-22 18:25:14 -04:00
Paul Davis f1151118cc when editing an audio clock, swallow illegal keys rather than allowing them to reach the rest of the GUI 2015-09-22 18:24:49 -04:00
Paul Davis ef3a9daa72 fix the logic of the GUI "toggle roll" action as it pertains to loop recording 2015-09-22 13:25:06 -04:00
Paul Davis f11d919c3b a few new DEBUG_TRACE calls related to session transport state 2015-09-22 13:25:06 -04:00
Paul Davis a257fb6602 minor fix for possible off-by-one logic when at/near the end of the loop range 2015-09-22 13:25:06 -04:00
Paul Davis e40635b4b9 fix a long-standing bug arising from a change to some logic which reversed an "is-rolling" test 2015-09-22 13:25:06 -04:00
Paul Davis fc685ceb2b move code location where loop playback is cancelled when stopping 2015-09-22 13:25:06 -04:00
Paul Davis 98743d510e loop record is a feature whether or not loop-is-mode is true or not 2015-09-22 13:25:06 -04:00
Paul Davis 18d9ee69ca Session::disable_record() should work whether we are in loop mode or not 2015-09-22 13:25:06 -04:00
Paul Davis 7041b04c69 add new action and loop marker menu item for setting up loop record 2015-09-22 13:25:06 -04:00
8 changed files with 185 additions and 75 deletions

View File

@ -2080,17 +2080,26 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
if (rolling && roll_out_of_bounded_mode) {
/* drop out of loop/range playback but leave transport rolling */
if (_session->get_play_loop()) {
if (Config->get_seamless_loop()) {
/* the disk buffers contain copies of the loop - we can't
just keep playing, so stop the transport. the user
can restart as they wish.
*/
affect_transport = true;
if (_session->actively_recording()) {
/* just stop using the loop, then actually stop
* below
*/
_session->request_play_loop (false, affect_transport);
} else {
/* disk buffers are normal, so we can keep playing */
affect_transport = false;
if (Config->get_seamless_loop()) {
/* the disk buffers contain copies of the loop - we can't
just keep playing, so stop the transport. the user
can restart as they wish.
*/
affect_transport = true;
} else {
/* disk buffers are normal, so we can keep playing */
affect_transport = false;
}
_session->request_play_loop (false, affect_transport);
}
_session->request_play_loop (false, affect_transport);
} else if (_session->get_play_range ()) {
affect_transport = false;
_session->request_play_range (0, true);

View File

@ -197,6 +197,7 @@ AudioClock::set_font (Pango::FontDescription font)
tmp->set_text ("8");
tmp->get_pixel_size (em_width, ignore_height);
/* force redraw of markup with new font-size */
set (last_when, true);
@ -312,15 +313,80 @@ AudioClock::render (cairo_t* cr, cairo_rectangle_t*)
double lw = layout_width * xscale;
double lh = layout_height * yscale;
cairo_move_to (cr, (get_width() - lw) / 2.0, (upper_height - lh) / 2.0);
double layout_x_offset;
double layout_y_offset = (upper_height - lh) / 2.0;
if (lw >= get_width()) {
layout_x_offset = 0.0;
} else {
layout_x_offset = get_width() - lw;
}
/* convert these back to unscaled units since we're going to use cairo
scaling for a bit.
*/
layout_x_offset /= xscale;
layout_y_offset /= xscale;
if (xscale != 1.0 || yscale != 1.0) {
cairo_save (cr);
cairo_scale (cr, xscale, yscale);
}
/* show the actual clock layout */
cairo_move_to (cr, layout_x_offset, layout_y_offset);
pango_cairo_show_layout (cr, _layout->gobj());
if (editing) {
Pango::Rectangle cursor;
const double scaled_x_half_pixel = 0.5/xscale;
const double scaled_y_half_pixel = 0.5/yscale;
if (!insert_map.empty()) {
if (input_string.length() < insert_map.size()) {
cursor = _layout->get_cursor_strong_pos (edit_string.length() - 1);
cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a);
cairo_set_line_width (cr, (1.0/xscale));
cairo_rectangle (cr,
layout_x_offset + (cursor.get_x()/PANGO_SCALE) + scaled_x_half_pixel,
layout_y_offset + scaled_y_half_pixel,
em_width,
layout_height - (1.0/yscale));
cairo_stroke (cr);
} else {
/* we've entered all possible digits, no cursor */
}
} else {
cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a);
if (edit_string.empty()) {
cairo_rectangle (cr,
layout_x_offset + get_width() - em_width + scaled_x_half_pixel,
layout_y_offset + scaled_y_half_pixel,
em_width,
upper_height - layout_y_offset - (1.0/yscale));
} else {
cursor = _layout->get_cursor_strong_pos (edit_string.length() - 1);
cairo_rectangle (cr,
layout_x_offset + (cursor.get_x()/PANGO_SCALE) + scaled_x_half_pixel,
layout_y_offset + scaled_y_half_pixel,
em_width,
upper_height - layout_y_offset - (1.0/yscale));
}
cairo_stroke (cr);
}
}
if (xscale != 1.0 || yscale != 1.0) {
cairo_restore (cr);
}
@ -400,45 +466,6 @@ AudioClock::render (cairo_t* cr, cairo_rectangle_t*)
}
}
if (editing) {
if (!insert_map.empty()) {
int xcenter = (get_width() - layout_width) /2;
if (input_string.length() < insert_map.size()) {
Pango::Rectangle cursor;
if (input_string.empty()) {
/* nothing entered yet, put cursor at the end
of string
*/
cursor = _layout->get_cursor_strong_pos (edit_string.length() - 1);
} else {
cursor = _layout->get_cursor_strong_pos (insert_map[input_string.length()]);
}
cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a);
cairo_rectangle (cr,
min (get_width() - 2.0,
(double) xcenter + cursor.get_x()/PANGO_SCALE + em_width),
(upper_height - layout_height)/2.0,
2.0, cursor.get_height()/PANGO_SCALE);
cairo_fill (cr);
} else {
/* we've entered all possible digits, no cursor */
}
} else {
if (input_string.empty()) {
cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a);
cairo_rectangle (cr,
(get_width()/2.0),
(upper_height - layout_height)/2.0,
2.0, upper_height);
cairo_fill (cr);
}
}
}
}
void
@ -471,14 +498,21 @@ AudioClock::set_clock_dimensions (Gtk::Requisition& req)
tmp->set_font_description (font);
/* this string is the longest thing we will ever display */
if (_mode == MinSec)
tmp->set_text (" 88:88:88,888 ");
else
tmp->set_text (" 88:88:88,88 ");
tmp->set_text (" 88:88:88,888 ");
tmp->get_pixel_size (req.width, req.height);
layout_height = req.height;
layout_width = req.width;
/* get the figure width for the font. This doesn't have to super
* accurate since we only use it to measure the (roughly 1 character)
* offset from the position Pango tells us for the "cursor"
*/
int ignore_height;
tmp->set_text ("8");
tmp->get_pixel_size (em_width, ignore_height);
}
void
@ -1419,7 +1453,10 @@ AudioClock::on_key_press_event (GdkEventKey* ev)
goto use_input_string;
default:
return false;
/* do not allow other keys to passthru to the rest of the GUI
when editing.
*/
return true;
}
if (!insert_map.empty() && (input_string.length() >= insert_map.size())) {

View File

@ -1457,7 +1457,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void set_loop_from_selection (bool play);
void set_punch_from_selection ();
void set_punch_from_region ();
void set_punch_from_loop ();
void setup_loop_record ();
void set_session_start_from_playhead ();
void set_session_end_from_playhead ();
void set_session_extents_from_selection ();
@ -1684,7 +1687,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void marker_context_menu (GdkEventButton*, ArdourCanvas::Item*);
void tempo_or_meter_marker_context_menu (GdkEventButton*, ArdourCanvas::Item*);
void new_transport_marker_context_menu (GdkEventButton*, ArdourCanvas::Item*);
void build_range_marker_menu (bool, bool);
void build_range_marker_menu (bool, bool, bool);
void build_marker_menu (ARDOUR::Location *);
void build_tempo_or_meter_marker_menu (bool);
void build_new_transport_marker_menu ();

View File

@ -306,6 +306,9 @@ Editor::register_actions ()
reg_sens (editor_actions, "set-punch-from-edit-range", _("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection));
reg_sens (editor_actions, "set-session-from-edit-range", _("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection));
reg_sens (editor_actions, "set-punch-from-loop", _("Set Punch from Loop"), sigc::mem_fun(*this, &Editor::set_punch_from_loop));
reg_sens (editor_actions, "setup-loop-record", _("Setup Loop Record"), sigc::mem_fun(*this, &Editor::setup_loop_record));
/* this is a duplicated action so that the main menu can use a different label */
reg_sens (editor_actions, "main-menu-play-selected-regions", _("Play Selected Regions"), sigc::mem_fun (*this, &Editor::play_selected_region));
reg_sens (editor_actions, "play-from-edit-point", _("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point));

View File

@ -827,7 +827,7 @@ Editor::marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
if (loc == transport_loop_location() || loc == transport_punch_location() || loc->is_session_range ()) {
if (transport_marker_menu == 0) {
build_range_marker_menu (loc == transport_loop_location() || loc == transport_punch_location(), loc->is_session_range());
build_range_marker_menu (loc == transport_loop_location(), loc == transport_punch_location(), loc->is_session_range());
}
marker_menu_item = item;
@ -857,7 +857,7 @@ Editor::marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
} else if (loc->is_range_marker()) {
if (range_marker_menu == 0) {
build_range_marker_menu (false, false);
build_range_marker_menu (false, false, false);
}
marker_menu_item = item;
range_marker_menu->popup (1, ev->time);
@ -915,11 +915,11 @@ Editor::build_marker_menu (Location* loc)
}
void
Editor::build_range_marker_menu (bool loop_or_punch, bool session)
Editor::build_range_marker_menu (bool loop, bool punch, bool session)
{
using namespace Menu_Helpers;
bool const loop_or_punch_or_session = loop_or_punch | session;
bool const loop_or_punch_or_session = loop | punch | session;
Menu *markerMenu = new Menu;
if (loop_or_punch_or_session) {
@ -933,7 +933,12 @@ Editor::build_range_marker_menu (bool loop_or_punch, bool session)
items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::marker_menu_play_range)));
items.push_back (MenuElem (_("Locate to Marker"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead)));
items.push_back (MenuElem (_("Play from Marker"), sigc::mem_fun(*this, &Editor::marker_menu_play_from)));
items.push_back (MenuElem (_("Loop Range"), sigc::mem_fun(*this, &Editor::marker_menu_loop_range)));
if (!loop) {
items.push_back (MenuElem (_("Loop Range"), sigc::mem_fun(*this, &Editor::marker_menu_loop_range)));
} else {
items.push_back (MenuElem (_("Setup Loop Record"), sigc::mem_fun(*this, &Editor::setup_loop_record)));
}
items.push_back (MenuElem (_("Set Marker from Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
if (!Profile->get_sae()) {

View File

@ -6265,6 +6265,60 @@ Editor::set_punch_from_selection ()
set_punch_range (start, end, _("set punch range from selection"));
}
void
Editor::set_punch_from_loop ()
{
if (_session == 0) {
return;
}
Location* tll;
if ((tll = transport_loop_location()) == 0) {
return;
}
set_punch_range (tll->start(), tll->end(), _("set punch range from loop"));
}
void
Editor::setup_loop_record ()
{
if (_session == 0) {
return;
}
Location * looploc = _session->locations()->auto_loop_location();
if (!looploc) {
return;
}
set_punch_range (looploc->start(), looploc->end(), _("setup loop recording"));
Glib::RefPtr<Action> action = ActionManager::get_action ("Transport", "TogglePunch");
if (action) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action);
if (!tact) {
return;
}
/* drive the other two actions from this one */
Glib::RefPtr<Action> in_action = ActionManager::get_action ("Transport", "TogglePunchIn");
Glib::RefPtr<Action> out_action = ActionManager::get_action ("Transport", "TogglePunchOut");
if (in_action && out_action) {
Glib::RefPtr<ToggleAction> tiact = Glib::RefPtr<ToggleAction>::cast_dynamic(in_action);
Glib::RefPtr<ToggleAction> toact = Glib::RefPtr<ToggleAction>::cast_dynamic(out_action);
tiact->set_active (true);
toact->set_active (true);
}
}
}
void
Editor::set_session_extents_from_selection ()
{

View File

@ -1817,7 +1817,7 @@ Session::disable_record (bool rt_context, bool force)
if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) {
if ((!Config->get_latched_record_enable () && !play_loop) || force) {
if (!Config->get_latched_record_enable () || force) {
g_atomic_int_set (&_record_status, Disabled);
send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit));
} else {
@ -1868,11 +1868,6 @@ Session::maybe_enable_record ()
save_state ("", true);
if (Config->get_loop_is_mode()) {
/* makes no sense to use loop play as mode when recording */
request_play_loop (false);
}
if (_transport_speed) {
if (!config.get_punch_in()) {
enable_record ();

View File

@ -283,6 +283,10 @@ Session::realtime_stop (bool abort, bool clear_state)
/* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
disable_record (true, (!Config->get_latched_record_enable() && clear_state));
if (clear_state && !Config->get_loop_is_mode()) {
unset_play_loop ();
}
reset_slave_state ();
_transport_speed = 0;
@ -1108,8 +1112,8 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
*/
bool transport_was_stopped = !transport_rolling();
if (transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_engine() && play_loop) &&
if (!transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_engine() && play_loop) &&
(!Profile->get_trx() || !(config.get_external_sync() && !synced_to_engine()))) {
realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
transport_was_stopped = true;
@ -1163,7 +1167,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
Location* al = _locations->auto_loop_location();
if (al) {
if (_transport_frame < al->start() || _transport_frame > al->end()) {
if (_transport_frame < al->start() || _transport_frame >= al->end()) {
// located outside the loop: cancel looping directly, this is called from event handling context
@ -1299,10 +1303,6 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
stop_transport (abort);
}
if (!Config->get_loop_is_mode()) {
unset_play_loop ();
}
} else if (transport_stopped() && speed == 1.0) {
/* we are stopped and we want to start rolling at speed 1 */
@ -1429,6 +1429,8 @@ Session::stop_transport (bool abort, bool clear_state)
return;
}
DEBUG_TRACE (DEBUG::Transport, string_compose ("stop_transport, declick required? %1\n", get_transport_declick_required()));
if (!get_transport_declick_required()) {
/* stop has not yet been scheduled */
@ -1481,8 +1483,8 @@ Session::stop_transport (bool abort, bool clear_state)
/* Not recording, schedule a declick in the next process() cycle and then stop at its end */
new_bits = PendingDeclickOut;
DEBUG_TRACE (DEBUG::Transport, string_compose ("stop scheduled for next process cycle @ %1\n", _transport_frame));
}
/* we'll be called again after the declick */
transport_sub_state = SubState (transport_sub_state|new_bits);
@ -1491,6 +1493,8 @@ Session::stop_transport (bool abort, bool clear_state)
return;
} else {
DEBUG_TRACE (DEBUG::Transport, "time to actually stop\n");
/* declick was scheduled, but we've been called again, which means it is really time to stop