mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-16 03:36:32 +01:00
Revert "refactor pianoroll/cueeditor/audioclipeditor to share code and do the right stuff (compile success stage)"
This reverts commit 01beb00a5f.
This commit is contained in:
parent
01beb00a5f
commit
7be70d658b
20 changed files with 1238 additions and 1339 deletions
|
|
@ -1852,6 +1852,17 @@ ARDOUR_UI::get_smart_mode() const
|
|||
void
|
||||
ARDOUR_UI::spacebar_action (bool with_abort, bool roll_out_of_bounded_mode)
|
||||
{
|
||||
if (!_session) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<TriggerBox> armed_tb = _session->armed_triggerbox();
|
||||
|
||||
if (armed_tb && _session->transport_rolling()) {
|
||||
armed_tb->disarm_all ();
|
||||
return;
|
||||
}
|
||||
|
||||
toggle_roll (with_abort, roll_out_of_bounded_mode);
|
||||
}
|
||||
|
||||
|
|
@ -1881,10 +1892,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
|
|||
|
||||
if (rolling) {
|
||||
|
||||
std::cerr << "TR rolling\n";
|
||||
|
||||
if (roll_out_of_bounded_mode) {
|
||||
std::cerr << "roobm\n";
|
||||
/* drop out of loop/range playback but leave transport rolling */
|
||||
|
||||
if (_session->get_play_loop()) {
|
||||
|
|
@ -1906,7 +1914,6 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
|
|||
}
|
||||
|
||||
} else {
|
||||
std::cerr << "stip\n";
|
||||
_session->request_stop (with_abort, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ ARDOUR_UI::we_have_dependents ()
|
|||
mixer->monitor_section().use_others_actions ();
|
||||
|
||||
StepEntry::setup_actions_and_bindings ();
|
||||
ClipEditorBox::init ();
|
||||
RegionEditor::setup_actions_and_bindings ();
|
||||
|
||||
setup_action_tooltips ();
|
||||
|
|
|
|||
|
|
@ -41,15 +41,12 @@
|
|||
#include "widgets/ardour_button.h"
|
||||
#include "widgets/ardour_icon.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "audio_clip_editor.h"
|
||||
#include "audio_clock.h"
|
||||
#include "editor_automation_line.h"
|
||||
#include "editor_cursors.h"
|
||||
#include "control_point.h"
|
||||
#include "editor.h"
|
||||
#include "region_view.h"
|
||||
#include "verbose_cursor.h"
|
||||
#include "ui_config.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
|
@ -63,6 +60,27 @@ using namespace ArdourWidgets;
|
|||
using std::max;
|
||||
using std::min;
|
||||
|
||||
Glib::RefPtr<Gtk::ActionGroup> ClipEditorBox::clip_editor_actions;
|
||||
|
||||
void
|
||||
ClipEditorBox::init ()
|
||||
{
|
||||
Bindings* bindings = Bindings::get_bindings (X_("Clip Editing"));
|
||||
|
||||
register_clip_editor_actions (bindings);
|
||||
}
|
||||
|
||||
void
|
||||
ClipEditorBox::register_clip_editor_actions (Bindings* clip_editor_bindings)
|
||||
{
|
||||
clip_editor_actions = ActionManager::create_action_group (clip_editor_bindings, X_("ClipEditing"));
|
||||
|
||||
/* two versions to allow same action for Delete and Backspace */
|
||||
|
||||
// ActionManager::register_action (clip_editor_actions, X_("zoom-in"), _("Zoom In"), sigc::mem_fun (*this, &ClipEditorBox::zoom_in));
|
||||
// ActionManager::register_action (clip_editor_actions, X_("zoom-in"), _("Zoom In"), sigc::mem_fun (*this, &ClipEditorBox::zoom_out));
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::ClipBBTMetric::get_marks (std::vector<ArdourCanvas::Ruler::Mark>& marks, int64_t lower, int64_t upper, int maxchars) const
|
||||
{
|
||||
|
|
@ -103,133 +121,46 @@ AudioClipEditor::ClipBBTMetric::get_marks (std::vector<ArdourCanvas::Ruler::Mark
|
|||
}
|
||||
}
|
||||
|
||||
AudioClipEditor::AudioClipEditor (std::string const & name, bool with_transport)
|
||||
: CueEditor (name, with_transport)
|
||||
, _viewport (horizontal_adjustment, vertical_adjustment)
|
||||
, canvas (*_viewport.canvas())
|
||||
, clip_metric (nullptr)
|
||||
AudioClipEditor::AudioClipEditor ()
|
||||
: clip_metric (0)
|
||||
, _spp (0)
|
||||
, scroll_fraction (0)
|
||||
, current_line_drag (0)
|
||||
, current_scroll_drag (0)
|
||||
{
|
||||
build_upper_toolbar ();
|
||||
build_canvas ();
|
||||
}
|
||||
const double scale = UIConfiguration::instance ().get_ui_scale ();
|
||||
|
||||
void
|
||||
AudioClipEditor::pack_inner (Gtk::Box& box)
|
||||
{
|
||||
box.pack_start (snap_box, false, false);
|
||||
box.pack_start (grid_box, false, false);
|
||||
box.pack_start (draw_box, false, false);
|
||||
}
|
||||
frame = new ArdourCanvas::Rectangle (root ());
|
||||
frame->name = "audio clip editor frame";
|
||||
frame->set_fill (false);
|
||||
frame->Event.connect (sigc::mem_fun (*this, &AudioClipEditor::event_handler));
|
||||
|
||||
void
|
||||
AudioClipEditor::pack_outer (Gtk::Box& box)
|
||||
{
|
||||
if (with_transport_controls) {
|
||||
box.pack_start (play_box, false, false);
|
||||
}
|
||||
/* Scroll bar does not scroll and it outside the frame */
|
||||
|
||||
box.pack_start (rec_box, false, false);
|
||||
box.pack_start (follow_playhead_button, false, false);
|
||||
}
|
||||
scroll_bar_trough = new ArdourCanvas::Rectangle (root ());
|
||||
scroll_bar_handle = new ArdourCanvas::Rectangle (scroll_bar_trough);
|
||||
scroll_bar_handle->set_outline (false);
|
||||
scroll_bar_handle->set_corner_radius (5.);
|
||||
scroll_bar_handle->Event.connect (sigc::mem_fun (*this, &AudioClipEditor::scroll_event_handler));
|
||||
scroll_bar_handle->disable_scroll_translation ();
|
||||
|
||||
void
|
||||
AudioClipEditor::build_lower_toolbar ()
|
||||
{
|
||||
horizontal_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &CueEditor::scrolled));
|
||||
_canvas_hscrollbar = manage (new Gtk::HScrollbar (horizontal_adjustment));
|
||||
/* A scrolling container for our waves and lines etc. */
|
||||
|
||||
_toolbox.pack_start (*_canvas_hscrollbar, false, false);
|
||||
_toolbox.pack_start (button_bar, false, false);
|
||||
}
|
||||
waves_container = new ArdourCanvas::ScrollGroup (frame, ScrollGroup::ScrollsHorizontally);
|
||||
add_scroller (*waves_container);
|
||||
|
||||
void
|
||||
AudioClipEditor::build_canvas ()
|
||||
{
|
||||
canvas.set_background_color (UIConfiguration::instance().color ("arrange base"));
|
||||
canvas.signal_event().connect (sigc::mem_fun (*this, &CueEditor::canvas_pre_event), false);
|
||||
canvas.use_nsglview (UIConfiguration::instance().get_nsgl_view_mode () == NSGLHiRes);
|
||||
|
||||
canvas.PreRender.connect (sigc::mem_fun(*this, &EditingContext::pre_render));
|
||||
|
||||
/* scroll group for items that should not automatically scroll
|
||||
* (e.g verbose cursor). It shares the canvas coordinate space.
|
||||
*/
|
||||
no_scroll_group = new ArdourCanvas::Container (canvas.root());
|
||||
|
||||
h_scroll_group = new ArdourCanvas::ScrollGroup (canvas.root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
|
||||
CANVAS_DEBUG_NAME (h_scroll_group, "audioclip h scroll");
|
||||
canvas.add_scroller (*h_scroll_group);
|
||||
|
||||
|
||||
v_scroll_group = new ArdourCanvas::ScrollGroup (canvas.root(), ArdourCanvas::ScrollGroup::ScrollsVertically);
|
||||
CANVAS_DEBUG_NAME (v_scroll_group, "audioclip v scroll");
|
||||
canvas.add_scroller (*v_scroll_group);
|
||||
|
||||
hv_scroll_group = new ArdourCanvas::ScrollGroup (canvas.root(),
|
||||
ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
|
||||
ArdourCanvas::ScrollGroup::ScrollsHorizontally));
|
||||
CANVAS_DEBUG_NAME (hv_scroll_group, "audioclip hv scroll");
|
||||
canvas.add_scroller (*hv_scroll_group);
|
||||
|
||||
cursor_scroll_group = new ArdourCanvas::ScrollGroup (canvas.root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
|
||||
CANVAS_DEBUG_NAME (cursor_scroll_group, "audioclip cursor scroll");
|
||||
canvas.add_scroller (*cursor_scroll_group);
|
||||
|
||||
/*a group to hold global rects like punch/loop indicators */
|
||||
global_rect_group = new ArdourCanvas::Container (hv_scroll_group);
|
||||
CANVAS_DEBUG_NAME (global_rect_group, "audioclip global rect group");
|
||||
|
||||
transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
|
||||
CANVAS_DEBUG_NAME (transport_loop_range_rect, "audioclip loop rect");
|
||||
transport_loop_range_rect->hide();
|
||||
|
||||
/*a group to hold time (measure) lines */
|
||||
time_line_group = new ArdourCanvas::Container (h_scroll_group);
|
||||
CANVAS_DEBUG_NAME (time_line_group, "audioclip time line group");
|
||||
|
||||
n_timebars = 0;
|
||||
minsec_ruler = new ArdourCanvas::Ruler (time_line_group, clip_metric, ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height));
|
||||
// minsec_ruler->set_name ("audio clip editor ruler");
|
||||
minsec_ruler->set_font_description (UIConfiguration::instance ().get_SmallerFont ());
|
||||
minsec_ruler->set_fill_color (UIConfiguration::instance().color (X_("theme:bg1")));
|
||||
minsec_ruler->set_outline_color (UIConfiguration::instance().color (X_("theme:contrasting less")));
|
||||
n_timebars++;
|
||||
|
||||
minsec_ruler->Event.connect (sigc::mem_fun (*this, &AudioClipEditor::minsec_ruler_event));
|
||||
|
||||
data_group = new ArdourCanvas::Container (hv_scroll_group);
|
||||
CANVAS_DEBUG_NAME (data_group, "cue data group");
|
||||
|
||||
data_group->set_position (ArdourCanvas::Duple (_timeline_origin, timebar_height * n_timebars));
|
||||
no_scroll_group->set_position (ArdourCanvas::Duple (_timeline_origin, timebar_height * n_timebars));
|
||||
cursor_scroll_group->set_position (ArdourCanvas::Duple (_timeline_origin, timebar_height * n_timebars));
|
||||
h_scroll_group->set_position (Duple (_timeline_origin, 0.));
|
||||
|
||||
_verbose_cursor = new VerboseCursor (*this);
|
||||
|
||||
// _playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event, X_("playhead"));
|
||||
_playhead_cursor = new EditorCursor (*this, X_("playhead"));
|
||||
_playhead_cursor->set_sensitive (UIConfiguration::instance().get_sensitize_playhead());
|
||||
_playhead_cursor->set_color (UIConfiguration::instance().color ("play head"));
|
||||
_playhead_cursor->canvas_item().raise_to_top();
|
||||
h_scroll_group->raise_to_top ();
|
||||
|
||||
canvas.set_name ("AudioClipCanvas");
|
||||
canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
|
||||
canvas.set_can_focus ();
|
||||
canvas.signal_show().connect (sigc::mem_fun (*this, &CueEditor::catch_pending_show_region));
|
||||
_viewport.signal_size_allocate().connect (sigc::mem_fun(*this, &AudioClipEditor::canvas_allocate), false);
|
||||
|
||||
_toolbox.pack_start (_viewport, true, true);
|
||||
ruler_container = new ArdourCanvas::Container (waves_container);
|
||||
ruler = new ArdourCanvas::Ruler (ruler_container, 0);
|
||||
ruler->name = "Clip Editor";
|
||||
ruler->set_font_description (UIConfiguration::instance ().get_SmallerFont ());
|
||||
ruler->set_fill_color (UIConfiguration::instance().color (X_("theme:bg1")));
|
||||
ruler->set_outline_color (UIConfiguration::instance().color (X_("theme:contrasting less")));
|
||||
|
||||
/* the lines */
|
||||
|
||||
line_container = new ArdourCanvas::Container (data_group);
|
||||
line_container = new ArdourCanvas::Container (waves_container);
|
||||
|
||||
const double line_width = 3.;
|
||||
double scale = UIConfiguration::instance().get_ui_scale();
|
||||
|
||||
start_line = new Line (line_container);
|
||||
start_line->set_outline_width (line_width * scale);
|
||||
|
|
@ -291,6 +222,41 @@ AudioClipEditor::line_event_handler (GdkEvent* ev, ArdourCanvas::Line* l)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioClipEditor::scroll_event_handler (GdkEvent* ev)
|
||||
{
|
||||
switch (ev->type) {
|
||||
case GDK_BUTTON_PRESS:
|
||||
current_scroll_drag = new ScrollDrag (*this);
|
||||
current_scroll_drag->begin (&ev->button);
|
||||
return true;
|
||||
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (current_scroll_drag) {
|
||||
current_scroll_drag->end (&ev->button);
|
||||
delete current_scroll_drag;
|
||||
current_scroll_drag = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (current_scroll_drag) {
|
||||
current_scroll_drag->motion (&ev->motion);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GDK_KEY_PRESS:
|
||||
return key_press (&ev->key);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioClipEditor::key_press (GdkEventKey* ev)
|
||||
{
|
||||
|
|
@ -311,6 +277,18 @@ AudioClipEditor::position_lines ()
|
|||
end_line->set_x1 (sample_to_pixel (audio_region->end ().samples ()));
|
||||
}
|
||||
|
||||
double
|
||||
AudioClipEditor::sample_to_pixel (samplepos_t s)
|
||||
{
|
||||
return round (s / _spp);
|
||||
}
|
||||
|
||||
samplepos_t
|
||||
AudioClipEditor::pixel_to_sample (double p)
|
||||
{
|
||||
return round (p * _spp);
|
||||
}
|
||||
|
||||
AudioClipEditor::LineDrag::LineDrag (AudioClipEditor& ed, ArdourCanvas::Line& l)
|
||||
: editor (ed)
|
||||
, line (l)
|
||||
|
|
@ -339,15 +317,78 @@ AudioClipEditor::LineDrag::motion (GdkEventMotion* ev)
|
|||
void
|
||||
AudioClipEditor::set_colors ()
|
||||
{
|
||||
canvas.set_background_color (UIConfiguration::instance ().color (X_("theme:bg")));
|
||||
set_background_color (UIConfiguration::instance ().color (X_("theme:bg")));
|
||||
|
||||
frame->set_outline_color (UIConfiguration::instance ().color (X_("neutral:midground")));
|
||||
|
||||
start_line->set_outline_color (UIConfiguration::instance ().color (X_("theme:contrasting clock")));
|
||||
end_line->set_outline_color (UIConfiguration::instance ().color (X_("theme:contrasting alt")));
|
||||
loop_line->set_outline_color (UIConfiguration::instance ().color (X_("theme:contrasting selection")));
|
||||
|
||||
scroll_bar_trough->set_fill_color (UIConfiguration::instance ().color (X_("theme:bg")));
|
||||
scroll_bar_trough->set_outline_color (UIConfiguration::instance ().color (X_("theme:contrasting less")));
|
||||
scroll_bar_handle->set_fill_color (UIConfiguration::instance ().color (X_("theme:contrasting clock")));
|
||||
|
||||
set_waveform_colors ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::scroll_changed ()
|
||||
{
|
||||
if (!audio_region) {
|
||||
return;
|
||||
}
|
||||
|
||||
const double right_edge = scroll_bar_handle->get ().x0;
|
||||
const double avail_width = scroll_bar_trough->get ().width () - scroll_bar_handle->get ().width ();
|
||||
scroll_fraction = right_edge / avail_width;
|
||||
scroll_fraction = std::min (1., std::max (0., scroll_fraction));
|
||||
const samplepos_t s = llrintf (audio_region->source (0)->length ().samples () * scroll_fraction);
|
||||
|
||||
ruler->set_range (s, s + pixel_to_sample (frame->get().width() - 2.));
|
||||
|
||||
scroll_to (sample_to_pixel (s), 0);
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
AudioClipEditor::ScrollDrag::ScrollDrag (AudioClipEditor& e)
|
||||
: editor (e)
|
||||
{
|
||||
e.scroll_bar_handle->grab ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::ScrollDrag::begin (GdkEventButton* ev)
|
||||
{
|
||||
last_x = ev->x;
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::ScrollDrag::end (GdkEventButton* ev)
|
||||
{
|
||||
editor.scroll_bar_handle->ungrab ();
|
||||
editor.scroll_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::ScrollDrag::motion (GdkEventMotion* ev)
|
||||
{
|
||||
ArdourCanvas::Rectangle& r (*editor.scroll_bar_handle);
|
||||
const double xdelta = ev->x - last_x;
|
||||
ArdourCanvas::Rect n (r.get ());
|
||||
const double handle_width = n.width ();
|
||||
const double avail_width = editor.scroll_bar_trough->get ().width () - handle_width;
|
||||
|
||||
n.x0 = std::max (0., std::min (avail_width, n.x0 + xdelta));
|
||||
n.x1 = n.x0 + handle_width;
|
||||
|
||||
r.set (n);
|
||||
last_x = ev->x;
|
||||
|
||||
editor.scroll_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::drop_waves ()
|
||||
{
|
||||
|
|
@ -359,50 +400,12 @@ AudioClipEditor::drop_waves ()
|
|||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::set_region (std::shared_ptr<ARDOUR::Region> r)
|
||||
{
|
||||
set_region (std::dynamic_pointer_cast<ARDOUR::AudioRegion> (r));
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::set_trigger (TriggerReference& tr)
|
||||
{
|
||||
TriggerPtr trigger (tr.trigger());
|
||||
|
||||
if (trigger == ref.trigger()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ref = tr;
|
||||
|
||||
std::shared_ptr<AudioTrigger> at = std::dynamic_pointer_cast<AudioTrigger> (trigger);
|
||||
if (at) {
|
||||
minsec_ruler->show ();
|
||||
minsec_ruler->set_range (0, pixel_to_sample (_visible_canvas_width - 2.));
|
||||
} else {
|
||||
minsec_ruler->hide ();
|
||||
}
|
||||
|
||||
if (ref.trigger()->the_region()) {
|
||||
std::shared_ptr<AudioRegion> ar = std::dynamic_pointer_cast<AudioRegion> (ref.trigger()->the_region());
|
||||
if (ar) {
|
||||
set_region (ar);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::set_region (std::shared_ptr<AudioRegion> r)
|
||||
AudioClipEditor::set_region (std::shared_ptr<AudioRegion> r, TriggerReference tr)
|
||||
{
|
||||
drop_waves ();
|
||||
|
||||
audio_region = r;
|
||||
|
||||
if (!audio_region) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ruler has to reflect tempo of the region, so we have to recreate it
|
||||
* every time. Note that we retain ownership of the metric, and that
|
||||
* because the GUI is single-threaded, we can set it and delete it
|
||||
|
|
@ -411,8 +414,8 @@ AudioClipEditor::set_region (std::shared_ptr<AudioRegion> r)
|
|||
*/
|
||||
|
||||
delete clip_metric;
|
||||
clip_metric = new ClipBBTMetric (ref);
|
||||
minsec_ruler->set_metric (clip_metric);
|
||||
clip_metric = new ClipBBTMetric (tr);
|
||||
ruler->set_metric (clip_metric);
|
||||
|
||||
uint32_t n_chans = r->n_channels ();
|
||||
samplecnt_t len;
|
||||
|
|
@ -430,7 +433,7 @@ AudioClipEditor::set_region (std::shared_ptr<AudioRegion> r)
|
|||
continue;
|
||||
}
|
||||
|
||||
WaveView* wv = new WaveView (data_group, war);
|
||||
WaveView* wv = new WaveView (waves_container, war);
|
||||
wv->set_channel (n);
|
||||
wv->set_show_zero_line (false);
|
||||
wv->set_clip_level (1.0);
|
||||
|
|
@ -439,44 +442,75 @@ AudioClipEditor::set_region (std::shared_ptr<AudioRegion> r)
|
|||
waves.push_back (wv);
|
||||
}
|
||||
|
||||
TriggerPtr trigger (tr.trigger());
|
||||
std::shared_ptr<AudioTrigger> at = std::dynamic_pointer_cast<AudioTrigger> (trigger);
|
||||
if (at) {
|
||||
if (at->segment_tempo() == 0.) {
|
||||
/* tempo unknown, hide ruler */
|
||||
ruler->hide ();
|
||||
} else {
|
||||
ruler->show ();
|
||||
ruler->set_range (0, pixel_to_sample (frame->get().width() - 2.));
|
||||
}
|
||||
} else {
|
||||
ruler->hide ();
|
||||
}
|
||||
set_spp_from_length (len);
|
||||
set_wave_heights ();
|
||||
set_waveform_colors ();
|
||||
|
||||
line_container->show ();
|
||||
line_container->raise_to_top ();
|
||||
|
||||
set_session (&r->session ());
|
||||
state_connection.disconnect ();
|
||||
|
||||
PBD::PropertyChange interesting_stuff;
|
||||
region_changed (interesting_stuff);
|
||||
audio_region->PropertyChanged.connect (state_connection, invalidator (*this), std::bind (&AudioClipEditor::region_changed, this, _1), gui_context ());
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::canvas_allocate (Gtk::Allocation& alloc)
|
||||
AudioClipEditor::on_size_allocate (Gtk::Allocation& alloc)
|
||||
{
|
||||
canvas.size_allocate (alloc);
|
||||
GtkCanvas::on_size_allocate (alloc);
|
||||
|
||||
_visible_canvas_width = alloc.get_width();
|
||||
_visible_canvas_height = alloc.get_height();
|
||||
ArdourCanvas::Rect r (1, 1, alloc.get_width () - 2, alloc.get_height () - 2);
|
||||
frame->set (r);
|
||||
|
||||
minsec_ruler->set (ArdourCanvas::Rect (2, 2, alloc.get_width() - 4, timebar_height));
|
||||
const double ruler_height = 25.;
|
||||
ruler->set (ArdourCanvas::Rect (2, 2, alloc.get_width() - 4, ruler_height));
|
||||
|
||||
const double scroll_bar_height = 10.;
|
||||
const double scroll_bar_width = alloc.get_width () - 2;
|
||||
const double scroll_bar_handle_left = scroll_bar_width * scroll_fraction;
|
||||
|
||||
scroll_bar_trough->set (ArdourCanvas::Rect (1, alloc.get_height () - scroll_bar_height, scroll_bar_width, alloc.get_height ()));
|
||||
scroll_bar_handle->set (ArdourCanvas::Rect (scroll_bar_handle_left, scroll_bar_trough->get ().y0 + 1, scroll_bar_handle_left + 30., scroll_bar_trough->get ().y1 - 1));
|
||||
|
||||
position_lines ();
|
||||
|
||||
start_line->set_y1 (_visible_canvas_height - 2.);
|
||||
end_line->set_y1 (_visible_canvas_height - 2.);
|
||||
loop_line->set_y1 (_visible_canvas_height - 2.);
|
||||
start_line->set_y1 (frame->get ().height () - 2. - scroll_bar_height);
|
||||
end_line->set_y1 (frame->get ().height () - 2. - scroll_bar_height);
|
||||
loop_line->set_y1 (frame->get ().height () - 2. - scroll_bar_height);
|
||||
|
||||
set_wave_heights ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::set_spp (double samples_per_pixel)
|
||||
{
|
||||
_spp = samples_per_pixel;
|
||||
|
||||
clip_metric->units_per_pixel = _spp;
|
||||
|
||||
position_lines ();
|
||||
|
||||
for (auto& wave : waves) {
|
||||
wave->set_samples_per_pixel (_spp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::set_spp_from_length (samplecnt_t len)
|
||||
{
|
||||
set_samples_per_pixel (floor (len / _visible_canvas_width));
|
||||
double available_width = frame->get ().width ();
|
||||
double s = floor (len / available_width);
|
||||
|
||||
set_spp (s);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -487,12 +521,12 @@ AudioClipEditor::set_wave_heights ()
|
|||
}
|
||||
|
||||
uint32_t n = 0;
|
||||
const Distance w = _visible_canvas_height - (n_timebars * timebar_height);
|
||||
const Distance w = frame->get ().height () - scroll_bar_trough->get ().height () - 2. - ruler->get().height();
|
||||
Distance ht = w / waves.size ();
|
||||
|
||||
for (auto& wave : waves) {
|
||||
wave->set_height (ht);
|
||||
wave->set_y_position ((n_timebars * timebar_height) + (n * ht));
|
||||
wave->set_y_position (ruler->get ().height () + (n * ht));
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
|
@ -513,69 +547,86 @@ AudioClipEditor::set_waveform_colors ()
|
|||
}
|
||||
}
|
||||
|
||||
Gtk::Widget&
|
||||
AudioClipEditor::viewport()
|
||||
{
|
||||
return _viewport;
|
||||
}
|
||||
|
||||
Gtk::Widget&
|
||||
AudioClipEditor::contents ()
|
||||
{
|
||||
return _contents;
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::region_changed (const PBD::PropertyChange& what_changed)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditor::set_samples_per_pixel (samplecnt_t spp)
|
||||
{
|
||||
CueEditor::set_samples_per_pixel (spp);
|
||||
|
||||
clip_metric->units_per_pixel = samples_per_pixel;
|
||||
|
||||
position_lines ();
|
||||
|
||||
for (auto& wave : waves) {
|
||||
wave->set_samples_per_pixel (samples_per_pixel);
|
||||
}
|
||||
|
||||
horizontal_adjustment.set_upper (max_zoom_extent().second.samples() / samples_per_pixel);
|
||||
horizontal_adjustment.set_page_size (current_page_samples()/ samples_per_pixel / 10);
|
||||
horizontal_adjustment.set_page_increment (current_page_samples()/ samples_per_pixel / 20);
|
||||
horizontal_adjustment.set_step_increment (current_page_samples() / samples_per_pixel / 100);
|
||||
}
|
||||
|
||||
samplecnt_t
|
||||
AudioClipEditor::current_page_samples() const
|
||||
{
|
||||
return (samplecnt_t) _track_canvas_width * samples_per_pixel;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioClipEditor::canvas_enter_leave (GdkEventCrossing* ev)
|
||||
AudioClipEditor::event_handler (GdkEvent* ev)
|
||||
{
|
||||
switch (ev->type) {
|
||||
case GDK_BUTTON_PRESS:
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
if (ev->detail != GDK_NOTIFY_INFERIOR) {
|
||||
canvas.grab_focus ();
|
||||
// ActionManager::set_sensitive (_midi_actions, true);
|
||||
within_track_canvas = true;
|
||||
}
|
||||
break;
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
if (ev->detail != GDK_NOTIFY_INFERIOR) {
|
||||
// ActionManager::set_sensitive (_midi_actions, false);
|
||||
within_track_canvas = false;
|
||||
ARDOUR_UI::instance()->reset_focus (&_viewport);
|
||||
gdk_window_set_cursor (_viewport.get_window()->gobj(), nullptr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioClipEditorBox::AudioClipEditorBox ()
|
||||
{
|
||||
_header_label.set_text (_("AUDIO Region Trimmer:"));
|
||||
_header_label.set_alignment (0.0, 0.5);
|
||||
|
||||
zoom_in_button.set_icon (ArdourIcon::ZoomIn);
|
||||
zoom_out_button.set_icon (ArdourIcon::ZoomOut);
|
||||
|
||||
zoom_in_button.signal_clicked.connect (sigc::mem_fun (*this, &AudioClipEditorBox::zoom_in_click));
|
||||
zoom_out_button.signal_clicked.connect (sigc::mem_fun (*this, &AudioClipEditorBox::zoom_out_click));
|
||||
|
||||
header_box.pack_start (_header_label, false, false);
|
||||
header_box.pack_start (zoom_in_button, false, false);
|
||||
header_box.pack_start (zoom_out_button, false, false);
|
||||
|
||||
pack_start (header_box, false, false, 6);
|
||||
|
||||
editor = manage (new AudioClipEditor);
|
||||
editor->set_size_request (600, 120);
|
||||
|
||||
pack_start (*editor, true, true);
|
||||
editor->show ();
|
||||
}
|
||||
|
||||
AudioClipEditorBox::~AudioClipEditorBox ()
|
||||
{
|
||||
delete editor;
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditorBox::zoom_in_click ()
|
||||
{
|
||||
editor->set_spp (editor->spp () / 2.);
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditorBox::zoom_out_click ()
|
||||
{
|
||||
editor->set_spp (editor->spp () * 2.);
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditorBox::set_region (std::shared_ptr<Region> r, TriggerReference tref)
|
||||
{
|
||||
std::shared_ptr<AudioRegion> ar = std::dynamic_pointer_cast<AudioRegion> (r);
|
||||
|
||||
if (!ar) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_session (&r->session ());
|
||||
|
||||
state_connection.disconnect ();
|
||||
|
||||
_region = r;
|
||||
editor->set_region (ar, tref);
|
||||
|
||||
PBD::PropertyChange interesting_stuff;
|
||||
region_changed (interesting_stuff);
|
||||
|
||||
_region->PropertyChanged.connect (state_connection, invalidator (*this), std::bind (&AudioClipEditorBox::region_changed, this, _1), gui_context ());
|
||||
}
|
||||
|
||||
void
|
||||
AudioClipEditorBox::region_changed (const PBD::PropertyChange& what_changed)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@
|
|||
#include <ytkmm/label.h>
|
||||
#include <ytkmm/table.h>
|
||||
|
||||
#include "pbd/history_owner.h"
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
#include "ardour/session_handle.h"
|
||||
#include "ardour/triggerbox.h"
|
||||
|
|
@ -46,7 +44,6 @@
|
|||
#include "canvas/scroll_group.h"
|
||||
|
||||
#include "audio_clock.h"
|
||||
#include "cue_editor.h"
|
||||
|
||||
namespace ARDOUR
|
||||
{
|
||||
|
|
@ -66,104 +63,59 @@ namespace ArdourWaveView
|
|||
class WaveView;
|
||||
}
|
||||
|
||||
class AudioClipEditor : public CueEditor
|
||||
class ClipEditorBox : public Gtk::VBox, public ARDOUR::SessionHandlePtr
|
||||
{
|
||||
public:
|
||||
AudioClipEditor (std::string const &, bool with_transport);
|
||||
ClipEditorBox () {}
|
||||
~ClipEditorBox () {}
|
||||
|
||||
virtual void set_region (std::shared_ptr<ARDOUR::Region>, ARDOUR::TriggerReference) = 0;
|
||||
|
||||
static void init ();
|
||||
static void register_clip_editor_actions (Gtkmm2ext::Bindings*);
|
||||
static Glib::RefPtr<Gtk::ActionGroup> clip_editor_actions;
|
||||
};
|
||||
|
||||
class ClipEditor
|
||||
{
|
||||
public:
|
||||
virtual ~ClipEditor () {}
|
||||
|
||||
virtual void zoom_in () = 0;
|
||||
virtual void zoom_out () = 0;
|
||||
};
|
||||
|
||||
class AudioClipEditor : public ArdourCanvas::GtkCanvas
|
||||
{
|
||||
public:
|
||||
AudioClipEditor ();
|
||||
~AudioClipEditor ();
|
||||
|
||||
void canvas_allocate (Gtk::Allocation&);
|
||||
|
||||
Gtk::Widget& viewport();
|
||||
Gtk::Widget& contents ();
|
||||
|
||||
void set_trigger (ARDOUR::TriggerReference&);
|
||||
void set_region (std::shared_ptr<ARDOUR::AudioRegion>);
|
||||
void set_region (std::shared_ptr<ARDOUR::Region> r);
|
||||
void region_changed (const PBD::PropertyChange& what_changed);
|
||||
void set_region (std::shared_ptr<ARDOUR::AudioRegion>, ARDOUR::TriggerReference);
|
||||
void on_size_allocate (Gtk::Allocation&);
|
||||
|
||||
double sample_to_pixel (ARDOUR::samplepos_t);
|
||||
samplepos_t pixel_to_sample (double);
|
||||
|
||||
void set_spp (double);
|
||||
double spp () const
|
||||
{
|
||||
return _spp;
|
||||
}
|
||||
|
||||
bool key_press (GdkEventKey*);
|
||||
bool minsec_ruler_event (GdkEvent*);
|
||||
|
||||
/* EditingContext API. As of July 2025, we do not implement most of
|
||||
* these
|
||||
*/
|
||||
|
||||
bool button_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) { return true; }
|
||||
bool button_press_handler_1 (ArdourCanvas::Item*, GdkEvent*, ItemType) { return true; }
|
||||
bool button_press_handler_2 (ArdourCanvas::Item*, GdkEvent*, ItemType) { return true; }
|
||||
bool button_release_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) { return true; }
|
||||
bool button_press_dispatch (GdkEventButton*) { return true; }
|
||||
bool button_release_dispatch (GdkEventButton*) { return true; }
|
||||
bool motion_handler (ArdourCanvas::Item*, GdkEvent*, bool from_autoscroll = false) { return true; }
|
||||
bool enter_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) { return true; }
|
||||
bool leave_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) { return true; }
|
||||
bool key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) { return true; }
|
||||
bool key_release_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) { return true; }
|
||||
|
||||
bool canvas_note_event (GdkEvent* event, ArdourCanvas::Item*) { return true; }
|
||||
bool canvas_velocity_base_event (GdkEvent* event, ArdourCanvas::Item*) { return true; }
|
||||
bool canvas_velocity_event (GdkEvent* event, ArdourCanvas::Item*) { return true; }
|
||||
bool canvas_control_point_event (GdkEvent* event, ArdourCanvas::Item*, ControlPoint*) { return true; }
|
||||
bool canvas_bg_event (GdkEvent* event, ArdourCanvas::Item*) { return true; }
|
||||
|
||||
ArdourCanvas::Container* get_trackview_group () const;
|
||||
ArdourCanvas::Container* get_noscroll_group() const;
|
||||
ArdourCanvas::ScrollGroup* get_hscroll_group () const;
|
||||
ArdourCanvas::ScrollGroup* get_cursor_scroll_group () const;
|
||||
|
||||
samplecnt_t current_page_samples() const;
|
||||
double visible_canvas_width() const;
|
||||
void set_samples_per_pixel (samplecnt_t);
|
||||
|
||||
ArdourCanvas::GtkCanvasViewport* get_canvas_viewport() const { return const_cast<ArdourCanvas::GtkCanvasViewport*> (&_viewport); }
|
||||
ArdourCanvas::GtkCanvas* get_canvas() const { return &canvas; }
|
||||
|
||||
std::pair<Temporal::timepos_t,Temporal::timepos_t> max_zoom_extent() const;
|
||||
|
||||
Gdk::Cursor* which_track_cursor () const { return nullptr; }
|
||||
Gdk::Cursor* which_mode_cursor () const { return nullptr; }
|
||||
Gdk::Cursor* which_trim_cursor (bool left_side) const { return nullptr; }
|
||||
Gdk::Cursor* which_canvas_cursor (ItemType type) const { return nullptr; }
|
||||
|
||||
RegionSelection region_selection();
|
||||
|
||||
Temporal::timepos_t snap_to_grid (Temporal::timepos_t const & start, Temporal::RoundMode direction, ARDOUR::SnapPref gpref) const { return start; }
|
||||
void snap_to_internal (Temporal::timepos_t& first, Temporal::RoundMode direction = Temporal::RoundNearest, ARDOUR::SnapPref gpref = ARDOUR::SnapToAny_Visual, bool ensure_snap = false) const {}
|
||||
|
||||
void select_all_within (Temporal::timepos_t const &, Temporal::timepos_t const &, double, double, std::list<SelectableOwner*> const &, ARDOUR::SelectionOperation, bool) {}
|
||||
void get_per_region_note_selection (std::list<std::pair<PBD::ID, std::set<std::shared_ptr<Evoral::Note<Temporal::Beats> > > > >&) const {}
|
||||
void get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const {}
|
||||
void maybe_autoscroll (bool, bool, bool from_headers) {};
|
||||
void stop_canvas_autoscroll () {}
|
||||
void redisplay_grid (bool immediate_redraw) {};
|
||||
void instant_save() {};
|
||||
|
||||
void point_selection_changed () {}
|
||||
void step_mouse_mode (bool next);
|
||||
void mouse_mode_toggled (Editing::MouseMode);
|
||||
void delete_ () {}
|
||||
void paste (float times, bool from_context_menu) {}
|
||||
void keyboard_paste () {}
|
||||
void cut_copy (Editing::CutCopyOp) {}
|
||||
|
||||
void register_actions() {}
|
||||
void visual_changer (const VisualChange&) {}
|
||||
void build_zoom_focus_menu () {}
|
||||
|
||||
private:
|
||||
ArdourCanvas::GtkCanvasViewport _viewport;
|
||||
ArdourCanvas::GtkCanvas& canvas;
|
||||
|
||||
ArdourCanvas::Rectangle* frame;
|
||||
ArdourCanvas::ScrollGroup* waves_container;
|
||||
ArdourCanvas::Container* line_container;
|
||||
ArdourCanvas::Line* start_line;
|
||||
ArdourCanvas::Line* end_line;
|
||||
ArdourCanvas::Line* loop_line;
|
||||
ArdourCanvas::Rectangle* scroll_bar_trough;
|
||||
ArdourCanvas::Rectangle* scroll_bar_handle;
|
||||
ArdourCanvas::Container* ruler_container;
|
||||
ArdourCanvas::Ruler* minsec_ruler;
|
||||
ArdourCanvas::Ruler* ruler;
|
||||
|
||||
class ClipBBTMetric : public ArdourCanvas::Ruler::Metric
|
||||
{
|
||||
|
|
@ -183,6 +135,7 @@ private:
|
|||
std::vector<ArdourWaveView::WaveView*> waves;
|
||||
double non_wave_height;
|
||||
samplepos_t left_origin;
|
||||
double _spp;
|
||||
double scroll_fraction;
|
||||
std::shared_ptr<ARDOUR::AudioRegion> audio_region;
|
||||
|
||||
|
|
@ -197,6 +150,7 @@ private:
|
|||
|
||||
bool event_handler (GdkEvent* ev);
|
||||
bool line_event_handler (GdkEvent* ev, ArdourCanvas::Line*);
|
||||
bool scroll_event_handler (GdkEvent* ev);
|
||||
void drop_waves ();
|
||||
void set_wave_heights ();
|
||||
void set_spp_from_length (ARDOUR::samplecnt_t);
|
||||
|
|
@ -222,12 +176,47 @@ private:
|
|||
friend class LineDrag;
|
||||
LineDrag* current_line_drag;
|
||||
|
||||
class ScrollDrag
|
||||
{
|
||||
public:
|
||||
ScrollDrag (AudioClipEditor&);
|
||||
|
||||
void begin (GdkEventButton*);
|
||||
void end (GdkEventButton*);
|
||||
void motion (GdkEventMotion*);
|
||||
|
||||
private:
|
||||
AudioClipEditor& editor;
|
||||
double last_x;
|
||||
};
|
||||
|
||||
friend class ScrollDrag;
|
||||
ScrollDrag* current_scroll_drag;
|
||||
};
|
||||
|
||||
class AudioClipEditorBox : public ClipEditorBox
|
||||
{
|
||||
public:
|
||||
AudioClipEditorBox ();
|
||||
~AudioClipEditorBox ();
|
||||
|
||||
void set_region (std::shared_ptr<ARDOUR::Region>, ARDOUR::TriggerReference);
|
||||
void region_changed (const PBD::PropertyChange& what_changed);
|
||||
|
||||
private:
|
||||
Gtk::HBox header_box;
|
||||
ArdourWidgets::ArdourButton zoom_in_button;
|
||||
ArdourWidgets::ArdourButton zoom_out_button;
|
||||
Gtk::Label _header_label;
|
||||
Gtk::Table table;
|
||||
|
||||
AudioClipEditor* editor;
|
||||
|
||||
PBD::ScopedConnection state_connection;
|
||||
|
||||
void build_canvas ();
|
||||
void build_lower_toolbar ();
|
||||
void pack_inner (Gtk::Box&);
|
||||
void pack_outer (Gtk::Box&);
|
||||
std::shared_ptr<ARDOUR::Region> _region;
|
||||
|
||||
bool canvas_enter_leave (GdkEventCrossing* ev);
|
||||
void zoom_in_click ();
|
||||
void zoom_out_click ();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -112,31 +112,29 @@ AudioTriggerPropertiesBox::AudioTriggerPropertiesBox ()
|
|||
|
||||
eTempoBox->show_all();
|
||||
|
||||
Gtk::Table* audio_t = manage (new Gtk::Table ());
|
||||
audio_t->set_homogeneous (true);
|
||||
audio_t->set_spacings (4);
|
||||
|
||||
/* -------------- Clip start&length (redundant with the trimmer gui handles?) ----------*/
|
||||
row = 0;
|
||||
|
||||
label = manage (new Gtk::Label (_("Start:")));
|
||||
label->set_alignment (1.0, 0.5);
|
||||
audio_t->attach (*label, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK);
|
||||
audio_t->attach (_start_clock, 1, 2, row, row + 1, Gtk::SHRINK, Gtk::SHRINK);
|
||||
_table.attach (*label, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK);
|
||||
_table.attach (_start_clock, 1, 2, row, row + 1, Gtk::SHRINK, Gtk::SHRINK);
|
||||
row++;
|
||||
|
||||
label = manage (new Gtk::Label (_("Clip Length:")));
|
||||
label->set_alignment (1.0, 0.5);
|
||||
audio_t->attach (*label, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK);
|
||||
audio_t->attach (_length_clock, 1, 2, row, row + 1, Gtk::SHRINK, Gtk::SHRINK);
|
||||
_table.attach (*label, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK);
|
||||
_table.attach (_length_clock, 1, 2, row, row + 1, Gtk::SHRINK, Gtk::SHRINK);
|
||||
row++;
|
||||
|
||||
audio_t->set_homogeneous (false);
|
||||
audio_t->set_spacings (4);
|
||||
audio_t->set_border_width (2);
|
||||
_table.set_homogeneous (false);
|
||||
_table.set_spacings (4);
|
||||
_table.set_border_width (2);
|
||||
|
||||
attach (*eTempoBox, 0,1, 0,1, Gtk::FILL, Gtk::EXPAND | Gtk::FILL);
|
||||
attach (*audio_t, 0,1, 1,2, Gtk::FILL, Gtk::SHRINK);
|
||||
#if 0
|
||||
attach (_table, 0,1, 1,2, Gtk::FILL, Gtk::SHRINK);
|
||||
#endif
|
||||
|
||||
_start_clock.ValueChanged.connect (sigc::mem_fun (*this, &AudioTriggerPropertiesBox::start_clock_changed));
|
||||
_length_clock.ValueChanged.connect (sigc::mem_fun (*this, &AudioTriggerPropertiesBox::length_clock_changed));
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef _gtk_ardour_audio_trigger_properties_box_h_
|
||||
#define _gtk_ardour_audio_trigger_properties_box_h_
|
||||
|
||||
#include <ytkmm/box.h>
|
||||
#include <ytkmm/label.h>
|
||||
|
|
@ -33,7 +34,18 @@
|
|||
|
||||
#include "audio_clock.h"
|
||||
#include "trigger_ui.h"
|
||||
#include "trigger_properties_box.h"
|
||||
|
||||
class TriggerPropertiesBox : public Gtk::Table, public ARDOUR::SessionHandlePtr, public TriggerUI
|
||||
{
|
||||
public:
|
||||
TriggerPropertiesBox () {}
|
||||
~TriggerPropertiesBox () {}
|
||||
|
||||
protected:
|
||||
Gtk::Label _header_label;
|
||||
|
||||
PBD::ScopedConnection _state_connection;
|
||||
};
|
||||
|
||||
class AudioTriggerPropertiesBox : public TriggerPropertiesBox
|
||||
{
|
||||
|
|
@ -60,6 +72,8 @@ private:
|
|||
|
||||
void MultiplyTempo(float mult);
|
||||
|
||||
Gtk::Table _table;
|
||||
|
||||
AudioClock _length_clock;
|
||||
AudioClock _start_clock;
|
||||
|
||||
|
|
@ -84,3 +98,5 @@ private:
|
|||
|
||||
bool _ignore_changes;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,49 +1,15 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "widgets/ardour_icon.h"
|
||||
#include "widgets/tooltips.h"
|
||||
|
||||
#include "ardour/types.h"
|
||||
|
||||
#include "canvas/canvas.h"
|
||||
|
||||
#include "cue_editor.h"
|
||||
#include "editor_drag.h"
|
||||
#include "gui_thread.h"
|
||||
#include "ui_config.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace ArdourWidgets;
|
||||
|
||||
CueEditor::CueEditor (std::string const & name, bool with_transport)
|
||||
CueEditor::CueEditor (std::string const & name)
|
||||
: EditingContext (name)
|
||||
, HistoryOwner (name)
|
||||
, with_transport_controls (with_transport)
|
||||
, length_label (X_("Record:"))
|
||||
, solo_button (S_("Solo|S"))
|
||||
, zoom_in_allocate (false)
|
||||
, timebar_height (15.)
|
||||
, n_timebars (0)
|
||||
, HistoryOwner (X_("cue-editor"))
|
||||
{
|
||||
_history.Changed.connect (history_connection, invalidator (*this), std::bind (&CueEditor::history_changed, this), gui_context());
|
||||
|
||||
set_zoom_focus (Editing::ZoomFocusLeft);
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +71,22 @@ CueEditor::find_marker_for_meter (Temporal::MeterPoint const &)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::maybe_autoscroll (bool, bool, bool from_headers)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::stop_canvas_autoscroll ()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CueEditor::autoscroll_active() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::redisplay_grid (bool immediate_redraw)
|
||||
{
|
||||
|
|
@ -281,695 +263,3 @@ CueEditor::_get_preferred_edit_position (Editing::EditIgnoreOption ignore, bool
|
|||
|
||||
return Temporal::timepos_t (where);
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::build_upper_toolbar ()
|
||||
{
|
||||
using namespace Gtk::Menu_Helpers;
|
||||
|
||||
Gtk::HBox* mode_box = manage(new Gtk::HBox);
|
||||
mode_box->set_border_width (2);
|
||||
mode_box->set_spacing(2);
|
||||
|
||||
Gtk::HBox* mouse_mode_box = manage (new Gtk::HBox);
|
||||
Gtk::HBox* mouse_mode_hbox = manage (new Gtk::HBox);
|
||||
Gtk::VBox* mouse_mode_vbox = manage (new Gtk::VBox);
|
||||
Gtk::Alignment* mouse_mode_align = manage (new Gtk::Alignment);
|
||||
|
||||
Glib::RefPtr<Gtk::SizeGroup> mouse_mode_size_group = Gtk::SizeGroup::create (Gtk::SIZE_GROUP_VERTICAL);
|
||||
mouse_mode_size_group->add_widget (mouse_draw_button);
|
||||
mouse_mode_size_group->add_widget (mouse_content_button);
|
||||
|
||||
mouse_mode_size_group->add_widget (grid_type_selector);
|
||||
mouse_mode_size_group->add_widget (draw_length_selector);
|
||||
mouse_mode_size_group->add_widget (draw_velocity_selector);
|
||||
mouse_mode_size_group->add_widget (draw_channel_selector);
|
||||
mouse_mode_size_group->add_widget (snap_mode_button);
|
||||
|
||||
mouse_mode_hbox->set_spacing (2);
|
||||
mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
|
||||
mouse_mode_hbox->pack_start (mouse_content_button, false, false);
|
||||
|
||||
mouse_mode_vbox->pack_start (*mouse_mode_hbox);
|
||||
|
||||
mouse_mode_align->add (*mouse_mode_vbox);
|
||||
mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
|
||||
|
||||
mouse_mode_box->pack_start (*mouse_mode_align, false, false);
|
||||
|
||||
pack_snap_box ();
|
||||
pack_draw_box (false);
|
||||
|
||||
Gtk::HBox* _toolbar_inner = manage (new Gtk::HBox);
|
||||
Gtk::HBox* _toolbar_outer = manage (new Gtk::HBox);
|
||||
Gtk::HBox* _toolbar_left = manage (new Gtk::HBox);
|
||||
|
||||
_toolbar_inner->pack_start (*mouse_mode_box, false, false);
|
||||
pack_inner (*_toolbar_inner);
|
||||
|
||||
set_tooltip (full_zoom_button, _("Zoom to full clip"));
|
||||
set_tooltip (note_mode_button, _("Toggle between drum and regular note drawing"));
|
||||
|
||||
play_button.set_icon (ArdourIcon::TransportPlay);
|
||||
play_button.set_name ("transport button");
|
||||
play_button.show();
|
||||
|
||||
if (with_transport_controls) {
|
||||
loop_button.set_icon (ArdourIcon::TransportLoop);
|
||||
loop_button.set_name ("transport button");
|
||||
|
||||
solo_button.set_name ("solo button");
|
||||
|
||||
play_box.set_spacing (8);
|
||||
play_box.pack_start (play_button, false, false);
|
||||
play_box.pack_start (loop_button, false, false);
|
||||
play_box.pack_start (solo_button, false, false);
|
||||
loop_button.show();
|
||||
solo_button.show();
|
||||
play_box.set_no_show_all (true);
|
||||
play_box.show ();
|
||||
|
||||
play_button.signal_button_release_event().connect (sigc::mem_fun (*this, &CueEditor::play_button_press), false);
|
||||
solo_button.signal_button_release_event().connect (sigc::mem_fun (*this, &CueEditor::solo_button_press), false);
|
||||
loop_button.signal_button_release_event().connect (sigc::mem_fun (*this, &CueEditor::loop_button_press), false);
|
||||
} else {
|
||||
rec_box.pack_start (play_button, false, false);
|
||||
play_button.signal_button_release_event().connect (sigc::mem_fun (*this, &CueEditor::bang_button_press), false);
|
||||
}
|
||||
|
||||
rec_enable_button.set_icon (ArdourIcon::RecButton);
|
||||
rec_enable_button.set_sensitive (false);
|
||||
rec_enable_button.signal_button_release_event().connect (sigc::mem_fun (*this, &CueEditor::rec_button_press), false);
|
||||
rec_enable_button.set_name ("record enable button");
|
||||
|
||||
length_selector.add_menu_elem (MenuElem (_("Until Stopped"), sigc::bind (sigc::mem_fun (*this, &CueEditor::set_recording_length), Temporal::BBT_Offset ())));
|
||||
length_selector.add_menu_elem (MenuElem (_("1 Bar"), sigc::bind (sigc::mem_fun (*this, &CueEditor::set_recording_length), Temporal::BBT_Offset (1, 0, 0))));
|
||||
std::vector<int> b ({ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 20, 24, 32 });
|
||||
for (auto & n : b) {
|
||||
length_selector.add_menu_elem (MenuElem (string_compose (_("%1 Bars"), n), sigc::bind (sigc::mem_fun (*this, &CueEditor::set_recording_length), Temporal::BBT_Offset (n, 0, 0))));
|
||||
}
|
||||
length_selector.set_active (_("Until Stopped"));
|
||||
|
||||
rec_box.set_spacing (12);
|
||||
rec_box.pack_start (rec_enable_button, false, false);
|
||||
rec_box.pack_start (length_label, false, false);
|
||||
rec_box.pack_start (length_selector, false, false);
|
||||
rec_enable_button.show();
|
||||
length_label.show ();
|
||||
length_selector.show ();
|
||||
rec_box.set_no_show_all (true);
|
||||
/* rec box not shown */
|
||||
|
||||
_toolbar_outer->set_border_width (6);
|
||||
_toolbar_outer->set_spacing (12);
|
||||
|
||||
pack_outer (*_toolbar_outer);
|
||||
|
||||
_toolbar_outer->pack_start (*_toolbar_inner, true, false);
|
||||
|
||||
build_zoom_focus_menu ();
|
||||
zoom_focus_selector.set_text (zoom_focus_strings[(int)_zoom_focus]);
|
||||
|
||||
_toolbar_left->pack_start (zoom_in_button, false, false);
|
||||
_toolbar_left->pack_start (zoom_out_button, false, false);
|
||||
_toolbar_left->pack_start (full_zoom_button, false, false);
|
||||
_toolbar_left->pack_start (zoom_focus_selector, false, false);
|
||||
|
||||
_toolbar_outer->pack_start (*_toolbar_left, true, false);
|
||||
_toolbox.pack_start (*_toolbar_outer, false, false);
|
||||
|
||||
_contents.add (_toolbox);
|
||||
_contents.signal_unmap().connect ([this]() {viewport().unmap (); }, false);
|
||||
_contents.signal_map().connect ([this]() { viewport().map (); }, false);
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::build_zoom_focus_menu ()
|
||||
{
|
||||
using namespace Gtk::Menu_Helpers;
|
||||
using namespace Editing;
|
||||
|
||||
zoom_focus_selector.add_menu_elem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &EditingContext::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
|
||||
zoom_focus_selector.add_menu_elem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &EditingContext::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
|
||||
zoom_focus_selector.add_menu_elem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &EditingContext::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
|
||||
zoom_focus_selector.add_menu_elem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &EditingContext::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
|
||||
zoom_focus_selector.set_sizing_texts (zoom_focus_strings);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CueEditor::play_button_press (GdkEventButton* ev)
|
||||
{
|
||||
#warning paul fix lookup region via CueEditor 87
|
||||
#if 0
|
||||
if (_session) {
|
||||
_session->request_locate (view->midi_region()->position().samples());
|
||||
_session->request_roll ();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CueEditor::loop_button_press (GdkEventButton* ev)
|
||||
{
|
||||
#warning paul fix region lookup via CueEditor 1
|
||||
#if 0
|
||||
if (!view) {
|
||||
return true;
|
||||
}
|
||||
if (!view->midi_region()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_session->get_play_loop()) {
|
||||
_session->request_play_loop (false);
|
||||
} else {
|
||||
set_loop_range (view->midi_region()->position(), view->midi_region()->end(), _("loop region"));
|
||||
_session->request_play_loop (true);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CueEditor::solo_button_press (GdkEventButton* ev)
|
||||
{
|
||||
#warning paul fix region lookup via CueEditor 2
|
||||
#if 0
|
||||
if (!view) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!view->midi_track()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
view->midi_track()->solo_control()->set_value (!view->midi_track()->solo_control()->get_value(), Controllable::NoGroup);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CueEditor::rec_button_press (GdkEventButton* ev)
|
||||
{
|
||||
#warning paul fix trigger lookup via CueEditor 1
|
||||
#if 0
|
||||
if (ev->button != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TriggerPtr trigger (ref.trigger());
|
||||
|
||||
if (!trigger) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (trigger->armed()) {
|
||||
trigger->disarm ();
|
||||
} else {
|
||||
trigger->arm (rec_length);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::blink_rec_enable (bool onoff)
|
||||
{
|
||||
if (onoff) {
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::ExplicitActive);
|
||||
} else {
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::Off);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::trigger_arm_change ()
|
||||
{
|
||||
#warning paul fix trigger lookup via CueEditor 1
|
||||
#if 0
|
||||
if (!ref.trigger()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ref.trigger()->armed()) {
|
||||
view->end_write ();
|
||||
} else {
|
||||
maybe_set_count_in ();
|
||||
}
|
||||
#endif
|
||||
rec_enable_change ();
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::rec_enable_change ()
|
||||
{
|
||||
#warning paul fix trigger lookup via CueEditor 1
|
||||
#if 0
|
||||
if (!ref.box()) {
|
||||
std::cerr << "no box!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
rec_blink_connection.disconnect ();
|
||||
count_in_connection.disconnect ();
|
||||
|
||||
std::cerr << "REC, state " << ref.box()->record_enabled() << std::endl;
|
||||
|
||||
switch (ref.box()->record_enabled()) {
|
||||
case Recording:
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::ExplicitActive);
|
||||
rec_blink_connection.disconnect ();
|
||||
if (view) {
|
||||
view->begin_write ();
|
||||
}
|
||||
break;
|
||||
case Enabled:
|
||||
if (!UIConfiguration::instance().get_no_strobe() && ref.trigger()->armed()) {
|
||||
rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &CueEditor::blink_rec_enable));
|
||||
} else {
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::Off);
|
||||
}
|
||||
maybe_set_count_in ();
|
||||
break;
|
||||
case Disabled:
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::Off);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::set_recording_length (Temporal::BBT_Offset dur)
|
||||
{
|
||||
rec_length = dur;
|
||||
}
|
||||
|
||||
bool
|
||||
CueEditor::bang_button_press (GdkEventButton* ev)
|
||||
{
|
||||
#warning paul fix trigger look from CueEditor 93
|
||||
#if 0
|
||||
if (!ref.trigger()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ref.trigger()->bang ();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::scrolled ()
|
||||
{
|
||||
pending_visual_change.add (VisualChange::TimeOrigin);
|
||||
pending_visual_change.time_origin = horizontal_adjustment.get_value() * samples_per_pixel;
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
bool
|
||||
CueEditor::canvas_pre_event (GdkEvent* ev)
|
||||
{
|
||||
switch (ev->type) {
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
if (canvas_enter_leave (&ev->crossing)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CueEditor::autoscroll_active () const
|
||||
{
|
||||
return autoscroll_connection.connected ();
|
||||
}
|
||||
|
||||
/** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
|
||||
*
|
||||
* @param allow_vert true to allow vertical autoscroll, otherwise false.
|
||||
*
|
||||
*/
|
||||
void
|
||||
CueEditor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
|
||||
{
|
||||
if (!UIConfiguration::instance().get_autoscroll_editor () || autoscroll_active ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* define a rectangular boundary for scrolling. If the mouse moves
|
||||
* outside of this area and/or continue to be outside of this area,
|
||||
* then we will continuously auto-scroll the canvas in the appropriate
|
||||
* direction(s)
|
||||
*
|
||||
* the boundary is defined in coordinates relative to canvas' own
|
||||
* window since that is what we're going to call ::get_pointer() on
|
||||
* during autoscrolling to determine if we're still outside the
|
||||
* boundary or not.
|
||||
*/
|
||||
|
||||
ArdourCanvas::Rect scrolling_boundary;
|
||||
Gtk::Allocation alloc;
|
||||
|
||||
alloc = get_canvas()->get_allocation ();
|
||||
|
||||
alloc.set_x (0);
|
||||
alloc.set_y (0);
|
||||
|
||||
if (allow_vert) {
|
||||
/* reduce height by the height of the timebars, which happens
|
||||
to correspond to the position of the data_group.
|
||||
*/
|
||||
|
||||
alloc.set_height (alloc.get_height() - data_group->position().y);
|
||||
alloc.set_y (alloc.get_y() + data_group->position().y);
|
||||
|
||||
/* now reduce it again so that we start autoscrolling before we
|
||||
* move off the top or bottom of the canvas
|
||||
*/
|
||||
|
||||
alloc.set_height (alloc.get_height() - 20);
|
||||
alloc.set_y (alloc.get_y() + 10);
|
||||
}
|
||||
|
||||
if (allow_horiz && (alloc.get_width() > 20)) {
|
||||
|
||||
#warning paul fix use of PRH in CueEditor context
|
||||
#if 0
|
||||
if (prh) {
|
||||
double w, h;
|
||||
prh->size_request (w, h);
|
||||
|
||||
alloc.set_width (alloc.get_width() - w);
|
||||
alloc.set_x (alloc.get_x() + w);
|
||||
}
|
||||
#endif
|
||||
/* the effective width of the autoscroll boundary so
|
||||
that we start scrolling before we hit the edge.
|
||||
|
||||
this helps when the window is slammed up against the
|
||||
right edge of the screen, making it hard to scroll
|
||||
effectively.
|
||||
*/
|
||||
|
||||
alloc.set_width (alloc.get_width() - 20);
|
||||
alloc.set_x (alloc.get_x() + 10);
|
||||
}
|
||||
|
||||
scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(), alloc.get_x() + alloc.get_width(), alloc.get_y() + alloc.get_height());
|
||||
|
||||
int x, y;
|
||||
Gdk::ModifierType mask;
|
||||
|
||||
get_canvas()->get_window()->get_pointer (x, y, mask);
|
||||
|
||||
if ((allow_horiz && ((x < scrolling_boundary.x0 && _leftmost_sample > 0) || x >= scrolling_boundary.x1)) ||
|
||||
(allow_vert && ((y < scrolling_boundary.y0 && vertical_adjustment.get_value() > 0)|| y >= scrolling_boundary.y1))) {
|
||||
start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CueEditor::autoscroll_canvas ()
|
||||
{
|
||||
using std::max;
|
||||
using std::min;
|
||||
int x, y;
|
||||
Gdk::ModifierType mask;
|
||||
sampleoffset_t dx = 0;
|
||||
bool no_stop = false;
|
||||
Gtk::Window* toplevel = dynamic_cast<Gtk::Window*> (viewport().get_toplevel());
|
||||
|
||||
if (!toplevel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
get_canvas()->get_window()->get_pointer (x, y, mask);
|
||||
|
||||
VisualChange vc;
|
||||
bool vertical_motion = false;
|
||||
|
||||
if (autoscroll_horizontal_allowed) {
|
||||
|
||||
samplepos_t new_sample = _leftmost_sample;
|
||||
|
||||
/* horizontal */
|
||||
|
||||
if (x > autoscroll_boundary.x1) {
|
||||
|
||||
/* bring it back into view */
|
||||
dx = x - autoscroll_boundary.x1;
|
||||
dx += 10 + (2 * (autoscroll_cnt/2));
|
||||
|
||||
dx = pixel_to_sample (dx);
|
||||
|
||||
dx *= UIConfiguration::instance().get_draggable_playhead_speed();
|
||||
|
||||
if (_leftmost_sample < max_samplepos - dx) {
|
||||
new_sample = _leftmost_sample + dx;
|
||||
} else {
|
||||
new_sample = max_samplepos;
|
||||
}
|
||||
|
||||
no_stop = true;
|
||||
|
||||
} else if (x < autoscroll_boundary.x0) {
|
||||
|
||||
dx = autoscroll_boundary.x0 - x;
|
||||
dx += 10 + (2 * (autoscroll_cnt/2));
|
||||
|
||||
dx = pixel_to_sample (dx);
|
||||
|
||||
dx *= UIConfiguration::instance().get_draggable_playhead_speed();
|
||||
|
||||
if (_leftmost_sample >= dx) {
|
||||
new_sample = _leftmost_sample - dx;
|
||||
} else {
|
||||
new_sample = 0;
|
||||
}
|
||||
|
||||
no_stop = true;
|
||||
}
|
||||
|
||||
if (new_sample != _leftmost_sample) {
|
||||
vc.time_origin = new_sample;
|
||||
vc.add (VisualChange::TimeOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
if (autoscroll_vertical_allowed) {
|
||||
|
||||
// const double vertical_pos = vertical_adjustment.get_value();
|
||||
const int speed_factor = 10;
|
||||
|
||||
/* vertical */
|
||||
|
||||
if (y < autoscroll_boundary.y0) {
|
||||
|
||||
/* scroll to make higher tracks visible */
|
||||
|
||||
if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
|
||||
// XXX SCROLL UP
|
||||
vertical_motion = true;
|
||||
}
|
||||
no_stop = true;
|
||||
|
||||
} else if (y > autoscroll_boundary.y1) {
|
||||
|
||||
if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
|
||||
// XXX SCROLL DOWN
|
||||
vertical_motion = true;
|
||||
}
|
||||
no_stop = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (vc.pending || vertical_motion) {
|
||||
|
||||
/* change horizontal first */
|
||||
|
||||
if (vc.pending) {
|
||||
visual_changer (vc);
|
||||
}
|
||||
|
||||
/* now send a motion event to notify anyone who cares
|
||||
that we have moved to a new location (because we scrolled)
|
||||
*/
|
||||
|
||||
GdkEventMotion ev;
|
||||
|
||||
ev.type = GDK_MOTION_NOTIFY;
|
||||
ev.state = Gdk::BUTTON1_MASK;
|
||||
|
||||
/* the motion handler expects events in canvas coordinate space */
|
||||
|
||||
/* we asked for the mouse position above (::get_pointer()) via
|
||||
* our own top level window (we being the Editor). Convert into
|
||||
* coordinates within the canvas window.
|
||||
*/
|
||||
|
||||
int cx;
|
||||
int cy;
|
||||
|
||||
//toplevel->translate_coordinates (*get_canvas(), x, y, cx,
|
||||
//cy);
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
/* clamp x and y to remain within the autoscroll boundary,
|
||||
* which is defined in window coordinates
|
||||
*/
|
||||
|
||||
x = min (max ((ArdourCanvas::Coord) cx, autoscroll_boundary.x0), autoscroll_boundary.x1);
|
||||
y = min (max ((ArdourCanvas::Coord) cy, autoscroll_boundary.y0), autoscroll_boundary.y1);
|
||||
|
||||
/* now convert from Editor window coordinates to canvas
|
||||
* window coordinates
|
||||
*/
|
||||
|
||||
ArdourCanvas::Duple d = get_canvas()->window_to_canvas (ArdourCanvas::Duple (cx, cy));
|
||||
ev.x = d.x;
|
||||
ev.y = d.y;
|
||||
ev.state = mask;
|
||||
|
||||
motion_handler (0, (GdkEvent*) &ev, true);
|
||||
|
||||
} else if (no_stop) {
|
||||
|
||||
/* not changing visual state but pointer is outside the scrolling boundary
|
||||
* so we still need to deliver a fake motion event
|
||||
*/
|
||||
|
||||
GdkEventMotion ev;
|
||||
|
||||
ev.type = GDK_MOTION_NOTIFY;
|
||||
ev.state = Gdk::BUTTON1_MASK;
|
||||
|
||||
/* the motion handler expects events in canvas coordinate space */
|
||||
|
||||
/* first convert from Editor window coordinates to canvas
|
||||
* window coordinates
|
||||
*/
|
||||
|
||||
int cx;
|
||||
int cy;
|
||||
|
||||
/* clamp x and y to remain within the visible area. except
|
||||
* .. if horizontal scrolling is allowed, always allow us to
|
||||
* move back to zero
|
||||
*/
|
||||
|
||||
if (autoscroll_horizontal_allowed) {
|
||||
x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
|
||||
} else {
|
||||
x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
|
||||
}
|
||||
y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
|
||||
|
||||
// toplevel->translate_coordinates (*get_canvas_viewport(), x,
|
||||
// y, cx, cy);
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
ArdourCanvas::Duple d = get_canvas()->window_to_canvas (ArdourCanvas::Duple (cx, cy));
|
||||
ev.x = d.x;
|
||||
ev.y = d.y;
|
||||
ev.state = mask;
|
||||
|
||||
motion_handler (0, (GdkEvent*) &ev, true);
|
||||
|
||||
} else {
|
||||
stop_canvas_autoscroll ();
|
||||
return false;
|
||||
}
|
||||
|
||||
autoscroll_cnt++;
|
||||
|
||||
return true; /* call me again */
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
|
||||
{
|
||||
if (!_session) {
|
||||
return;
|
||||
}
|
||||
|
||||
stop_canvas_autoscroll ();
|
||||
|
||||
autoscroll_horizontal_allowed = allow_horiz;
|
||||
autoscroll_vertical_allowed = allow_vert;
|
||||
autoscroll_boundary = boundary;
|
||||
|
||||
/* do the first scroll right now
|
||||
*/
|
||||
|
||||
autoscroll_canvas ();
|
||||
|
||||
/* scroll again at very very roughly 30FPS */
|
||||
|
||||
autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &CueEditor::autoscroll_canvas), 30);
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::stop_canvas_autoscroll ()
|
||||
{
|
||||
autoscroll_connection.disconnect ();
|
||||
autoscroll_cnt = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::visual_changer (const VisualChange& vc)
|
||||
{
|
||||
/**
|
||||
* Changed first so the correct horizontal canvas position is calculated in
|
||||
* EditingContext::set_horizontal_position
|
||||
*/
|
||||
if (vc.pending & VisualChange::ZoomLevel) {
|
||||
set_samples_per_pixel (vc.samples_per_pixel);
|
||||
}
|
||||
|
||||
if (vc.pending & VisualChange::TimeOrigin) {
|
||||
double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
|
||||
set_horizontal_position (new_time_origin);
|
||||
update_rulers ();
|
||||
}
|
||||
|
||||
if (vc.pending & VisualChange::YOrigin) {
|
||||
vertical_adjustment.set_value (vc.y_origin);
|
||||
}
|
||||
|
||||
if (vc.pending & VisualChange::ZoomLevel) {
|
||||
if (!(vc.pending & VisualChange::TimeOrigin)) {
|
||||
update_rulers ();
|
||||
}
|
||||
} else {
|
||||
/* If the canvas is not being zoomed then the canvas items will not change
|
||||
* and cause Item::prepare_for_render to be called so do it here manually.
|
||||
* Not ideal, but I can't think of a better solution atm.
|
||||
*/
|
||||
get_canvas()->prepare_for_render();
|
||||
}
|
||||
|
||||
/* If we are only scrolling vertically there is no need to update these */
|
||||
if (vc.pending != VisualChange::YOrigin) {
|
||||
// XXX update_fixed_rulers ();
|
||||
redisplay_grid (true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::catch_pending_show_region ()
|
||||
{
|
||||
if (_visible_pending_region) {
|
||||
set_region (_visible_pending_region);
|
||||
_visible_pending_region.reset ();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,25 +20,15 @@
|
|||
|
||||
#include "pbd/history_owner.h"
|
||||
|
||||
#include "widgets/ardour_button.h"
|
||||
#include "widgets/eventboxext.h"
|
||||
|
||||
#include "editing.h"
|
||||
#include "editing_context.h"
|
||||
|
||||
namespace Gtk {
|
||||
class HScrollbar;
|
||||
}
|
||||
|
||||
class CueEditor : public EditingContext, public PBD::HistoryOwner
|
||||
{
|
||||
public:
|
||||
CueEditor (std::string const & name, bool with_transport_controls);
|
||||
CueEditor (std::string const & name);
|
||||
~CueEditor ();
|
||||
|
||||
virtual Gtk::Widget& viewport() = 0;
|
||||
virtual Gtk::Widget& contents () = 0;
|
||||
|
||||
void get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const;
|
||||
StripableTimeAxisView* get_stripable_time_axis_by_id (const PBD::ID& id) const;
|
||||
TrackViewList axis_views_from_routes (std::shared_ptr<ARDOUR::RouteList>) const;
|
||||
|
|
@ -56,7 +46,6 @@ class CueEditor : public EditingContext, public PBD::HistoryOwner
|
|||
|
||||
void redisplay_grid (bool immediate_redraw);
|
||||
Temporal::timecnt_t get_nudge_distance (Temporal::timepos_t const & pos, Temporal::timecnt_t& next) const;
|
||||
std::list<SelectableOwner*> selectable_owners() { return std::list<SelectableOwner*>(); }
|
||||
|
||||
void instant_save();
|
||||
|
||||
|
|
@ -108,89 +97,10 @@ class CueEditor : public EditingContext, public PBD::HistoryOwner
|
|||
std::shared_ptr<Temporal::TempoMap const> start_local_tempo_map (std::shared_ptr<Temporal::TempoMap>);
|
||||
void end_local_tempo_map (std::shared_ptr<Temporal::TempoMap const>);
|
||||
|
||||
void scrolled ();
|
||||
bool canvas_pre_event (GdkEvent*);
|
||||
void catch_pending_show_region ();
|
||||
|
||||
protected:
|
||||
ARDOUR::TriggerReference ref;
|
||||
std::shared_ptr<ARDOUR::MidiTrack> _track;
|
||||
bool with_transport_controls;
|
||||
ArdourWidgets::EventBoxExt _contents;
|
||||
Gtk::VBox _toolbox;
|
||||
Gtk::HBox button_bar;
|
||||
Gtk::HScrollbar* _canvas_hscrollbar;
|
||||
|
||||
/* The group containing all other groups that are scrolled vertically
|
||||
and horizontally.
|
||||
*/
|
||||
ArdourCanvas::ScrollGroup* hv_scroll_group;
|
||||
|
||||
/* The group containing all other groups that are scrolled horizontally ONLY
|
||||
*/
|
||||
ArdourCanvas::ScrollGroup* h_scroll_group;
|
||||
ArdourCanvas::ScrollGroup* v_scroll_group;
|
||||
|
||||
/* Scroll group for cursors, scrolled horizontally, above everything else
|
||||
*/
|
||||
ArdourCanvas::ScrollGroup* cursor_scroll_group;
|
||||
|
||||
ArdourCanvas::Container* global_rect_group;
|
||||
ArdourCanvas::Container* no_scroll_group;
|
||||
ArdourCanvas::Container* data_group;
|
||||
|
||||
Gtk::Label length_label;
|
||||
Gtk::HBox rec_box;
|
||||
Gtk::HBox play_box;
|
||||
|
||||
virtual void pack_inner (Gtk::Box&) = 0;
|
||||
virtual void pack_outer (Gtk::Box&) = 0;
|
||||
void build_zoom_focus_menu ();
|
||||
|
||||
virtual void update_rulers() {}
|
||||
virtual bool canvas_enter_leave (GdkEventCrossing* ev) = 0;
|
||||
|
||||
void build_upper_toolbar ();
|
||||
void do_undo (uint32_t n);
|
||||
void do_redo (uint32_t n);
|
||||
|
||||
Temporal::timepos_t _get_preferred_edit_position (Editing::EditIgnoreOption, bool use_context_click, bool from_outside_canvas);
|
||||
|
||||
ArdourWidgets::ArdourButton rec_enable_button;
|
||||
ArdourWidgets::ArdourButton play_button;
|
||||
ArdourWidgets::ArdourButton solo_button;
|
||||
ArdourWidgets::ArdourButton loop_button;
|
||||
|
||||
ArdourCanvas::Rectangle* transport_loop_range_rect;
|
||||
|
||||
bool play_button_press (GdkEventButton*);
|
||||
bool solo_button_press (GdkEventButton*);
|
||||
bool bang_button_press (GdkEventButton*);
|
||||
bool loop_button_press (GdkEventButton*);
|
||||
|
||||
ArdourWidgets::ArdourDropdown length_selector;
|
||||
Temporal::BBT_Offset rec_length;
|
||||
|
||||
bool zoom_in_allocate;
|
||||
|
||||
void set_recording_length (Temporal::BBT_Offset bars);
|
||||
virtual void set_region (std::shared_ptr<ARDOUR::Region>) = 0;
|
||||
|
||||
bool rec_button_press (GdkEventButton*);
|
||||
void rec_enable_change ();
|
||||
void blink_rec_enable (bool);
|
||||
sigc::connection rec_blink_connection;
|
||||
|
||||
void trigger_arm_change ();
|
||||
|
||||
double timebar_height;
|
||||
size_t n_timebars;
|
||||
|
||||
/* autoscrolling */
|
||||
|
||||
bool autoscroll_canvas ();
|
||||
void start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary);
|
||||
void visual_changer (const VisualChange&);
|
||||
|
||||
std::shared_ptr<ARDOUR::Region> _visible_pending_region;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -258,9 +258,6 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider,
|
|||
double timeline_to_canvas (double p) const { return p + _timeline_origin; }
|
||||
double canvas_to_timeline (double p) const { return p - _timeline_origin; }
|
||||
|
||||
double visible_canvas_width () const { return _visible_canvas_width; }
|
||||
double visible_canvas_height () const { return _visible_canvas_height; }
|
||||
|
||||
/** computes the timeline position for an event whose coordinates
|
||||
* are in canvas units (pixels, scroll offset included). The time
|
||||
* domain used by the return value will match ::default_time_domain()
|
||||
|
|
@ -636,6 +633,7 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider,
|
|||
bool ensure_snap = false) const = 0;
|
||||
|
||||
void check_best_snap (Temporal::timepos_t const & presnap, Temporal::timepos_t &test, Temporal::timepos_t &dist, Temporal::timepos_t &best) const;
|
||||
virtual double visible_canvas_width() const = 0;
|
||||
|
||||
enum BBTRulerScale {
|
||||
bbt_show_many,
|
||||
|
|
|
|||
|
|
@ -177,6 +177,9 @@ public:
|
|||
return (samplecnt_t) _visible_canvas_width* samples_per_pixel;
|
||||
}
|
||||
|
||||
double visible_canvas_height () const {
|
||||
return _visible_canvas_height;
|
||||
}
|
||||
double trackviews_height () const;
|
||||
|
||||
XMLNode& get_state () const;
|
||||
|
|
@ -2122,6 +2125,8 @@ private:
|
|||
Temporal::timepos_t snap_to_marker (Temporal::timepos_t const & presnap,
|
||||
Temporal::RoundMode direction = Temporal::RoundNearest) const;
|
||||
|
||||
double visible_canvas_width() const { return _visible_canvas_width; }
|
||||
|
||||
RhythmFerret* rhythm_ferret;
|
||||
|
||||
void fit_tracks (TrackViewList &);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include "ardour/ardour.h"
|
||||
#include "ardour/triggerbox.h"
|
||||
|
||||
#include "trigger_properties_box.h"
|
||||
#include "audio_trigger_properties_box.h"
|
||||
|
||||
class MidiTriggerPropertiesBox : public TriggerPropertiesBox
|
||||
{
|
||||
|
|
|
|||
|
|
@ -66,13 +66,19 @@ using namespace Gtkmm2ext;
|
|||
using namespace Temporal;
|
||||
|
||||
Pianoroll::Pianoroll (std::string const & name, bool with_transport)
|
||||
: CueEditor (name, with_transport)
|
||||
: CueEditor (name)
|
||||
, timebar_height (15.)
|
||||
, n_timebars (0)
|
||||
, prh (nullptr)
|
||||
, bg (nullptr)
|
||||
, view (nullptr)
|
||||
, bbt_metric (*this)
|
||||
, _note_mode (Sustained)
|
||||
, zoom_in_allocate (false)
|
||||
, solo_button (S_("Solo|S"))
|
||||
, length_label (X_("Record:"))
|
||||
, ignore_channel_changes (false)
|
||||
, with_transport_controls (with_transport)
|
||||
, show_source (false)
|
||||
{
|
||||
mouse_mode = Editing::MouseContent;
|
||||
|
|
@ -142,6 +148,23 @@ Pianoroll::get_canvas() const
|
|||
return _canvas;
|
||||
}
|
||||
|
||||
bool
|
||||
Pianoroll::canvas_pre_event (GdkEvent* ev)
|
||||
{
|
||||
switch (ev->type) {
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
if (canvas_enter_leave (&ev->crossing)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::rebuild_parameter_button_map()
|
||||
{
|
||||
|
|
@ -251,6 +274,15 @@ Pianoroll::add_multi_controller_item (Gtk::Menu_Helpers::MenuList&,
|
|||
mb->add_item (name, menu_text, *chn_menu, [](){});
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Pianoroll::scrolled ()
|
||||
{
|
||||
pending_visual_change.add (VisualChange::TimeOrigin);
|
||||
pending_visual_change.time_origin = horizontal_adjustment.get_value() * samples_per_pixel;
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::build_lower_toolbar ()
|
||||
{
|
||||
|
|
@ -323,24 +355,145 @@ Pianoroll::build_lower_toolbar ()
|
|||
}
|
||||
|
||||
void
|
||||
Pianoroll::pack_inner (Gtk::Box& box)
|
||||
Pianoroll::build_upper_toolbar ()
|
||||
{
|
||||
box.pack_start (snap_box, false, false);
|
||||
box.pack_start (grid_box, false, false);
|
||||
box.pack_start (draw_box, false, false);
|
||||
using namespace Gtk::Menu_Helpers;
|
||||
|
||||
Gtk::HBox* mode_box = manage(new Gtk::HBox);
|
||||
mode_box->set_border_width (2);
|
||||
mode_box->set_spacing(2);
|
||||
|
||||
Gtk::HBox* mouse_mode_box = manage (new Gtk::HBox);
|
||||
Gtk::HBox* mouse_mode_hbox = manage (new Gtk::HBox);
|
||||
Gtk::VBox* mouse_mode_vbox = manage (new Gtk::VBox);
|
||||
Gtk::Alignment* mouse_mode_align = manage (new Gtk::Alignment);
|
||||
|
||||
Glib::RefPtr<Gtk::SizeGroup> mouse_mode_size_group = Gtk::SizeGroup::create (Gtk::SIZE_GROUP_VERTICAL);
|
||||
mouse_mode_size_group->add_widget (mouse_draw_button);
|
||||
mouse_mode_size_group->add_widget (mouse_content_button);
|
||||
|
||||
mouse_mode_size_group->add_widget (grid_type_selector);
|
||||
mouse_mode_size_group->add_widget (draw_length_selector);
|
||||
mouse_mode_size_group->add_widget (draw_velocity_selector);
|
||||
mouse_mode_size_group->add_widget (draw_channel_selector);
|
||||
mouse_mode_size_group->add_widget (snap_mode_button);
|
||||
|
||||
mouse_mode_hbox->set_spacing (2);
|
||||
mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
|
||||
mouse_mode_hbox->pack_start (mouse_content_button, false, false);
|
||||
|
||||
mouse_mode_vbox->pack_start (*mouse_mode_hbox);
|
||||
|
||||
mouse_mode_align->add (*mouse_mode_vbox);
|
||||
mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
|
||||
|
||||
mouse_mode_box->pack_start (*mouse_mode_align, false, false);
|
||||
|
||||
pack_snap_box ();
|
||||
pack_draw_box (false);
|
||||
|
||||
Gtk::HBox* _toolbar_inner = manage (new Gtk::HBox);
|
||||
Gtk::HBox* _toolbar_outer = manage (new Gtk::HBox);
|
||||
Gtk::HBox* _toolbar_left = manage (new Gtk::HBox);
|
||||
|
||||
_toolbar_inner->pack_start (*mouse_mode_box, false, false);
|
||||
_toolbar_inner->pack_start (snap_box, false, false);
|
||||
_toolbar_inner->pack_start (grid_box, false, false);
|
||||
_toolbar_inner->pack_start (draw_box, false, false);
|
||||
|
||||
set_tooltip (full_zoom_button, _("Zoom to full clip"));
|
||||
set_tooltip (note_mode_button, _("Toggle between drum and regular note drawing"));
|
||||
note_mode_button.set_icon (ArdourIcon::Drum);
|
||||
|
||||
play_note_selection_button.set_icon (ArdourIcon::ToolAudition);
|
||||
|
||||
#define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
|
||||
note_mode_button.set_size_request (PX_SCALE(50), -1);
|
||||
note_mode_button.set_active_color (UIConfiguration::instance().color ("alert:yellow"));
|
||||
|
||||
play_button.set_icon (ArdourIcon::TransportPlay);
|
||||
play_button.set_name ("transport button");
|
||||
play_button.show();
|
||||
|
||||
if (with_transport_controls) {
|
||||
loop_button.set_icon (ArdourIcon::TransportLoop);
|
||||
loop_button.set_name ("transport button");
|
||||
|
||||
solo_button.set_name ("solo button");
|
||||
|
||||
play_box.set_spacing (8);
|
||||
play_box.pack_start (play_button, false, false);
|
||||
play_box.pack_start (loop_button, false, false);
|
||||
play_box.pack_start (solo_button, false, false);
|
||||
loop_button.show();
|
||||
solo_button.show();
|
||||
play_box.set_no_show_all (true);
|
||||
play_box.show ();
|
||||
|
||||
play_button.signal_button_release_event().connect (sigc::mem_fun (*this, &Pianoroll::play_button_press), false);
|
||||
solo_button.signal_button_release_event().connect (sigc::mem_fun (*this, &Pianoroll::solo_button_press), false);
|
||||
loop_button.signal_button_release_event().connect (sigc::mem_fun (*this, &Pianoroll::loop_button_press), false);
|
||||
} else {
|
||||
rec_box.pack_start (play_button, false, false);
|
||||
play_button.signal_button_release_event().connect (sigc::mem_fun (*this, &Pianoroll::bang_button_press), false);
|
||||
}
|
||||
|
||||
rec_enable_button.set_icon (ArdourIcon::RecButton);
|
||||
rec_enable_button.set_sensitive (false);
|
||||
rec_enable_button.signal_button_release_event().connect (sigc::mem_fun (*this, &Pianoroll::rec_button_press), false);
|
||||
rec_enable_button.set_name ("record enable button");
|
||||
|
||||
length_selector.add_menu_elem (MenuElem (_("Until Stopped"), sigc::bind (sigc::mem_fun (*this, &Pianoroll::set_recording_length), Temporal::BBT_Offset ())));
|
||||
length_selector.add_menu_elem (MenuElem (_("1 Bar"), sigc::bind (sigc::mem_fun (*this, &Pianoroll::set_recording_length), Temporal::BBT_Offset (1, 0, 0))));
|
||||
std::vector<int> b ({ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 20, 24, 32 });
|
||||
for (auto & n : b) {
|
||||
length_selector.add_menu_elem (MenuElem (string_compose (_("%1 Bars"), n), sigc::bind (sigc::mem_fun (*this, &Pianoroll::set_recording_length), Temporal::BBT_Offset (n, 0, 0))));
|
||||
}
|
||||
length_selector.set_active (_("Until Stopped"));
|
||||
|
||||
rec_box.set_spacing (12);
|
||||
rec_box.pack_start (rec_enable_button, false, false);
|
||||
rec_box.pack_start (length_label, false, false);
|
||||
rec_box.pack_start (length_selector, false, false);
|
||||
rec_enable_button.show();
|
||||
length_label.show ();
|
||||
length_selector.show ();
|
||||
rec_box.set_no_show_all (true);
|
||||
/* rec box not shown */
|
||||
|
||||
_toolbar_outer->set_border_width (6);
|
||||
_toolbar_outer->set_spacing (12);
|
||||
if (with_transport_controls) {
|
||||
_toolbar_outer->pack_start (play_box, false, false);
|
||||
}
|
||||
_toolbar_outer->pack_start (rec_box, false, false);
|
||||
_toolbar_outer->pack_start (visible_channel_label, false, false);
|
||||
_toolbar_outer->pack_start (visible_channel_selector, false, false);
|
||||
_toolbar_outer->pack_start (play_note_selection_button, false, false);
|
||||
_toolbar_outer->pack_start (note_mode_button, false, false);
|
||||
_toolbar_outer->pack_start (follow_playhead_button, false, false);
|
||||
_toolbar_outer->pack_start (*_toolbar_inner, true, false);
|
||||
|
||||
build_zoom_focus_menu ();
|
||||
zoom_focus_selector.set_text (zoom_focus_strings[(int)_zoom_focus]);
|
||||
|
||||
_toolbar_left->pack_start (zoom_in_button, false, false);
|
||||
_toolbar_left->pack_start (zoom_out_button, false, false);
|
||||
_toolbar_left->pack_start (full_zoom_button, false, false);
|
||||
_toolbar_left->pack_start (zoom_focus_selector, false, false);
|
||||
|
||||
_toolbar_outer->pack_start (*_toolbar_left, true, false);
|
||||
_toolbox.pack_start (*_toolbar_outer, false, false);
|
||||
|
||||
_contents.add (_toolbox);
|
||||
_contents.signal_unmap().connect ([this]() {_canvas_viewport->unmap ();}, false);
|
||||
_contents.signal_map().connect ([this]() {_canvas_viewport->map ();}, false);
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::pack_outer (Gtk::Box& box)
|
||||
Pianoroll::set_recording_length (Temporal::BBT_Offset dur)
|
||||
{
|
||||
if (with_transport_controls) {
|
||||
box.pack_start (play_box, false, false);
|
||||
}
|
||||
|
||||
box.pack_start (rec_box, false, false);
|
||||
box.pack_start (visible_channel_label, false, false);
|
||||
box.pack_start (visible_channel_selector, false, false);
|
||||
box.pack_start (follow_playhead_button, false, false);
|
||||
rec_length = dur;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -504,6 +657,15 @@ Pianoroll::build_canvas ()
|
|||
_toolbox.pack_start (*_canvas_viewport, true, true);
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::catch_pending_show_region ()
|
||||
{
|
||||
if (_visible_pending_region) {
|
||||
set_region (_visible_pending_region);
|
||||
_visible_pending_region.reset ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Pianoroll::bbt_ruler_event (GdkEvent* ev)
|
||||
{
|
||||
|
|
@ -1538,6 +1700,365 @@ Pianoroll::get_state () const
|
|||
get_common_editing_state (*node);
|
||||
return *node;
|
||||
}
|
||||
|
||||
/** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
|
||||
*
|
||||
* @param allow_vert true to allow vertical autoscroll, otherwise false.
|
||||
*
|
||||
*/
|
||||
void
|
||||
Pianoroll::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
|
||||
{
|
||||
if (!UIConfiguration::instance().get_autoscroll_editor () || autoscroll_active ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* define a rectangular boundary for scrolling. If the mouse moves
|
||||
* outside of this area and/or continue to be outside of this area,
|
||||
* then we will continuously auto-scroll the canvas in the appropriate
|
||||
* direction(s)
|
||||
*
|
||||
* the boundary is defined in coordinates relative to canvas' own
|
||||
* window since that is what we're going to call ::get_pointer() on
|
||||
* during autoscrolling to determine if we're still outside the
|
||||
* boundary or not.
|
||||
*/
|
||||
|
||||
ArdourCanvas::Rect scrolling_boundary;
|
||||
Gtk::Allocation alloc;
|
||||
|
||||
alloc = get_canvas()->get_allocation ();
|
||||
|
||||
alloc.set_x (0);
|
||||
alloc.set_y (0);
|
||||
|
||||
if (allow_vert) {
|
||||
/* reduce height by the height of the timebars, which happens
|
||||
to correspond to the position of the data_group.
|
||||
*/
|
||||
|
||||
alloc.set_height (alloc.get_height() - data_group->position().y);
|
||||
alloc.set_y (alloc.get_y() + data_group->position().y);
|
||||
|
||||
/* now reduce it again so that we start autoscrolling before we
|
||||
* move off the top or bottom of the canvas
|
||||
*/
|
||||
|
||||
alloc.set_height (alloc.get_height() - 20);
|
||||
alloc.set_y (alloc.get_y() + 10);
|
||||
}
|
||||
|
||||
if (allow_horiz && (alloc.get_width() > 20)) {
|
||||
|
||||
if (prh) {
|
||||
double w, h;
|
||||
prh->size_request (w, h);
|
||||
|
||||
alloc.set_width (alloc.get_width() - w);
|
||||
alloc.set_x (alloc.get_x() + w);
|
||||
}
|
||||
|
||||
/* the effective width of the autoscroll boundary so
|
||||
that we start scrolling before we hit the edge.
|
||||
|
||||
this helps when the window is slammed up against the
|
||||
right edge of the screen, making it hard to scroll
|
||||
effectively.
|
||||
*/
|
||||
|
||||
alloc.set_width (alloc.get_width() - 20);
|
||||
alloc.set_x (alloc.get_x() + 10);
|
||||
}
|
||||
|
||||
scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(), alloc.get_x() + alloc.get_width(), alloc.get_y() + alloc.get_height());
|
||||
|
||||
int x, y;
|
||||
Gdk::ModifierType mask;
|
||||
|
||||
get_canvas()->get_window()->get_pointer (x, y, mask);
|
||||
|
||||
if ((allow_horiz && ((x < scrolling_boundary.x0 && _leftmost_sample > 0) || x >= scrolling_boundary.x1)) ||
|
||||
(allow_vert && ((y < scrolling_boundary.y0 && vertical_adjustment.get_value() > 0)|| y >= scrolling_boundary.y1))) {
|
||||
start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Pianoroll::autoscroll_active () const
|
||||
{
|
||||
return autoscroll_connection.connected ();
|
||||
}
|
||||
|
||||
bool
|
||||
Pianoroll::autoscroll_canvas ()
|
||||
{
|
||||
using std::max;
|
||||
using std::min;
|
||||
int x, y;
|
||||
Gdk::ModifierType mask;
|
||||
sampleoffset_t dx = 0;
|
||||
bool no_stop = false;
|
||||
Gtk::Window* toplevel = dynamic_cast<Gtk::Window*>(_canvas_viewport->get_toplevel());
|
||||
|
||||
if (!toplevel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
get_canvas()->get_window()->get_pointer (x, y, mask);
|
||||
|
||||
VisualChange vc;
|
||||
bool vertical_motion = false;
|
||||
|
||||
if (autoscroll_horizontal_allowed) {
|
||||
|
||||
samplepos_t new_sample = _leftmost_sample;
|
||||
|
||||
/* horizontal */
|
||||
|
||||
if (x > autoscroll_boundary.x1) {
|
||||
|
||||
/* bring it back into view */
|
||||
dx = x - autoscroll_boundary.x1;
|
||||
dx += 10 + (2 * (autoscroll_cnt/2));
|
||||
|
||||
dx = pixel_to_sample (dx);
|
||||
|
||||
dx *= UIConfiguration::instance().get_draggable_playhead_speed();
|
||||
|
||||
if (_leftmost_sample < max_samplepos - dx) {
|
||||
new_sample = _leftmost_sample + dx;
|
||||
} else {
|
||||
new_sample = max_samplepos;
|
||||
}
|
||||
|
||||
no_stop = true;
|
||||
|
||||
} else if (x < autoscroll_boundary.x0) {
|
||||
|
||||
dx = autoscroll_boundary.x0 - x;
|
||||
dx += 10 + (2 * (autoscroll_cnt/2));
|
||||
|
||||
dx = pixel_to_sample (dx);
|
||||
|
||||
dx *= UIConfiguration::instance().get_draggable_playhead_speed();
|
||||
|
||||
if (_leftmost_sample >= dx) {
|
||||
new_sample = _leftmost_sample - dx;
|
||||
} else {
|
||||
new_sample = 0;
|
||||
}
|
||||
|
||||
no_stop = true;
|
||||
}
|
||||
|
||||
if (new_sample != _leftmost_sample) {
|
||||
vc.time_origin = new_sample;
|
||||
vc.add (VisualChange::TimeOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
if (autoscroll_vertical_allowed) {
|
||||
|
||||
// const double vertical_pos = vertical_adjustment.get_value();
|
||||
const int speed_factor = 10;
|
||||
|
||||
/* vertical */
|
||||
|
||||
if (y < autoscroll_boundary.y0) {
|
||||
|
||||
/* scroll to make higher tracks visible */
|
||||
|
||||
if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
|
||||
// XXX SCROLL UP
|
||||
vertical_motion = true;
|
||||
}
|
||||
no_stop = true;
|
||||
|
||||
} else if (y > autoscroll_boundary.y1) {
|
||||
|
||||
if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
|
||||
// XXX SCROLL DOWN
|
||||
vertical_motion = true;
|
||||
}
|
||||
no_stop = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (vc.pending || vertical_motion) {
|
||||
|
||||
/* change horizontal first */
|
||||
|
||||
if (vc.pending) {
|
||||
visual_changer (vc);
|
||||
}
|
||||
|
||||
/* now send a motion event to notify anyone who cares
|
||||
that we have moved to a new location (because we scrolled)
|
||||
*/
|
||||
|
||||
GdkEventMotion ev;
|
||||
|
||||
ev.type = GDK_MOTION_NOTIFY;
|
||||
ev.state = Gdk::BUTTON1_MASK;
|
||||
|
||||
/* the motion handler expects events in canvas coordinate space */
|
||||
|
||||
/* we asked for the mouse position above (::get_pointer()) via
|
||||
* our own top level window (we being the Editor). Convert into
|
||||
* coordinates within the canvas window.
|
||||
*/
|
||||
|
||||
int cx;
|
||||
int cy;
|
||||
|
||||
//toplevel->translate_coordinates (*get_canvas(), x, y, cx,
|
||||
//cy);
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
/* clamp x and y to remain within the autoscroll boundary,
|
||||
* which is defined in window coordinates
|
||||
*/
|
||||
|
||||
x = min (max ((ArdourCanvas::Coord) cx, autoscroll_boundary.x0), autoscroll_boundary.x1);
|
||||
y = min (max ((ArdourCanvas::Coord) cy, autoscroll_boundary.y0), autoscroll_boundary.y1);
|
||||
|
||||
/* now convert from Editor window coordinates to canvas
|
||||
* window coordinates
|
||||
*/
|
||||
|
||||
ArdourCanvas::Duple d = get_canvas()->window_to_canvas (ArdourCanvas::Duple (cx, cy));
|
||||
ev.x = d.x;
|
||||
ev.y = d.y;
|
||||
ev.state = mask;
|
||||
|
||||
motion_handler (0, (GdkEvent*) &ev, true);
|
||||
|
||||
} else if (no_stop) {
|
||||
|
||||
/* not changing visual state but pointer is outside the scrolling boundary
|
||||
* so we still need to deliver a fake motion event
|
||||
*/
|
||||
|
||||
GdkEventMotion ev;
|
||||
|
||||
ev.type = GDK_MOTION_NOTIFY;
|
||||
ev.state = Gdk::BUTTON1_MASK;
|
||||
|
||||
/* the motion handler expects events in canvas coordinate space */
|
||||
|
||||
/* first convert from Editor window coordinates to canvas
|
||||
* window coordinates
|
||||
*/
|
||||
|
||||
int cx;
|
||||
int cy;
|
||||
|
||||
/* clamp x and y to remain within the visible area. except
|
||||
* .. if horizontal scrolling is allowed, always allow us to
|
||||
* move back to zero
|
||||
*/
|
||||
|
||||
if (autoscroll_horizontal_allowed) {
|
||||
x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
|
||||
} else {
|
||||
x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
|
||||
}
|
||||
y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
|
||||
|
||||
// toplevel->translate_coordinates (*get_canvas_viewport(), x,
|
||||
// y, cx, cy);
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
ArdourCanvas::Duple d = get_canvas()->window_to_canvas (ArdourCanvas::Duple (cx, cy));
|
||||
ev.x = d.x;
|
||||
ev.y = d.y;
|
||||
ev.state = mask;
|
||||
|
||||
motion_handler (0, (GdkEvent*) &ev, true);
|
||||
|
||||
} else {
|
||||
stop_canvas_autoscroll ();
|
||||
return false;
|
||||
}
|
||||
|
||||
autoscroll_cnt++;
|
||||
|
||||
return true; /* call me again */
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
|
||||
{
|
||||
if (!_session) {
|
||||
return;
|
||||
}
|
||||
|
||||
stop_canvas_autoscroll ();
|
||||
|
||||
autoscroll_horizontal_allowed = allow_horiz;
|
||||
autoscroll_vertical_allowed = allow_vert;
|
||||
autoscroll_boundary = boundary;
|
||||
|
||||
/* do the first scroll right now
|
||||
*/
|
||||
|
||||
autoscroll_canvas ();
|
||||
|
||||
/* scroll again at very very roughly 30FPS */
|
||||
|
||||
autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Pianoroll::autoscroll_canvas), 30);
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::stop_canvas_autoscroll ()
|
||||
{
|
||||
autoscroll_connection.disconnect ();
|
||||
autoscroll_cnt = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::visual_changer (const VisualChange& vc)
|
||||
{
|
||||
/**
|
||||
* Changed first so the correct horizontal canvas position is calculated in
|
||||
* EditingContext::set_horizontal_position
|
||||
*/
|
||||
if (vc.pending & VisualChange::ZoomLevel) {
|
||||
set_samples_per_pixel (vc.samples_per_pixel);
|
||||
}
|
||||
|
||||
if (vc.pending & VisualChange::TimeOrigin) {
|
||||
double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
|
||||
set_horizontal_position (new_time_origin);
|
||||
update_tempo_based_rulers ();
|
||||
}
|
||||
|
||||
if (vc.pending & VisualChange::YOrigin) {
|
||||
vertical_adjustment.set_value (vc.y_origin);
|
||||
}
|
||||
|
||||
if (vc.pending & VisualChange::ZoomLevel) {
|
||||
if (!(vc.pending & VisualChange::TimeOrigin)) {
|
||||
update_tempo_based_rulers ();
|
||||
}
|
||||
} else {
|
||||
/* If the canvas is not being zoomed then the canvas items will not change
|
||||
* and cause Item::prepare_for_render to be called so do it here manually.
|
||||
* Not ideal, but I can't think of a better solution atm.
|
||||
*/
|
||||
get_canvas()->prepare_for_render();
|
||||
}
|
||||
|
||||
/* If we are only scrolling vertically there is no need to update these */
|
||||
if (vc.pending != VisualChange::YOrigin) {
|
||||
// XXX update_fixed_rulers ();
|
||||
redisplay_grid (true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::midi_action (void (MidiView::*method)())
|
||||
{
|
||||
|
|
@ -1775,15 +2296,65 @@ Pianoroll::region_prop_change (PBD::PropertyChange const & what_changed)
|
|||
}
|
||||
|
||||
void
|
||||
Pianoroll::maybe_set_count_in ()
|
||||
Pianoroll::blink_rec_enable (bool onoff)
|
||||
{
|
||||
if (!ref.box()) {
|
||||
std::cerr << "msci no box\n";
|
||||
if (onoff) {
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::ExplicitActive);
|
||||
} else {
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::Off);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::trigger_arm_change ()
|
||||
{
|
||||
if (!ref.trigger()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ref.box()->record_enabled() == Disabled) {
|
||||
std::cerr << "msci RE\n";
|
||||
if (!ref.trigger()->armed()) {
|
||||
view->end_write ();
|
||||
}
|
||||
|
||||
rec_enable_change ();
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::rec_enable_change ()
|
||||
{
|
||||
if (!ref.box()) {
|
||||
return;
|
||||
}
|
||||
|
||||
rec_blink_connection.disconnect ();
|
||||
count_in_connection.disconnect ();
|
||||
|
||||
switch (ref.box()->record_enabled()) {
|
||||
case Recording:
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::ExplicitActive);
|
||||
rec_blink_connection.disconnect ();
|
||||
if (view) {
|
||||
view->begin_write ();
|
||||
}
|
||||
break;
|
||||
case Enabled:
|
||||
if (!UIConfiguration::instance().get_no_strobe() && ref.trigger()->armed()) {
|
||||
rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &Pianoroll::blink_rec_enable));
|
||||
} else {
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::Off);
|
||||
}
|
||||
maybe_set_count_in ();
|
||||
break;
|
||||
case Disabled:
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::Off);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::maybe_set_count_in ()
|
||||
{
|
||||
if (!ref.box()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1794,7 +2365,6 @@ Pianoroll::maybe_set_count_in ()
|
|||
count_in_to = ref.box()->start_time (valid);
|
||||
|
||||
if (!valid) {
|
||||
std::cerr << "no start time\n";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1802,12 +2372,10 @@ Pianoroll::maybe_set_count_in ()
|
|||
Temporal::Beats const & a_q (tmap->quarters_at_sample (audible));
|
||||
|
||||
if ((count_in_to - a_q).get_beats() == 0) {
|
||||
std::cerr << "not enough time\n";
|
||||
return;
|
||||
}
|
||||
|
||||
count_in_connection = ARDOUR_UI::Clock.connect (sigc::bind (sigc::mem_fun (*this, &Pianoroll::count_in), ARDOUR_UI::clock_signal_interval()));
|
||||
std::cerr << "count in started, with view " << view << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1850,23 +2418,92 @@ Pianoroll::count_in (Temporal::timepos_t audible, unsigned int clock_interval_ms
|
|||
}
|
||||
|
||||
std::string str (string_compose ("%1", current_delta.get_beats()));
|
||||
std::cerr << str << std::endl;
|
||||
view->set_overlay_text (str);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::set_region (std::shared_ptr<ARDOUR::Region> r)
|
||||
bool
|
||||
Pianoroll::play_button_press (GdkEventButton* ev)
|
||||
{
|
||||
set_region (std::dynamic_pointer_cast<ARDOUR::MidiRegion> (r));
|
||||
_session->request_locate (view->midi_region()->position().samples());
|
||||
_session->request_roll ();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Pianoroll::bang_button_press (GdkEventButton* ev)
|
||||
{
|
||||
if (!ref.trigger()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ref.trigger()->bang ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Pianoroll::loop_button_press (GdkEventButton* ev)
|
||||
{
|
||||
if (!view) {
|
||||
return true;
|
||||
}
|
||||
if (!view->midi_region()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_session->get_play_loop()) {
|
||||
_session->request_play_loop (false);
|
||||
} else {
|
||||
set_loop_range (view->midi_region()->position(), view->midi_region()->end(), _("loop region"));
|
||||
_session->request_play_loop (true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Pianoroll::solo_button_press (GdkEventButton* ev)
|
||||
{
|
||||
if (!view) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!view->midi_track()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
view->midi_track()->solo_control()->set_value (!view->midi_track()->solo_control()->get_value(), Controllable::NoGroup);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Pianoroll::rec_button_press (GdkEventButton* ev)
|
||||
{
|
||||
if (ev->button != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TriggerPtr trigger (ref.trigger());
|
||||
|
||||
if (!trigger) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (trigger->armed()) {
|
||||
trigger->disarm ();
|
||||
} else {
|
||||
trigger->arm (rec_length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::set_trigger (TriggerReference & tref)
|
||||
{
|
||||
std::cerr << "set trigger\n";
|
||||
PBD::stacktrace (std::cerr, 17);
|
||||
|
||||
if (tref.trigger() == ref.trigger()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1885,8 +2522,6 @@ Pianoroll::set_trigger (TriggerReference & tref)
|
|||
/* Don't bind a shared_ptr<TriggerBox> within the lambda */
|
||||
TriggerBox* tb (ref.box().get());
|
||||
tb->RecEnableChanged.connect (object_connections, invalidator (*this), std::bind (&Pianoroll::rec_enable_change, this), gui_context());
|
||||
std::cerr << "connected to box " << tb->order() << std::endl;
|
||||
maybe_set_count_in ();
|
||||
|
||||
Stripable* st = dynamic_cast<Stripable*> (ref.box()->owner());
|
||||
assert (st);
|
||||
|
|
@ -1942,7 +2577,6 @@ Pianoroll::unset (bool trigger_too)
|
|||
_history.clear ();
|
||||
_update_connection.disconnect();
|
||||
object_connections.drop_connections ();
|
||||
std::cerr << "disconnected\n";
|
||||
_track.reset ();
|
||||
view->set_region (nullptr);
|
||||
if (trigger_too) {
|
||||
|
|
@ -1997,9 +2631,6 @@ Pianoroll::set_region (std::shared_ptr<ARDOUR::MidiRegion> r)
|
|||
return;
|
||||
}
|
||||
|
||||
std::cerr << editor_name() << " set region to " << r << std::endl;
|
||||
PBD::stacktrace (std::cerr, 19);
|
||||
|
||||
unset (false);
|
||||
|
||||
if (!r) {
|
||||
|
|
@ -2195,6 +2826,20 @@ Pianoroll::set_note_mode (NoteMode nm)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::build_zoom_focus_menu ()
|
||||
{
|
||||
using namespace Gtk::Menu_Helpers;
|
||||
using namespace Editing;
|
||||
|
||||
zoom_focus_selector.add_menu_elem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &EditingContext::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
|
||||
zoom_focus_selector.add_menu_elem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &EditingContext::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
|
||||
zoom_focus_selector.add_menu_elem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &EditingContext::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
|
||||
zoom_focus_selector.add_menu_elem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &EditingContext::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
|
||||
zoom_focus_selector.set_sizing_texts (zoom_focus_strings);
|
||||
}
|
||||
|
||||
|
||||
std::pair<Temporal::timepos_t,Temporal::timepos_t>
|
||||
Pianoroll::max_zoom_extent() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ class Pianoroll : public CueEditor
|
|||
Gtk::Widget& viewport();
|
||||
Gtk::Widget& contents ();
|
||||
|
||||
double visible_canvas_width() const { return _visible_canvas_width; }
|
||||
samplecnt_t current_page_samples() const;
|
||||
|
||||
void get_per_region_note_selection (std::list<std::pair<PBD::ID, std::set<std::shared_ptr<Evoral::Note<Temporal::Beats> > > > >&) const {}
|
||||
|
|
@ -83,7 +84,6 @@ class Pianoroll : public CueEditor
|
|||
|
||||
void set_trigger (ARDOUR::TriggerReference&);
|
||||
void set_region (std::shared_ptr<ARDOUR::MidiRegion>);
|
||||
void set_region (std::shared_ptr<ARDOUR::Region> r);
|
||||
void set_track (std::shared_ptr<ARDOUR::MidiTrack>);
|
||||
|
||||
ArdourCanvas::ScrollGroup* get_hscroll_group () const { return h_scroll_group; }
|
||||
|
|
@ -97,12 +97,20 @@ class Pianoroll : public CueEditor
|
|||
Editing::MouseMode current_mouse_mode () const;
|
||||
bool internal_editing() const;
|
||||
|
||||
void trigger_arm_change ();
|
||||
|
||||
double timebar_height;
|
||||
size_t n_timebars;
|
||||
|
||||
ArdourCanvas::GtkCanvasViewport* get_canvas_viewport() const;
|
||||
ArdourCanvas::GtkCanvas* get_canvas() const;
|
||||
|
||||
int set_state (const XMLNode&, int version);
|
||||
XMLNode& get_state () const;
|
||||
|
||||
void maybe_autoscroll (bool, bool, bool);
|
||||
bool autoscroll_active() const;
|
||||
|
||||
void midi_action (void (MidiView::*method)());
|
||||
|
||||
std::list<SelectableOwner*> selectable_owners();
|
||||
|
|
@ -175,14 +183,41 @@ class Pianoroll : public CueEditor
|
|||
void escape ();
|
||||
|
||||
private:
|
||||
ARDOUR::TriggerReference ref;
|
||||
std::shared_ptr<ARDOUR::MidiTrack> _track;
|
||||
ArdourCanvas::GtkCanvasViewport* _canvas_viewport;
|
||||
ArdourCanvas::GtkCanvas* _canvas;
|
||||
|
||||
Gtk::HScrollbar* _canvas_hscrollbar;
|
||||
|
||||
/* The group containing all other groups that are scrolled vertically
|
||||
and horizontally.
|
||||
*/
|
||||
ArdourCanvas::ScrollGroup* hv_scroll_group;
|
||||
|
||||
/* The group containing all other groups that are scrolled horizontally ONLY
|
||||
*/
|
||||
ArdourCanvas::ScrollGroup* h_scroll_group;
|
||||
ArdourCanvas::ScrollGroup* v_scroll_group;
|
||||
|
||||
/* Scroll group for cursors, scrolled horizontally, above everything else
|
||||
*/
|
||||
ArdourCanvas::ScrollGroup* cursor_scroll_group;
|
||||
|
||||
ArdourCanvas::Container* global_rect_group;
|
||||
ArdourCanvas::Container* no_scroll_group;
|
||||
ArdourCanvas::Container* data_group;
|
||||
ArdourCanvas::Ruler* bbt_ruler;
|
||||
ArdourCanvas::Rectangle* tempo_bar;
|
||||
ArdourCanvas::Rectangle* meter_bar;
|
||||
ArdourCanvas::PianoRollHeader* prh;
|
||||
|
||||
ArdourCanvas::Rectangle* transport_loop_range_rect;
|
||||
|
||||
ArdourWidgets::EventBoxExt _contents;
|
||||
Gtk::VBox _toolbox;
|
||||
|
||||
Gtk::HBox button_bar;
|
||||
ArdourWidgets::ArdourButton* velocity_button;
|
||||
ArdourWidgets::ArdourButton* bender_button;
|
||||
ArdourWidgets::ArdourButton* pressure_button;
|
||||
|
|
@ -225,6 +260,14 @@ class Pianoroll : public CueEditor
|
|||
|
||||
BBTMetric bbt_metric;
|
||||
|
||||
bool canvas_pre_event (GdkEvent*);
|
||||
|
||||
/* autoscrolling */
|
||||
|
||||
bool autoscroll_canvas ();
|
||||
void start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary);
|
||||
void stop_canvas_autoscroll ();
|
||||
|
||||
sigc::connection _update_connection;
|
||||
PBD::ScopedConnectionList object_connections;
|
||||
PBD::ScopedConnectionList view_connections;
|
||||
|
|
@ -234,6 +277,7 @@ class Pianoroll : public CueEditor
|
|||
|
||||
void unset (bool trigger_too);
|
||||
|
||||
void visual_changer (const VisualChange&);
|
||||
void bindings_changed ();
|
||||
|
||||
void data_captured (samplecnt_t);
|
||||
|
|
@ -255,10 +299,37 @@ class Pianoroll : public CueEditor
|
|||
|
||||
void automation_state_changed ();
|
||||
|
||||
void build_zoom_focus_menu ();
|
||||
|
||||
std::pair<Temporal::timepos_t,Temporal::timepos_t> max_zoom_extent() const;
|
||||
|
||||
void point_selection_changed ();
|
||||
|
||||
bool zoom_in_allocate;
|
||||
|
||||
ArdourWidgets::ArdourButton rec_enable_button;
|
||||
ArdourWidgets::ArdourButton play_button;
|
||||
ArdourWidgets::ArdourButton solo_button;
|
||||
ArdourWidgets::ArdourButton loop_button;
|
||||
|
||||
bool play_button_press (GdkEventButton*);
|
||||
bool bang_button_press (GdkEventButton*);
|
||||
bool solo_button_press (GdkEventButton*);
|
||||
bool loop_button_press (GdkEventButton*);
|
||||
|
||||
ArdourWidgets::ArdourDropdown length_selector;
|
||||
Temporal::BBT_Offset rec_length;
|
||||
Gtk::Label length_label;
|
||||
Gtk::HBox rec_box;
|
||||
Gtk::HBox play_box;
|
||||
|
||||
void set_recording_length (Temporal::BBT_Offset bars);
|
||||
|
||||
bool rec_button_press (GdkEventButton*);
|
||||
void rec_enable_change ();
|
||||
void blink_rec_enable (bool);
|
||||
sigc::connection rec_blink_connection;
|
||||
|
||||
void add_single_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, int ctl, const std::string& name, ArdourWidgets::MetaButton*);
|
||||
void add_multi_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, uint16_t channels, int ctl, const std::string& name, ArdourWidgets::MetaButton*);
|
||||
void reset_user_cc_choice (std::string, Evoral::Parameter param, ArdourWidgets::MetaButton*);
|
||||
|
|
@ -278,18 +349,18 @@ class Pianoroll : public CueEditor
|
|||
|
||||
bool bbt_ruler_event (GdkEvent*);
|
||||
void ruler_locate (GdkEventButton*);
|
||||
void scrolled ();
|
||||
void update_tempo_based_rulers ();
|
||||
void update_rulers() { update_tempo_based_rulers (); }
|
||||
|
||||
Gtk::Menu _region_context_menu;
|
||||
void popup_region_context_menu (ArdourCanvas::Item* item, GdkEvent* event);
|
||||
|
||||
std::shared_ptr<ARDOUR::MidiRegion> _visible_pending_region;
|
||||
void catch_pending_show_region ();
|
||||
|
||||
bool show_source;
|
||||
void set_note_selection (uint8_t note);
|
||||
void add_note_selection (uint8_t note);
|
||||
void extend_note_selection (uint8_t note);
|
||||
void toggle_note_selection (uint8_t note);
|
||||
|
||||
void pack_inner (Gtk::Box&);
|
||||
void pack_outer (Gtk::Box&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -287,6 +287,8 @@ public:
|
|||
/** @return true if the playhead is currently being dragged, otherwise false */
|
||||
virtual bool dragging_playhead () const = 0;
|
||||
virtual samplepos_t leftmost_sample() const = 0;
|
||||
virtual samplecnt_t current_page_samples() const = 0;
|
||||
virtual double visible_canvas_height () const = 0;
|
||||
virtual void ensure_time_axis_view_is_visible (TimeAxisView const & tav, bool at_top = false) = 0;
|
||||
virtual void override_visible_track_count () = 0;
|
||||
virtual void scroll_tracks_down_line () = 0;
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ TriggerPage::TriggerPage ()
|
|||
_sidebar_pager2.set_index (3);
|
||||
|
||||
_midi_editor = new Pianoroll (X_("MIDICueEditor"));
|
||||
_audio_editor = new AudioClipEditor (X_("AudioClipEditor"), true);
|
||||
|
||||
/* Bottom -- Properties of selected Slot/Region */
|
||||
|
||||
|
|
@ -476,7 +475,9 @@ TriggerPage::trigger_arm_changed (Trigger const * trigger)
|
|||
|
||||
/* hide everything */
|
||||
|
||||
hide_all ();
|
||||
_audio_trig_box.hide ();
|
||||
_midi_trig_box.hide ();
|
||||
_midi_editor->viewport().hide ();
|
||||
|
||||
Tabbable::showhide_att_bottom (false);
|
||||
|
||||
|
|
@ -484,12 +485,10 @@ TriggerPage::trigger_arm_changed (Trigger const * trigger)
|
|||
TriggerReference ref (trigger->boxptr(), trigger->index());
|
||||
|
||||
if (box.data_type () == DataType::AUDIO) {
|
||||
|
||||
if (trigger->the_region()) {
|
||||
_audio_trig_box.set_trigger (ref);
|
||||
_audio_trig_box.show ();
|
||||
|
||||
// _audio_editor->set_trigger (ref);
|
||||
_audio_editor->viewport().show ();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -505,30 +504,20 @@ TriggerPage::trigger_arm_changed (Trigger const * trigger)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
TriggerPage::hide_all ()
|
||||
{
|
||||
_audio_trig_box.hide ();
|
||||
_audio_editor->viewport().hide ();
|
||||
_audio_trig_box.hide ();
|
||||
_midi_trig_box.hide ();
|
||||
}
|
||||
|
||||
void
|
||||
TriggerPage::selection_changed ()
|
||||
{
|
||||
Selection& selection (Editor::instance ().get_selection ());
|
||||
|
||||
hide_all ();
|
||||
/* hide everything */
|
||||
|
||||
_audio_trig_box.hide ();
|
||||
_midi_trig_box.hide ();
|
||||
|
||||
if (_midi_editor->contents().get_parent()) {
|
||||
_midi_editor->contents().get_parent()->remove (_midi_editor->contents());
|
||||
}
|
||||
|
||||
if (_audio_editor->contents().get_parent()) {
|
||||
_audio_editor->contents().get_parent()->remove (_audio_editor->contents());
|
||||
}
|
||||
|
||||
Tabbable::showhide_att_bottom (false);
|
||||
|
||||
if (selection.triggers.empty ()) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include "widgets/tabbable.h"
|
||||
|
||||
#include "application_bar.h"
|
||||
#include "audio_clip_editor.h"
|
||||
#include "audio_region_operations_box.h"
|
||||
#include "audio_trigger_properties_box.h"
|
||||
#include "axis_provider.h"
|
||||
|
|
@ -77,7 +76,7 @@ private:
|
|||
void remove_route (TriggerStrip*);
|
||||
|
||||
void clear_selected_slot ();
|
||||
void hide_all ();
|
||||
|
||||
void redisplay_track_list ();
|
||||
void pi_property_changed (PBD::PropertyChange const&);
|
||||
void stripable_property_changed (PBD::PropertyChange const&, std::weak_ptr<ARDOUR::Stripable>);
|
||||
|
|
@ -141,10 +140,10 @@ private:
|
|||
|
||||
#if REGION_PROPERTIES_BOX_TODO
|
||||
AudioRegionOperationsBox _audio_ops_box;
|
||||
AudioClipEditorBox _audio_trim_box;
|
||||
#endif
|
||||
|
||||
Pianoroll* _midi_editor;
|
||||
AudioClipEditor* _audio_editor;
|
||||
|
||||
RouteProcessorSelection _selection;
|
||||
std::list<TriggerStrip*> _strips;
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Paul Davis <paul@linuxaudiosystems.com>
|
||||
* Copyright (C) 2021 Ben Loftis <ben@harrisonconsoles.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ytkmm/label.h>
|
||||
#include <ytkmm/table.h>
|
||||
|
||||
#include "pbd/signals.h"
|
||||
|
||||
#include "ardour/session_handle.h"
|
||||
|
||||
#include "trigger_ui.h"
|
||||
|
||||
class TriggerPropertiesBox : public Gtk::Table, public ARDOUR::SessionHandlePtr, public TriggerUI
|
||||
{
|
||||
public:
|
||||
TriggerPropertiesBox () {}
|
||||
~TriggerPropertiesBox () {}
|
||||
|
||||
protected:
|
||||
Gtk::Label _header_label;
|
||||
|
||||
PBD::ScopedConnection _state_connection;
|
||||
};
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
|||
void arm (Temporal::BBT_Offset duration = Temporal::BBT_Offset()) {
|
||||
_arm (duration);
|
||||
}
|
||||
virtual void disarm (bool disarm_box = true);
|
||||
virtual void disarm ();
|
||||
bool armed() const { return _armed; }
|
||||
PBD::Signal<void()> ArmChanged;
|
||||
static PBD::Signal<void(Trigger const *)> TriggerArmChanged;
|
||||
|
|
@ -353,11 +353,11 @@ class LIBARDOUR_API Trigger : public PBD::Stateful {
|
|||
|
||||
bool compute_quantized_transition (samplepos_t start_sample, Temporal::Beats const & start, Temporal::Beats const & end,
|
||||
Temporal::BBT_Argument& t_bbt, Temporal::Beats& t_beats, samplepos_t& t_samples,
|
||||
Temporal::TempoMap::SharedPtr const & tmap, Temporal::BBT_Offset const & q, int multiple = 0);
|
||||
Temporal::TempoMap::SharedPtr const & tmap, Temporal::BBT_Offset const & q);
|
||||
|
||||
pframes_t compute_next_transition (samplepos_t start_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t nframes,
|
||||
Temporal::BBT_Argument& t_bbt, Temporal::Beats& t_beats, samplepos_t& t_samples,
|
||||
Temporal::TempoMap::SharedPtr const & tmap, int multiple = 0);
|
||||
Temporal::TempoMap::SharedPtr const & tmap);
|
||||
|
||||
|
||||
template<typename TriggerType>
|
||||
|
|
@ -616,7 +616,7 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
|
|||
bool playable() const { return rt_midibuffer.load() || _region; }
|
||||
|
||||
void captured (SlotArmInfo&, BufferSet&);
|
||||
void disarm (bool disarm_box);
|
||||
void disarm ();
|
||||
|
||||
template<bool actually_run> pframes_t midi_run (BufferSet&, samplepos_t start_sample, samplepos_t end_sample,
|
||||
Temporal::Beats const & start_beats, Temporal::Beats const & end_beats, pframes_t nframes, pframes_t offset, double bpm, pframes_t& quantize_offset);
|
||||
|
|
@ -848,8 +848,8 @@ class LIBARDOUR_API TriggerBox : public Processor, public std::enable_shared_fro
|
|||
static PBD::Signal<void()> TriggerRecEnableChanged;
|
||||
|
||||
void arm_from_another_thread (Trigger& slot, samplepos_t, uint32_t chans, Temporal::BBT_Offset const &);
|
||||
void disarm ();
|
||||
void disarm_all(bool disarm_box);
|
||||
void disarm();
|
||||
void disarm_all();
|
||||
bool armed() const { return (bool) _arm_info.load(); }
|
||||
PBD::Signal<void()> ArmedChanged;
|
||||
|
||||
|
|
|
|||
|
|
@ -909,19 +909,6 @@ Session::request_stop (bool abort, bool clear_state, TransportRequestSource orig
|
|||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouteList const> rl (routes.reader());
|
||||
for (auto & r : *rl) {
|
||||
std::shared_ptr<TriggerBox> tb = r->triggerbox();
|
||||
bool was_clip_recording = false;
|
||||
if (tb && tb->record_enabled() == Recording) {
|
||||
tb->disarm_all (false);
|
||||
was_clip_recording = true;
|
||||
}
|
||||
if (was_clip_recording) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* clear our solo-selection, if there is one */
|
||||
if ( solo_selection_active() ) {
|
||||
solo_selection ( _soloSelection, false );
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ Trigger::_arm (Temporal::BBT_Offset const & duration)
|
|||
|
||||
/* trigger arming is mutually exclusive within a given TriggerBox */
|
||||
|
||||
_box.disarm_all (true);
|
||||
_box.disarm_all ();
|
||||
|
||||
int chns;
|
||||
|
||||
|
|
@ -329,18 +329,14 @@ Trigger::_arm (Temporal::BBT_Offset const & duration)
|
|||
}
|
||||
|
||||
void
|
||||
Trigger::disarm (bool disarm_box)
|
||||
Trigger::disarm ()
|
||||
{
|
||||
if (_armed) {
|
||||
_armed = false;
|
||||
if (disarm_box) {
|
||||
_box.disarm ();
|
||||
}
|
||||
ArmChanged(); /* EMIT SIGNAL */
|
||||
if (disarm_box) {
|
||||
TriggerArmChanged (this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1044,7 +1040,7 @@ Trigger::compute_start (Temporal::TempoMap::SharedPtr const & tmap, samplepos_t
|
|||
bool
|
||||
Trigger::compute_quantized_transition (samplepos_t start_sample, Temporal::Beats const & start_beats, Temporal::Beats const & end_beats,
|
||||
Temporal::BBT_Argument& t_bbt, Temporal::Beats& t_beats, samplepos_t& t_samples,
|
||||
Temporal::TempoMap::SharedPtr const & tmap, Temporal::BBT_Offset const & q, int multiplier)
|
||||
Temporal::TempoMap::SharedPtr const & tmap, Temporal::BBT_Offset const & q)
|
||||
{
|
||||
/* XXX need to use global grid here is quantization == zero */
|
||||
|
||||
|
|
@ -1065,9 +1061,7 @@ Trigger::compute_quantized_transition (samplepos_t start_sample, Temporal::Beats
|
|||
|
||||
} else if (q.bars == 0) {
|
||||
|
||||
Temporal::Beats qb (q.beats, q.ticks);
|
||||
possible_beats = start_beats.round_up_to_multiple (qb);
|
||||
possible_beats += (qb * multiplier);
|
||||
possible_beats = start_beats.round_up_to_multiple (Temporal::Beats (q.beats, q.ticks));
|
||||
possible_bbt = tmap->bbt_at (possible_beats);
|
||||
possible_samples = tmap->sample_at (possible_beats);
|
||||
|
||||
|
|
@ -1084,7 +1078,6 @@ Trigger::compute_quantized_transition (samplepos_t start_sample, Temporal::Beats
|
|||
if (possible_beats % qb != Temporal::Beats()) {
|
||||
possible_beats = ((tmap->quarters_at (start) + (qb/2)) / qb) * qb;
|
||||
}
|
||||
possible_beats += (qb * multiplier);
|
||||
possible_bbt = tmap->bbt_at (possible_beats);
|
||||
possible_samples = tmap->sample_at (possible_beats);
|
||||
|
||||
|
|
@ -1109,7 +1102,7 @@ Trigger::compute_quantized_transition (samplepos_t start_sample, Temporal::Beats
|
|||
pframes_t
|
||||
Trigger::compute_next_transition (samplepos_t start_sample, Temporal::Beats const & start, Temporal::Beats const & end, pframes_t nframes,
|
||||
Temporal::BBT_Argument& t_bbt, Temporal::Beats& t_beats, samplepos_t& t_samples,
|
||||
Temporal::TempoMap::SharedPtr const & tmap, int multiple)
|
||||
Temporal::TempoMap::SharedPtr const & tmap)
|
||||
{
|
||||
using namespace Temporal;
|
||||
|
||||
|
|
@ -1134,7 +1127,7 @@ Trigger::compute_next_transition (samplepos_t start_sample, Temporal::Beats cons
|
|||
|
||||
}
|
||||
|
||||
if (!compute_quantized_transition (start_sample, start, end, t_bbt, t_beats, t_samples, tmap, q, multiple)) {
|
||||
if (!compute_quantized_transition (start_sample, start, end, t_bbt, t_beats, t_samples, tmap, q)) {
|
||||
/* no transition */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2542,16 +2535,16 @@ MIDITrigger::_arm (Temporal::BBT_Offset const & duration)
|
|||
}
|
||||
|
||||
void
|
||||
MIDITrigger::disarm (bool disarm_box)
|
||||
MIDITrigger::disarm ()
|
||||
{
|
||||
Trigger::disarm (disarm_box);
|
||||
Trigger::disarm ();
|
||||
}
|
||||
|
||||
void
|
||||
MIDITrigger::captured (SlotArmInfo& ai, BufferSet& bufs)
|
||||
{
|
||||
if (ai.midi_buf->size() == 0) {
|
||||
disarm (true);
|
||||
disarm ();
|
||||
DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1/%2 captured but with no MIDI data\n", _box.order(), index()));
|
||||
return;
|
||||
}
|
||||
|
|
@ -2580,7 +2573,7 @@ MIDITrigger::captured (SlotArmInfo& ai, BufferSet& bufs)
|
|||
// std::cerr << "capture done, ask for a source of length " << dur.beats().str() << std::endl;
|
||||
TriggerBox::worker->request_build_source (this, timecnt_t (dur.beats()));
|
||||
|
||||
disarm (true);
|
||||
disarm ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3700,8 +3693,6 @@ TriggerBox::arm_from_another_thread (Trigger& slot, samplepos_t now, uint32_t ch
|
|||
{
|
||||
using namespace Temporal;
|
||||
|
||||
std::cerr << "AFAT...\n";
|
||||
|
||||
SlotArmInfo* ai = &_the_arm_info;
|
||||
|
||||
/* Delete any dangling RTMidiBuffer and Stretcher from previous capture
|
||||
|
|
@ -3729,9 +3720,8 @@ TriggerBox::arm_from_another_thread (Trigger& slot, samplepos_t now, uint32_t ch
|
|||
Beats now_beats = tmap->quarters_at (timepos_t (now));
|
||||
|
||||
slot.compute_quantized_transition (now, now_beats, std::numeric_limits<Beats>::max(),
|
||||
t_bbt, t_beats, t_samples, tmap, slot.quantization(), 2);
|
||||
t_bbt, t_beats, t_samples, tmap, slot.quantization());
|
||||
|
||||
std::cerr << " from " << now_beats.str() << " compute start at " << t_beats.str() << std::endl;
|
||||
ai->start_samples = t_samples;
|
||||
ai->start_beats = t_beats;
|
||||
|
||||
|
|
@ -3748,10 +3738,10 @@ TriggerBox::arm_from_another_thread (Trigger& slot, samplepos_t now, uint32_t ch
|
|||
}
|
||||
|
||||
void
|
||||
TriggerBox::disarm_all (bool disarm_box)
|
||||
TriggerBox::disarm_all ()
|
||||
{
|
||||
for (auto & t : all_triggers) {
|
||||
t->disarm (disarm_box);
|
||||
t->disarm ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3760,8 +3750,6 @@ TriggerBox::disarm ()
|
|||
{
|
||||
/* This must be called as an alternative to ::finish_recording() */
|
||||
|
||||
std::cerr << "disarmed\n";
|
||||
PBD::stacktrace (std::cerr, 17);
|
||||
_arm_info = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -3780,7 +3768,6 @@ TriggerBox::finish_recording (BufferSet& bufs)
|
|||
/* XXX this should likely be dependent on what the post-record action is */
|
||||
|
||||
_record_state = Disabled;
|
||||
std::cerr << "all done!\n";
|
||||
RecEnableChanged (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
|
|
@ -3792,7 +3779,6 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_
|
|||
SlotArmInfo* ai = _arm_info.load();
|
||||
|
||||
if (!ai) {
|
||||
std::cerr << "no AI\n";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3800,7 +3786,6 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_
|
|||
bool reached_end = false;
|
||||
|
||||
if (!ai->slot->armed()) {
|
||||
std::cerr << "not armed!\n";
|
||||
/* since _arm_info is set, we have been capturing for a slot,
|
||||
but now the slot is no longer armed.
|
||||
*/
|
||||
|
|
@ -3823,10 +3808,7 @@ TriggerBox::maybe_capture (BufferSet& bufs, samplepos_t start_sample, samplepos_
|
|||
t_bbt, t_beats, t_samples, tmap, ai->slot->quantization());
|
||||
ai->end_samples = t_samples;
|
||||
ai->end_beats = t_beats;
|
||||
std::cerr << "will stop at " << t_beats.str() << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "still armed\n";
|
||||
}
|
||||
|
||||
if (speed <= 0.) {
|
||||
|
|
@ -3942,7 +3924,9 @@ TriggerBox::set_record_enabled (bool yn)
|
|||
_record_state = yn ? Enabled : Disabled;
|
||||
|
||||
if (_record_state == Disabled) {
|
||||
disarm_all (false);
|
||||
for (auto & trig : all_triggers) {
|
||||
trig->disarm ();
|
||||
}
|
||||
}
|
||||
|
||||
RecEnableChanged (); /* EMIT SIGNAL */
|
||||
|
|
@ -5974,11 +5958,10 @@ TriggerBox::start_time (bool& is_set) const
|
|||
{
|
||||
SlotArmInfo* ai = _arm_info.load ();
|
||||
if (!ai) {
|
||||
std::cerr << "no slot\n";
|
||||
is_set = false;
|
||||
return Temporal::Beats();
|
||||
}
|
||||
std::cerr << "have slot\n";
|
||||
|
||||
is_set = true;
|
||||
return ai->start_beats;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue