further steps towards MidiRegionView outside the Editor
This commit is contained in:
parent
ca7bd9a73d
commit
204d4237f8
@ -22,6 +22,7 @@
|
|||||||
#include "pbd/stacktrace.h"
|
#include "pbd/stacktrace.h"
|
||||||
|
|
||||||
#include "ardour/rc_configuration.h"
|
#include "ardour/rc_configuration.h"
|
||||||
|
#include "ardour/quantize.h"
|
||||||
|
|
||||||
#include "gtkmm2ext/bindings.h"
|
#include "gtkmm2ext/bindings.h"
|
||||||
|
|
||||||
@ -30,6 +31,7 @@
|
|||||||
#include "editor_drag.h"
|
#include "editor_drag.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "midi_region_view.h"
|
#include "midi_region_view.h"
|
||||||
|
#include "quantize_dialog.h"
|
||||||
#include "selection.h"
|
#include "selection.h"
|
||||||
#include "selection_memento.h"
|
#include "selection_memento.h"
|
||||||
#include "verbose_cursor.h"
|
#include "verbose_cursor.h"
|
||||||
@ -100,10 +102,9 @@ EditingContext::EditingContext ()
|
|||||||
, bbt_bar_helper_on (0)
|
, bbt_bar_helper_on (0)
|
||||||
, _visible_canvas_width (0)
|
, _visible_canvas_width (0)
|
||||||
, _visible_canvas_height (0)
|
, _visible_canvas_height (0)
|
||||||
|
, quantize_dialog (nullptr)
|
||||||
{
|
{
|
||||||
grid_type_strings = I18N (_grid_type_strings);
|
grid_type_strings = I18N (_grid_type_strings);
|
||||||
|
|
||||||
_verbose_cursor = new VerboseCursor (*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EditingContext::~EditingContext()
|
EditingContext::~EditingContext()
|
||||||
@ -1528,3 +1529,29 @@ EditingContext::compute_bbt_ruler_scale (samplepos_t lower, samplepos_t upper)
|
|||||||
|
|
||||||
bbt_ruler_scale = (EditingContext::BBTRulerScale) suggested_scale;
|
bbt_ruler_scale = (EditingContext::BBTRulerScale) suggested_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Quantize*
|
||||||
|
EditingContext::get_quantize_op ()
|
||||||
|
{
|
||||||
|
if (!quantize_dialog) {
|
||||||
|
quantize_dialog = new QuantizeDialog (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
quantize_dialog->present ();
|
||||||
|
int r = quantize_dialog->run ();
|
||||||
|
quantize_dialog->hide ();
|
||||||
|
|
||||||
|
|
||||||
|
if (r != Gtk::RESPONSE_OK) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Quantize (quantize_dialog->snap_start(),
|
||||||
|
quantize_dialog->snap_end(),
|
||||||
|
quantize_dialog->start_grid_size(),
|
||||||
|
quantize_dialog->end_grid_size(),
|
||||||
|
quantize_dialog->strength(),
|
||||||
|
quantize_dialog->swing(),
|
||||||
|
quantize_dialog->threshold());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#include "temporal/timeline.h"
|
#include "temporal/timeline.h"
|
||||||
|
|
||||||
|
#include "ardour/midi_operator.h"
|
||||||
#include "ardour/session_handle.h"
|
#include "ardour/session_handle.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
|
||||||
@ -278,6 +279,8 @@ public:
|
|||||||
PBD::Signal0<void> MouseModeChanged;
|
PBD::Signal0<void> MouseModeChanged;
|
||||||
|
|
||||||
/* MIDI actions, proxied to selected MidiRegionView(s) */
|
/* MIDI actions, proxied to selected MidiRegionView(s) */
|
||||||
|
ARDOUR::Quantize* get_quantize_op ();
|
||||||
|
virtual void apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs) = 0;
|
||||||
void midi_action (void (MidiRegionView::*method)());
|
void midi_action (void (MidiRegionView::*method)());
|
||||||
virtual std::vector<MidiRegionView*> filter_to_unique_midi_region_views (RegionSelection const & ms) const = 0;
|
virtual std::vector<MidiRegionView*> filter_to_unique_midi_region_views (RegionSelection const & ms) const = 0;
|
||||||
|
|
||||||
@ -415,6 +418,8 @@ public:
|
|||||||
|
|
||||||
double _visible_canvas_width;
|
double _visible_canvas_width;
|
||||||
double _visible_canvas_height; ///< height of the visible area of the track canvas
|
double _visible_canvas_height; ///< height of the visible area of the track canvas
|
||||||
|
|
||||||
|
QuantizeDialog* quantize_dialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -409,7 +409,6 @@ Editor::Editor ()
|
|||||||
, _show_touched_automation (false)
|
, _show_touched_automation (false)
|
||||||
, _control_point_toggled_on_press (false)
|
, _control_point_toggled_on_press (false)
|
||||||
, _stepping_axis_view (0)
|
, _stepping_axis_view (0)
|
||||||
, quantize_dialog (0)
|
|
||||||
, _main_menu_disabler (0)
|
, _main_menu_disabler (0)
|
||||||
, domain_bounce_info (nullptr)
|
, domain_bounce_info (nullptr)
|
||||||
, track_drag (nullptr)
|
, track_drag (nullptr)
|
||||||
|
@ -1245,7 +1245,6 @@ private:
|
|||||||
void normalize_region ();
|
void normalize_region ();
|
||||||
void adjust_region_gain (bool up);
|
void adjust_region_gain (bool up);
|
||||||
void reset_region_gain ();
|
void reset_region_gain ();
|
||||||
ARDOUR::Quantize* get_quantize_op ();
|
|
||||||
void apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs);
|
void apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs);
|
||||||
void set_tempo_curve_range (double& max, double& min) const;
|
void set_tempo_curve_range (double& max, double& min) const;
|
||||||
void quantize_region ();
|
void quantize_region ();
|
||||||
@ -2350,7 +2349,6 @@ private:
|
|||||||
void update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, std::string name);
|
void update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, std::string name);
|
||||||
void bring_all_sources_into_session ();
|
void bring_all_sources_into_session ();
|
||||||
|
|
||||||
QuantizeDialog* quantize_dialog;
|
|
||||||
MainMenuDisabler* _main_menu_disabler;
|
MainMenuDisabler* _main_menu_disabler;
|
||||||
|
|
||||||
std::vector<MidiRegionView*> filter_to_unique_midi_region_views (RegionSelection const & ms) const;
|
std::vector<MidiRegionView*> filter_to_unique_midi_region_views (RegionSelection const & ms) const;
|
||||||
|
@ -94,6 +94,8 @@ Editor::initialize_canvas ()
|
|||||||
*/
|
*/
|
||||||
no_scroll_group = new ArdourCanvas::Container (_track_canvas->root());
|
no_scroll_group = new ArdourCanvas::Container (_track_canvas->root());
|
||||||
|
|
||||||
|
_verbose_cursor = new VerboseCursor (*this);
|
||||||
|
|
||||||
ArdourCanvas::ScrollGroup* hsg;
|
ArdourCanvas::ScrollGroup* hsg;
|
||||||
ArdourCanvas::ScrollGroup* hg;
|
ArdourCanvas::ScrollGroup* hg;
|
||||||
ArdourCanvas::ScrollGroup* cg;
|
ArdourCanvas::ScrollGroup* cg;
|
||||||
|
@ -111,7 +111,6 @@
|
|||||||
#include "note.h"
|
#include "note.h"
|
||||||
#include "paste_context.h"
|
#include "paste_context.h"
|
||||||
#include "patch_change_dialog.h"
|
#include "patch_change_dialog.h"
|
||||||
#include "quantize_dialog.h"
|
|
||||||
#include "region_gain_line.h"
|
#include "region_gain_line.h"
|
||||||
#include "route_time_axis.h"
|
#include "route_time_axis.h"
|
||||||
#include "selection.h"
|
#include "selection.h"
|
||||||
@ -6336,31 +6335,6 @@ Editor::quantize_regions (const RegionSelection& rs)
|
|||||||
delete quant;
|
delete quant;
|
||||||
}
|
}
|
||||||
|
|
||||||
Quantize*
|
|
||||||
Editor::get_quantize_op ()
|
|
||||||
{
|
|
||||||
if (!quantize_dialog) {
|
|
||||||
quantize_dialog = new QuantizeDialog (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
quantize_dialog->present ();
|
|
||||||
int r = quantize_dialog->run ();
|
|
||||||
quantize_dialog->hide ();
|
|
||||||
|
|
||||||
|
|
||||||
if (r != Gtk::RESPONSE_OK) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Quantize (quantize_dialog->snap_start(),
|
|
||||||
quantize_dialog->snap_end(),
|
|
||||||
quantize_dialog->start_grid_size(),
|
|
||||||
quantize_dialog->end_grid_size(),
|
|
||||||
quantize_dialog->strength(),
|
|
||||||
quantize_dialog->swing(),
|
|
||||||
quantize_dialog->threshold());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::legatize_region (bool shrink_only)
|
Editor::legatize_region (bool shrink_only)
|
||||||
{
|
{
|
||||||
|
@ -75,6 +75,7 @@ void
|
|||||||
MidiClipEditorBox::set_session (Session* s)
|
MidiClipEditorBox::set_session (Session* s)
|
||||||
{
|
{
|
||||||
SessionHandlePtr::set_session (s);
|
SessionHandlePtr::set_session (s);
|
||||||
|
editor->set_session (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "midi_cue_editor.h"
|
#include "midi_cue_editor.h"
|
||||||
#include "ui_config.h"
|
#include "ui_config.h"
|
||||||
|
#include "verbose_cursor.h"
|
||||||
|
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace ArdourCanvas;
|
using namespace ArdourCanvas;
|
||||||
@ -34,6 +35,8 @@ MidiCueEditor::MidiCueEditor()
|
|||||||
, horizontal_adjustment (0.0, 0.0, 1e16)
|
, horizontal_adjustment (0.0, 0.0, 1e16)
|
||||||
{
|
{
|
||||||
build_canvas ();
|
build_canvas ();
|
||||||
|
|
||||||
|
_verbose_cursor = new VerboseCursor (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiCueEditor::~MidiCueEditor ()
|
MidiCueEditor::~MidiCueEditor ()
|
||||||
@ -44,10 +47,10 @@ void
|
|||||||
MidiCueEditor::build_canvas ()
|
MidiCueEditor::build_canvas ()
|
||||||
{
|
{
|
||||||
_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
|
_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
|
||||||
_canvas = _canvas_viewport->canvas ();
|
|
||||||
|
|
||||||
_canvas->set_background_color (UIConfiguration::instance().color ("arrange base"));
|
_canvas = _canvas_viewport->canvas ();
|
||||||
// _canvas->use_nsglview (UIConfiguration::instance().get_nsgl_view_mode () == NSGLHiRes);
|
_canvas->set_background_color (0xff00000a); // UIConfiguration::instance().color ("arrange base"));
|
||||||
|
dynamic_cast<ArdourCanvas::GtkCanvas*>(_canvas)->use_nsglview (UIConfiguration::instance().get_nsgl_view_mode () == NSGLHiRes);
|
||||||
|
|
||||||
/* scroll group for items that should not automatically scroll
|
/* scroll group for items that should not automatically scroll
|
||||||
* (e.g verbose cursor). It shares the canvas coordinate space.
|
* (e.g verbose cursor). It shares the canvas coordinate space.
|
||||||
@ -139,3 +142,29 @@ MidiCueEditor::current_page_samples() const
|
|||||||
return (samplecnt_t) _visible_canvas_width* samples_per_pixel;
|
return (samplecnt_t) _visible_canvas_width* samples_per_pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiCueEditor::apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PBD::Command*
|
||||||
|
MidiCueEditor::apply_midi_note_edit_op_to_region (ARDOUR::MidiOperator& op, MidiRegionView& mrv)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
Evoral::Sequence<Temporal::Beats>::Notes selected;
|
||||||
|
mrv.selection_as_notelist (selected, true);
|
||||||
|
|
||||||
|
if (selected.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Evoral::Sequence<Temporal::Beats>::Notes> v;
|
||||||
|
v.push_back (selected);
|
||||||
|
|
||||||
|
timepos_t pos = mrv.midi_region()->source_position();
|
||||||
|
|
||||||
|
return op (mrv.midi_region()->model(), pos.beats(), v);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
@ -54,6 +54,9 @@ class MidiCueEditor : public CueEditor
|
|||||||
int32_t get_grid_beat_divisions (Editing::GridType gt) { return 1; }
|
int32_t get_grid_beat_divisions (Editing::GridType gt) { return 1; }
|
||||||
int32_t get_grid_music_divisions (Editing::GridType gt, uint32_t event_state) { return 1; }
|
int32_t get_grid_music_divisions (Editing::GridType gt, uint32_t event_state) { return 1; }
|
||||||
|
|
||||||
|
void apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs);
|
||||||
|
PBD::Command* apply_midi_note_edit_op_to_region (ARDOUR::MidiOperator& op, MidiRegionView& mrv);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Temporal::timepos_t snap_to_grid (Temporal::timepos_t const & start,
|
Temporal::timepos_t snap_to_grid (Temporal::timepos_t const & start,
|
||||||
Temporal::RoundMode direction,
|
Temporal::RoundMode direction,
|
||||||
|
@ -326,6 +326,59 @@ MidiRegionView::connect_to_diskstream ()
|
|||||||
gui_context());
|
gui_context());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
MidiRegionView::get_modifier_name () const
|
||||||
|
{
|
||||||
|
const bool opaque = _region->opaque() || trackview.layer_display () == Stacked;
|
||||||
|
|
||||||
|
std::string mod_name;
|
||||||
|
|
||||||
|
if (_dragging) {
|
||||||
|
mod_name = "dragging region";
|
||||||
|
} else if (editing_context.internal_editing()) {
|
||||||
|
if (!opaque || _region->muted ()) {
|
||||||
|
mod_name = "editable region";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!opaque || _region->muted ()) {
|
||||||
|
mod_name = "transparent region base";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
GhostRegion*
|
||||||
|
MidiRegionView::add_ghost (TimeAxisView& tv)
|
||||||
|
{
|
||||||
|
double unit_position = editing_context.time_to_pixel (_region->position ());
|
||||||
|
MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(&tv);
|
||||||
|
MidiGhostRegion* ghost;
|
||||||
|
|
||||||
|
if (mtv && mtv->midi_view()) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&tv);
|
||||||
|
if (atv && atv->parameter() == Evoral::Parameter (MidiVelocityAutomation)) {
|
||||||
|
ghost = new VelocityGhostRegion (*this, tv, trackview, unit_position);
|
||||||
|
} else {
|
||||||
|
ghost = new MidiGhostRegion (*this, tv, trackview, unit_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ghost->set_colors ();
|
||||||
|
ghost->set_height ();
|
||||||
|
ghost->set_duration (_region->length().samples() / samples_per_pixel);
|
||||||
|
|
||||||
|
for (auto const & i : _events) {
|
||||||
|
ghost->add_note (i.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
ghosts.push_back (ghost);
|
||||||
|
return ghost;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MidiRegionView::canvas_group_event(GdkEvent* ev)
|
MidiRegionView::canvas_group_event(GdkEvent* ev)
|
||||||
{
|
{
|
||||||
@ -1639,36 +1692,6 @@ MidiRegionView::apply_note_range (uint8_t min, uint8_t max, bool force)
|
|||||||
view_changed ();
|
view_changed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
GhostRegion*
|
|
||||||
MidiRegionView::add_ghost (TimeAxisView& tv)
|
|
||||||
{
|
|
||||||
double unit_position = editing_context.time_to_pixel (_region->position ());
|
|
||||||
MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(&tv);
|
|
||||||
MidiGhostRegion* ghost;
|
|
||||||
|
|
||||||
if (mtv && mtv->midi_view()) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&tv);
|
|
||||||
if (atv && atv->parameter() == Evoral::Parameter (MidiVelocityAutomation)) {
|
|
||||||
ghost = new VelocityGhostRegion (*this, tv, trackview, unit_position);
|
|
||||||
} else {
|
|
||||||
ghost = new MidiGhostRegion (*this, tv, trackview, unit_position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ghost->set_colors ();
|
|
||||||
ghost->set_height ();
|
|
||||||
ghost->set_duration (_region->length().samples() / samples_per_pixel);
|
|
||||||
|
|
||||||
for (auto const & i : _events) {
|
|
||||||
ghost->add_note (i.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
ghosts.push_back (ghost);
|
|
||||||
return ghost;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Begin tracking note state for successive calls to add_event
|
/** Begin tracking note state for successive calls to add_event
|
||||||
*/
|
*/
|
||||||
@ -3806,25 +3829,10 @@ MidiRegionView::note_mouse_position (float x_fraction, float /*y_fraction*/, boo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
MidiRegionView::get_fill_color() const
|
MidiRegionView::get_fill_color() const
|
||||||
{
|
{
|
||||||
const bool opaque = _region->opaque() || trackview.layer_display () == Stacked;
|
|
||||||
|
|
||||||
std::string mod_name;
|
|
||||||
|
|
||||||
if (_dragging) {
|
|
||||||
mod_name = "dragging region";
|
|
||||||
} else if (editing_context.internal_editing()) {
|
|
||||||
if (!opaque || _region->muted ()) {
|
|
||||||
mod_name = "editable region";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!opaque || _region->muted ()) {
|
|
||||||
mod_name = "transparent region base";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Gtkmm2ext::Color c;
|
Gtkmm2ext::Color c;
|
||||||
if (_selected) {
|
if (_selected) {
|
||||||
c = UIConfiguration::instance().color ("selected region base");
|
c = UIConfiguration::instance().color ("selected region base");
|
||||||
@ -3834,6 +3842,8 @@ MidiRegionView::get_fill_color() const
|
|||||||
c = fill_color;
|
c = fill_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string mod_name = get_modifier_name();
|
||||||
|
|
||||||
if (mod_name.empty ()) {
|
if (mod_name.empty ()) {
|
||||||
return c;
|
return c;
|
||||||
} else {
|
} else {
|
||||||
@ -4738,7 +4748,7 @@ MidiRegionView::quantize_selected_notes ()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
trackview.editor().apply_midi_note_edit_op (*quant, rs);
|
editing_context.apply_midi_note_edit_op (*quant, rs);
|
||||||
|
|
||||||
delete quant;
|
delete quant;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,7 @@ public:
|
|||||||
|
|
||||||
inline ARDOUR::ColorMode color_mode() const { return midi_view()->color_mode(); }
|
inline ARDOUR::ColorMode color_mode() const { return midi_view()->color_mode(); }
|
||||||
|
|
||||||
|
std::string get_modifier_name() const;
|
||||||
uint32_t get_fill_color() const;
|
uint32_t get_fill_color() const;
|
||||||
void color_handler ();
|
void color_handler ();
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@
|
|||||||
|
|
||||||
#include <gtkmm2ext/gtk_ui.h>
|
#include <gtkmm2ext/gtk_ui.h>
|
||||||
|
|
||||||
#include "canvas/line_set.h"
|
|
||||||
#include "canvas/rectangle.h"
|
#include "canvas/rectangle.h"
|
||||||
|
#include "canvas/line_set.h"
|
||||||
|
|
||||||
#include "ardour/midi_region.h"
|
#include "ardour/midi_region.h"
|
||||||
#include "ardour/midi_source.h"
|
#include "ardour/midi_source.h"
|
||||||
@ -64,14 +64,7 @@ using namespace Editing;
|
|||||||
|
|
||||||
MidiStreamView::MidiStreamView (MidiTimeAxisView& tv)
|
MidiStreamView::MidiStreamView (MidiTimeAxisView& tv)
|
||||||
: StreamView (tv)
|
: StreamView (tv)
|
||||||
, note_range_adjustment(0.0f, 0.0f, 0.0f)
|
, MidiViewBackground (_canvas_group)
|
||||||
, _range_dirty(false)
|
|
||||||
, _range_sum_cache(-1.0)
|
|
||||||
, _lowest_note(UIConfiguration::instance().get_default_lower_midi_note())
|
|
||||||
, _highest_note(UIConfiguration::instance().get_default_upper_midi_note())
|
|
||||||
, _data_note_min(60)
|
|
||||||
, _data_note_max(71)
|
|
||||||
, _note_lines (0)
|
|
||||||
, _updates_suspended (false)
|
, _updates_suspended (false)
|
||||||
{
|
{
|
||||||
/* use a dedicated group for MIDI regions (on top of the grid and lines) */
|
/* use a dedicated group for MIDI regions (on top of the grid and lines) */
|
||||||
@ -82,25 +75,16 @@ MidiStreamView::MidiStreamView (MidiTimeAxisView& tv)
|
|||||||
/* put the note lines in the timeaxisview's group, so it
|
/* put the note lines in the timeaxisview's group, so it
|
||||||
can be put below ghost regions from MIDI underlays
|
can be put below ghost regions from MIDI underlays
|
||||||
*/
|
*/
|
||||||
_note_lines = new ArdourCanvas::LineSet (_canvas_group, ArdourCanvas::LineSet::Horizontal);
|
|
||||||
|
|
||||||
_note_lines->Event.connect(
|
_note_lines->Event.connect(
|
||||||
sigc::bind(sigc::mem_fun(_trackview.editor(),
|
sigc::bind(sigc::mem_fun(_trackview.editor(),
|
||||||
&PublicEditor::canvas_stream_view_event),
|
&PublicEditor::canvas_stream_view_event),
|
||||||
_note_lines, &_trackview));
|
_note_lines, &_trackview));
|
||||||
|
|
||||||
_note_lines->lower_to_bottom();
|
|
||||||
|
|
||||||
color_handler ();
|
color_handler ();
|
||||||
|
|
||||||
UIConfiguration::instance().ColorsChanged.connect(sigc::mem_fun(*this, &MidiStreamView::color_handler));
|
UIConfiguration::instance().ColorsChanged.connect(sigc::mem_fun(*this, &MidiStreamView::color_handler));
|
||||||
UIConfiguration::instance().ParameterChanged.connect(sigc::mem_fun(*this, &MidiStreamView::parameter_changed));
|
UIConfiguration::instance().ParameterChanged.connect(sigc::mem_fun(*this, &MidiStreamView::parameter_changed));
|
||||||
|
|
||||||
note_range_adjustment.set_page_size(_highest_note - _lowest_note);
|
|
||||||
note_range_adjustment.set_value(_lowest_note);
|
|
||||||
|
|
||||||
note_range_adjustment.signal_value_changed().connect(
|
|
||||||
sigc::mem_fun(*this, &MidiStreamView::note_range_adjustment_changed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiStreamView::~MidiStreamView ()
|
MidiStreamView::~MidiStreamView ()
|
||||||
@ -110,11 +94,7 @@ MidiStreamView::~MidiStreamView ()
|
|||||||
void
|
void
|
||||||
MidiStreamView::parameter_changed (string const & param)
|
MidiStreamView::parameter_changed (string const & param)
|
||||||
{
|
{
|
||||||
if (param == X_("max-note-height")) {
|
StreamView::parameter_changed (param);
|
||||||
apply_note_range (_lowest_note, _highest_note, true);
|
|
||||||
} else {
|
|
||||||
StreamView::parameter_changed (param);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionView*
|
RegionView*
|
||||||
@ -243,21 +223,6 @@ MidiStreamView::update_contents_metrics(std::shared_ptr<Region> r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
MidiStreamView::update_data_note_range(uint8_t min, uint8_t max)
|
|
||||||
{
|
|
||||||
bool dirty = false;
|
|
||||||
if (min < _data_note_min) {
|
|
||||||
_data_note_min = min;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
if (max > _data_note_max) {
|
|
||||||
_data_note_max = max;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
return dirty;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStreamView::set_layer_display (LayerDisplay d)
|
MidiStreamView::set_layer_display (LayerDisplay d)
|
||||||
{
|
{
|
||||||
@ -314,140 +279,7 @@ MidiStreamView::redisplay_track ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStreamView::update_contents_height ()
|
MidiStreamView::apply_note_range_to_children ()
|
||||||
{
|
|
||||||
StreamView::update_contents_height();
|
|
||||||
|
|
||||||
_note_lines->set_extent (ArdourCanvas::COORD_MAX);
|
|
||||||
|
|
||||||
apply_note_range (lowest_note(), highest_note(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiStreamView::draw_note_lines()
|
|
||||||
{
|
|
||||||
if (!_note_lines || _updates_suspended) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double y;
|
|
||||||
double prev_y = 0.;
|
|
||||||
Gtkmm2ext::Color black = UIConfiguration::instance().color_mod ("piano roll black", "piano roll black");
|
|
||||||
Gtkmm2ext::Color white = UIConfiguration::instance().color_mod ("piano roll white", "piano roll white");
|
|
||||||
Gtkmm2ext::Color outline = UIConfiguration::instance().color ("piano roll black outline");
|
|
||||||
Gtkmm2ext::Color color;
|
|
||||||
|
|
||||||
ArdourCanvas::LineSet::ResetRAII lr (*_note_lines);
|
|
||||||
|
|
||||||
if (child_height() < 140 || note_height() < 3) {
|
|
||||||
/* track is too small for note lines, or there are too many */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do this is order of highest ... lowest since that matches the
|
|
||||||
* coordinate system in which y=0 is at the top
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (int i = highest_note() + 1; i >= lowest_note(); --i) {
|
|
||||||
|
|
||||||
y = floor (note_to_y (i));
|
|
||||||
|
|
||||||
/* add a thicker line/bar which covers the entire vertical height of this note. */
|
|
||||||
|
|
||||||
switch (i % 12) {
|
|
||||||
case 1:
|
|
||||||
case 3:
|
|
||||||
case 6:
|
|
||||||
case 8:
|
|
||||||
case 10:
|
|
||||||
color = black;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
case 11:
|
|
||||||
/* this is the line actually corresponding to the division between B & C and E & F */
|
|
||||||
_note_lines->add_coord (y, 1.0, outline);
|
|
||||||
/* fallthrough */
|
|
||||||
default:
|
|
||||||
color = white;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
double h = y - prev_y;
|
|
||||||
double middle = y + (h/2.0);
|
|
||||||
|
|
||||||
if (!fmod (h, 2.) && !fmod (middle, 1.)) {
|
|
||||||
middle += 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (middle >= 0 && h > 1.0) {
|
|
||||||
_note_lines->add_coord (middle, h, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
prev_y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiStreamView::set_note_range(VisibleNoteRange r)
|
|
||||||
{
|
|
||||||
if (r == FullRange) {
|
|
||||||
_lowest_note = 0;
|
|
||||||
_highest_note = 127;
|
|
||||||
} else {
|
|
||||||
_lowest_note = _data_note_min;
|
|
||||||
_highest_note = _data_note_max;
|
|
||||||
}
|
|
||||||
|
|
||||||
apply_note_range(_lowest_note, _highest_note, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiStreamView::apply_note_range(uint8_t lowest, uint8_t highest, bool to_region_views)
|
|
||||||
{
|
|
||||||
_highest_note = highest;
|
|
||||||
_lowest_note = lowest;
|
|
||||||
|
|
||||||
float uiscale = UIConfiguration::instance().get_ui_scale();
|
|
||||||
uiscale = expf (uiscale) / expf (1.f);
|
|
||||||
|
|
||||||
const int mnh = UIConfiguration::instance().get_max_note_height();
|
|
||||||
int const max_note_height = std::max<int> (mnh, mnh * uiscale);
|
|
||||||
int const range = _highest_note - _lowest_note;
|
|
||||||
|
|
||||||
int const available_note_range = floor (child_height() / max_note_height);
|
|
||||||
int additional_notes = available_note_range - range;
|
|
||||||
|
|
||||||
/* distribute additional notes to higher and lower ranges, clamp at 0 and 127 */
|
|
||||||
for (int i = 0; i < additional_notes; i++){
|
|
||||||
|
|
||||||
if (i % 2 && _highest_note < 127){
|
|
||||||
_highest_note++;
|
|
||||||
}
|
|
||||||
else if (i % 2) {
|
|
||||||
_lowest_note--;
|
|
||||||
}
|
|
||||||
else if (_lowest_note > 0){
|
|
||||||
_lowest_note--;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_highest_note++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
note_range_adjustment.set_page_size (_highest_note - _lowest_note);
|
|
||||||
note_range_adjustment.set_value (_lowest_note);
|
|
||||||
|
|
||||||
draw_note_lines();
|
|
||||||
|
|
||||||
if (to_region_views) {
|
|
||||||
apply_note_range_to_regions ();
|
|
||||||
}
|
|
||||||
|
|
||||||
NoteRangeChanged(); /* EMIT SIGNAL*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiStreamView::apply_note_range_to_regions ()
|
|
||||||
{
|
{
|
||||||
if (!_updates_suspended) {
|
if (!_updates_suspended) {
|
||||||
for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
|
for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
|
||||||
@ -456,13 +288,6 @@ MidiStreamView::apply_note_range_to_regions ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
MidiStreamView::update_note_range(uint8_t note_num)
|
|
||||||
{
|
|
||||||
_data_note_min = min(_data_note_min, note_num);
|
|
||||||
_data_note_max = max(_data_note_max, note_num);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStreamView::setup_rec_box ()
|
MidiStreamView::setup_rec_box ()
|
||||||
{
|
{
|
||||||
@ -559,8 +384,9 @@ MidiStreamView::setup_rec_box ()
|
|||||||
void
|
void
|
||||||
MidiStreamView::color_handler ()
|
MidiStreamView::color_handler ()
|
||||||
{
|
{
|
||||||
|
MidiViewBackground::color_handler ();
|
||||||
|
|
||||||
_region_group->set_render_with_alpha (UIConfiguration::instance().modifier ("region alpha").a());
|
_region_group->set_render_with_alpha (UIConfiguration::instance().modifier ("region alpha").a());
|
||||||
draw_note_lines ();
|
|
||||||
|
|
||||||
if (_trackview.is_midi_track()) {
|
if (_trackview.is_midi_track()) {
|
||||||
canvas_rect->set_fill_color (UIConfiguration::instance().color_mod ("midi track base", "midi track base"));
|
canvas_rect->set_fill_color (UIConfiguration::instance().color_mod ("midi track base", "midi track base"));
|
||||||
@ -573,34 +399,6 @@ MidiStreamView::color_handler ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
MidiStreamView::note_range_adjustment_changed()
|
|
||||||
{
|
|
||||||
double sum = note_range_adjustment.get_value() + note_range_adjustment.get_page_size();
|
|
||||||
int lowest = (int) floor(note_range_adjustment.get_value());
|
|
||||||
int highest;
|
|
||||||
|
|
||||||
if (sum == _range_sum_cache) {
|
|
||||||
//cerr << "cached" << endl;
|
|
||||||
highest = (int) floor(sum);
|
|
||||||
} else {
|
|
||||||
//cerr << "recalc" << endl;
|
|
||||||
highest = lowest + (int) floor(note_range_adjustment.get_page_size());
|
|
||||||
_range_sum_cache = sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lowest == _lowest_note && highest == _highest_note) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cerr << "note range adjustment changed: " << lowest << " " << highest << endl;
|
|
||||||
//cerr << " val=" << v_zoom_adjustment.get_value() << " page=" << v_zoom_adjustment.get_page_size() << " sum=" << v_zoom_adjustment.get_value() + v_zoom_adjustment.get_page_size() << endl;
|
|
||||||
|
|
||||||
_lowest_note = lowest;
|
|
||||||
_highest_note = highest;
|
|
||||||
apply_note_range(lowest, highest, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStreamView::update_rec_box ()
|
MidiStreamView::update_rec_box ()
|
||||||
{
|
{
|
||||||
@ -618,21 +416,6 @@ MidiStreamView::update_rec_box ()
|
|||||||
mrv->extend_active_notes ();
|
mrv->extend_active_notes ();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
|
||||||
MidiStreamView::y_to_note (double y) const
|
|
||||||
{
|
|
||||||
int const n = ((contents_height() - y) / contents_height() * (double)contents_note_range())
|
|
||||||
+ lowest_note();
|
|
||||||
|
|
||||||
if (n < 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (n > 127) {
|
|
||||||
return 127;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* min due to rounding and/or off-by-one errors */
|
|
||||||
return min ((uint8_t) n, highest_note());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Suspend updates to the regions' note ranges and our
|
/** Suspend updates to the regions' note ranges and our
|
||||||
* note lines until resume_updates() is called.
|
* note lines until resume_updates() is called.
|
||||||
@ -652,7 +435,7 @@ MidiStreamView::resume_updates ()
|
|||||||
_updates_suspended = false;
|
_updates_suspended = false;
|
||||||
|
|
||||||
draw_note_lines ();
|
draw_note_lines ();
|
||||||
apply_note_range_to_regions ();
|
apply_note_range_to_children ();
|
||||||
|
|
||||||
_canvas_group->redraw ();
|
_canvas_group->redraw ();
|
||||||
}
|
}
|
||||||
@ -710,3 +493,4 @@ MidiStreamView::get_regions_with_selected_data (RegionSelection& rs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "ardour/location.h"
|
#include "ardour/location.h"
|
||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
|
#include "midi_view_background.h"
|
||||||
#include "streamview.h"
|
#include "streamview.h"
|
||||||
#include "time_axis_view_item.h"
|
#include "time_axis_view_item.h"
|
||||||
#include "route_time_axis.h"
|
#include "route_time_axis.h"
|
||||||
@ -57,7 +58,7 @@ class RegionSelection;
|
|||||||
class CrossfadeView;
|
class CrossfadeView;
|
||||||
class Selection;
|
class Selection;
|
||||||
|
|
||||||
class MidiStreamView : public StreamView
|
class MidiStreamView : public StreamView, public MidiViewBackground
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiStreamView (MidiTimeAxisView&);
|
MidiStreamView (MidiTimeAxisView&);
|
||||||
@ -66,50 +67,18 @@ public:
|
|||||||
void get_inverted_selectables (Selection&, std::list<Selectable* >& results);
|
void get_inverted_selectables (Selection&, std::list<Selectable* >& results);
|
||||||
void get_regions_with_selected_data (RegionSelection&);
|
void get_regions_with_selected_data (RegionSelection&);
|
||||||
|
|
||||||
enum VisibleNoteRange {
|
|
||||||
FullRange,
|
|
||||||
ContentsRange
|
|
||||||
};
|
|
||||||
|
|
||||||
Gtk::Adjustment note_range_adjustment;
|
|
||||||
|
|
||||||
void set_note_range(VisibleNoteRange r);
|
|
||||||
|
|
||||||
inline uint8_t lowest_note() const { return _lowest_note; }
|
|
||||||
inline uint8_t highest_note() const { return _highest_note; }
|
|
||||||
|
|
||||||
void update_note_range(uint8_t note_num);
|
|
||||||
|
|
||||||
void set_layer_display (LayerDisplay);
|
void set_layer_display (LayerDisplay);
|
||||||
//bool can_change_layer_display() const { return false; } // revert this change for now. Although stacked view is weirdly implemented wrt the "scroomer", it is still necessary to be able to manage layered regions.
|
//bool can_change_layer_display() const { return false; } // revert this change for now. Although stacked view is weirdly implemented wrt the "scroomer", it is still necessary to be able to manage layered regions.
|
||||||
void redisplay_track ();
|
void redisplay_track ();
|
||||||
|
|
||||||
inline double contents_height() const {
|
double contents_height() const {
|
||||||
return (child_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 2);
|
return (child_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double note_to_y(uint8_t note) const {
|
|
||||||
return contents_height() - (note + 1 - lowest_note()) * note_height() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t y_to_note(double y) const;
|
|
||||||
|
|
||||||
inline double note_height() const {
|
|
||||||
return contents_height() / (double)contents_note_range();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t contents_note_range() const {
|
|
||||||
return highest_note() - lowest_note() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sigc::signal<void> NoteRangeChanged;
|
|
||||||
|
|
||||||
RegionView* create_region_view (std::shared_ptr<ARDOUR::Region>, bool, bool);
|
RegionView* create_region_view (std::shared_ptr<ARDOUR::Region>, bool, bool);
|
||||||
|
|
||||||
bool paste (Temporal::timepos_t const & pos, const Selection& selection, PasteContext& ctx);
|
bool paste (Temporal::timepos_t const & pos, const Selection& selection, PasteContext& ctx);
|
||||||
|
|
||||||
void apply_note_range(uint8_t lowest, uint8_t highest, bool to_region_views);
|
|
||||||
|
|
||||||
void suspend_updates ();
|
void suspend_updates ();
|
||||||
void resume_updates ();
|
void resume_updates ();
|
||||||
|
|
||||||
@ -120,11 +89,11 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void setup_rec_box ();
|
void setup_rec_box ();
|
||||||
void update_rec_box ();
|
void update_rec_box ();
|
||||||
|
bool updates_suspended() const { return _updates_suspended; }
|
||||||
|
|
||||||
ArdourCanvas::Container* _region_group;
|
ArdourCanvas::Container* _region_group;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
RegionView* add_region_view_internal (
|
RegionView* add_region_view_internal (
|
||||||
std::shared_ptr<ARDOUR::Region>,
|
std::shared_ptr<ARDOUR::Region>,
|
||||||
bool wait_for_waves,
|
bool wait_for_waves,
|
||||||
@ -133,24 +102,12 @@ private:
|
|||||||
void display_region(MidiRegionView* region_view, bool load_model);
|
void display_region(MidiRegionView* region_view, bool load_model);
|
||||||
void display_track (std::shared_ptr<ARDOUR::Track> tr);
|
void display_track (std::shared_ptr<ARDOUR::Track> tr);
|
||||||
|
|
||||||
void update_contents_height ();
|
void update_contents_metrics (std::shared_ptr<ARDOUR::Region> r);
|
||||||
|
|
||||||
void draw_note_lines();
|
|
||||||
bool update_data_note_range(uint8_t min, uint8_t max);
|
|
||||||
void update_contents_metrics(std::shared_ptr<ARDOUR::Region> r);
|
|
||||||
|
|
||||||
void color_handler ();
|
void color_handler ();
|
||||||
|
|
||||||
void note_range_adjustment_changed();
|
void apply_note_range_to_children ();
|
||||||
void apply_note_range_to_regions ();
|
|
||||||
|
|
||||||
bool _range_dirty;
|
|
||||||
double _range_sum_cache;
|
|
||||||
uint8_t _lowest_note; ///< currently visible
|
|
||||||
uint8_t _highest_note; ///< currently visible
|
|
||||||
uint8_t _data_note_min; ///< in data
|
|
||||||
uint8_t _data_note_max; ///< in data
|
|
||||||
ArdourCanvas::LineSet* _note_lines;
|
|
||||||
/** true if updates to the note lines and regions are currently suspended */
|
/** true if updates to the note lines and regions are currently suspended */
|
||||||
bool _updates_suspended;
|
bool _updates_suspended;
|
||||||
};
|
};
|
||||||
|
272
gtk2_ardour/midi_view_background.cc
Normal file
272
gtk2_ardour/midi_view_background.cc
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
|
||||||
|
* Copyright (C) 2007 Doug McLain <doug@nostar.net>
|
||||||
|
* Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
|
||||||
|
* Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
|
||||||
|
* Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
|
||||||
|
* Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
|
||||||
|
* Copyright (C) 2016 Nick Mainsbridge <mainsbridge@gmail.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 "canvas/line_set.h"
|
||||||
|
|
||||||
|
#include "midi_view_background.h"
|
||||||
|
#include "ui_config.h"
|
||||||
|
|
||||||
|
#include "pbd/i18n.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
MidiViewBackground::MidiViewBackground (ArdourCanvas::Item* parent)
|
||||||
|
: note_range_adjustment (0.0f, 0.0f, 0.0f)
|
||||||
|
, _range_dirty (false)
|
||||||
|
, _range_sum_cache (-1.0)
|
||||||
|
, _lowest_note (UIConfiguration::instance().get_default_lower_midi_note())
|
||||||
|
, _highest_note (UIConfiguration::instance().get_default_upper_midi_note())
|
||||||
|
, _data_note_min (60)
|
||||||
|
, _data_note_max (71)
|
||||||
|
, _note_lines (new ArdourCanvas::LineSet (parent, ArdourCanvas::LineSet::Horizontal))
|
||||||
|
{
|
||||||
|
_note_lines->lower_to_bottom();
|
||||||
|
|
||||||
|
color_handler ();
|
||||||
|
|
||||||
|
UIConfiguration::instance().ColorsChanged.connect(sigc::mem_fun(*this, &MidiViewBackground::color_handler));
|
||||||
|
UIConfiguration::instance().ParameterChanged.connect(sigc::mem_fun(*this, &MidiViewBackground::parameter_changed));
|
||||||
|
|
||||||
|
note_range_adjustment.set_page_size(_highest_note - _lowest_note);
|
||||||
|
note_range_adjustment.set_value(_lowest_note);
|
||||||
|
|
||||||
|
note_range_adjustment.signal_value_changed().connect(sigc::mem_fun(*this, &MidiViewBackground::note_range_adjustment_changed));
|
||||||
|
}
|
||||||
|
|
||||||
|
MidiViewBackground::~MidiViewBackground()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiViewBackground::parameter_changed (std::string const & param)
|
||||||
|
{
|
||||||
|
if (param == X_("max-note-height")) {
|
||||||
|
apply_note_range (_lowest_note, _highest_note, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiViewBackground::color_handler ()
|
||||||
|
{
|
||||||
|
draw_note_lines ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiViewBackground::note_range_adjustment_changed()
|
||||||
|
{
|
||||||
|
double sum = note_range_adjustment.get_value() + note_range_adjustment.get_page_size();
|
||||||
|
int lowest = (int) floor(note_range_adjustment.get_value());
|
||||||
|
int highest;
|
||||||
|
|
||||||
|
if (sum == _range_sum_cache) {
|
||||||
|
//cerr << "cached" << endl;
|
||||||
|
highest = (int) floor(sum);
|
||||||
|
} else {
|
||||||
|
//cerr << "recalc" << endl;
|
||||||
|
highest = lowest + (int) floor(note_range_adjustment.get_page_size());
|
||||||
|
_range_sum_cache = sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowest == _lowest_note && highest == _highest_note) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cerr << "note range adjustment changed: " << lowest << " " << highest << endl;
|
||||||
|
//cerr << " val=" << v_zoom_adjustment.get_value() << " page=" << v_zoom_adjustment.get_page_size() << " sum=" << v_zoom_adjustment.get_value() + v_zoom_adjustment.get_page_size() << endl;
|
||||||
|
|
||||||
|
_lowest_note = lowest;
|
||||||
|
_highest_note = highest;
|
||||||
|
apply_note_range (lowest, highest, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
MidiViewBackground::y_to_note (double y) const
|
||||||
|
{
|
||||||
|
int const n = ((contents_height() - y) / contents_height() * (double)contents_note_range())
|
||||||
|
+ lowest_note();
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (n > 127) {
|
||||||
|
return 127;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* min due to rounding and/or off-by-one errors */
|
||||||
|
return min ((uint8_t) n, highest_note());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiViewBackground::update_note_range(uint8_t note_num)
|
||||||
|
{
|
||||||
|
_data_note_min = min(_data_note_min, note_num);
|
||||||
|
_data_note_max = max(_data_note_max, note_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiViewBackground::update_contents_height ()
|
||||||
|
{
|
||||||
|
_note_lines->set_extent (ArdourCanvas::COORD_MAX);
|
||||||
|
apply_note_range (lowest_note(), highest_note(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiViewBackground::draw_note_lines()
|
||||||
|
{
|
||||||
|
if (updates_suspended()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double y;
|
||||||
|
double prev_y = 0.;
|
||||||
|
Gtkmm2ext::Color black = UIConfiguration::instance().color_mod ("piano roll black", "piano roll black");
|
||||||
|
Gtkmm2ext::Color white = UIConfiguration::instance().color_mod ("piano roll white", "piano roll white");
|
||||||
|
Gtkmm2ext::Color outline = UIConfiguration::instance().color ("piano roll black outline");
|
||||||
|
Gtkmm2ext::Color color;
|
||||||
|
|
||||||
|
ArdourCanvas::LineSet::ResetRAII lr (*_note_lines);
|
||||||
|
|
||||||
|
if (contents_height() < 140 || note_height() < 3) {
|
||||||
|
/* context is too small for note lines, or there are too many */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do this is order of highest ... lowest since that matches the
|
||||||
|
* coordinate system in which y=0 is at the top
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (int i = highest_note() + 1; i >= lowest_note(); --i) {
|
||||||
|
|
||||||
|
y = floor (note_to_y (i));
|
||||||
|
|
||||||
|
/* add a thicker line/bar which covers the entire vertical height of this note. */
|
||||||
|
|
||||||
|
switch (i % 12) {
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
case 6:
|
||||||
|
case 8:
|
||||||
|
case 10:
|
||||||
|
color = black;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 11:
|
||||||
|
/* this is the line actually corresponding to the division between B & C and E & F */
|
||||||
|
_note_lines->add_coord (y, 1.0, outline);
|
||||||
|
/* fallthrough */
|
||||||
|
default:
|
||||||
|
color = white;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
double h = y - prev_y;
|
||||||
|
double middle = y + (h/2.0);
|
||||||
|
|
||||||
|
if (!fmod (h, 2.) && !fmod (middle, 1.)) {
|
||||||
|
middle += 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (middle >= 0 && h > 1.0) {
|
||||||
|
_note_lines->add_coord (middle, h, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiViewBackground::set_note_range(VisibleNoteRange r)
|
||||||
|
{
|
||||||
|
if (r == FullRange) {
|
||||||
|
_lowest_note = 0;
|
||||||
|
_highest_note = 127;
|
||||||
|
} else {
|
||||||
|
_lowest_note = _data_note_min;
|
||||||
|
_highest_note = _data_note_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_note_range(_lowest_note, _highest_note, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiViewBackground::apply_note_range(uint8_t lowest, uint8_t highest, bool to_children)
|
||||||
|
{
|
||||||
|
_highest_note = highest;
|
||||||
|
_lowest_note = lowest;
|
||||||
|
|
||||||
|
float uiscale = UIConfiguration::instance().get_ui_scale();
|
||||||
|
uiscale = expf (uiscale) / expf (1.f);
|
||||||
|
|
||||||
|
const int mnh = UIConfiguration::instance().get_max_note_height();
|
||||||
|
int const max_note_height = std::max<int> (mnh, mnh * uiscale);
|
||||||
|
int const range = _highest_note - _lowest_note;
|
||||||
|
|
||||||
|
int const available_note_range = floor (contents_height() / max_note_height);
|
||||||
|
int additional_notes = available_note_range - range;
|
||||||
|
|
||||||
|
/* distribute additional notes to higher and lower ranges, clamp at 0 and 127 */
|
||||||
|
for (int i = 0; i < additional_notes; i++){
|
||||||
|
|
||||||
|
if (i % 2 && _highest_note < 127){
|
||||||
|
_highest_note++;
|
||||||
|
}
|
||||||
|
else if (i % 2) {
|
||||||
|
_lowest_note--;
|
||||||
|
}
|
||||||
|
else if (_lowest_note > 0){
|
||||||
|
_lowest_note--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_highest_note++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
note_range_adjustment.set_page_size (_highest_note - _lowest_note);
|
||||||
|
note_range_adjustment.set_value (_lowest_note);
|
||||||
|
|
||||||
|
draw_note_lines();
|
||||||
|
|
||||||
|
if (to_children) {
|
||||||
|
apply_note_range_to_children ();
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteRangeChanged(); /* EMIT SIGNAL*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
MidiViewBackground::update_data_note_range (uint8_t min, uint8_t max)
|
||||||
|
{
|
||||||
|
bool dirty = false;
|
||||||
|
if (min < _data_note_min) {
|
||||||
|
_data_note_min = min;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
if (max > _data_note_max) {
|
||||||
|
_data_note_max = max;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
return dirty;
|
||||||
|
}
|
96
gtk2_ardour/midi_view_background.h
Normal file
96
gtk2_ardour/midi_view_background.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
|
||||||
|
* Copyright (C) 2007 Doug McLain <doug@nostar.net>
|
||||||
|
* Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
|
||||||
|
* Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
|
||||||
|
* Copyright (C) 2016-2017 Robin Gareus <robin@gareus.org>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __gtk2_ardour_midi_view_background_h__
|
||||||
|
#define __gtk2_ardour_midi_view_background_h__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <gtkmm/adjustment.h>
|
||||||
|
|
||||||
|
namespace ArdourCanvas {
|
||||||
|
class Item;
|
||||||
|
class LineSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MidiViewBackground
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MidiViewBackground (ArdourCanvas::Item* parent);
|
||||||
|
virtual ~MidiViewBackground ();
|
||||||
|
|
||||||
|
Gtk::Adjustment note_range_adjustment;
|
||||||
|
|
||||||
|
enum VisibleNoteRange {
|
||||||
|
FullRange,
|
||||||
|
ContentsRange
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_note_range (VisibleNoteRange r);
|
||||||
|
|
||||||
|
inline uint8_t lowest_note() const { return _lowest_note; }
|
||||||
|
inline uint8_t highest_note() const { return _highest_note; }
|
||||||
|
|
||||||
|
void update_note_range(uint8_t note_num);
|
||||||
|
|
||||||
|
virtual double contents_height() const = 0;
|
||||||
|
|
||||||
|
double note_to_y (uint8_t note) const {
|
||||||
|
return contents_height() - (note + 1 - lowest_note()) * note_height() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t y_to_note(double y) const;
|
||||||
|
|
||||||
|
uint8_t contents_note_range() const {
|
||||||
|
return highest_note() - lowest_note() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double note_height() const {
|
||||||
|
return contents_height() / (double)contents_note_range();
|
||||||
|
}
|
||||||
|
|
||||||
|
sigc::signal<void> NoteRangeChanged;
|
||||||
|
void apply_note_range (uint8_t lowest, uint8_t highest, bool to_children);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool _range_dirty;
|
||||||
|
double _range_sum_cache;
|
||||||
|
uint8_t _lowest_note; ///< currently visible
|
||||||
|
uint8_t _highest_note; ///< currently visible
|
||||||
|
uint8_t _data_note_min; ///< in data
|
||||||
|
uint8_t _data_note_max; ///< in data
|
||||||
|
ArdourCanvas::LineSet* _note_lines;
|
||||||
|
|
||||||
|
void color_handler ();
|
||||||
|
void parameter_changed (std::string const &);
|
||||||
|
void note_range_adjustment_changed();
|
||||||
|
void update_contents_height ();
|
||||||
|
void draw_note_lines();
|
||||||
|
bool update_data_note_range(uint8_t min, uint8_t max);
|
||||||
|
virtual void apply_note_range_to_children () = 0;
|
||||||
|
virtual bool updates_suspended() const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __gtk2_ardour_midi_view_background_h__ */
|
@ -468,9 +468,6 @@ public:
|
|||||||
|
|
||||||
virtual void queue_redisplay_track_views () = 0;
|
virtual void queue_redisplay_track_views () = 0;
|
||||||
|
|
||||||
virtual ARDOUR::Quantize* get_quantize_op () = 0;
|
|
||||||
virtual void apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs) = 0;
|
|
||||||
|
|
||||||
virtual void set_tempo_curve_range (double& max, double& min) const = 0;
|
virtual void set_tempo_curve_range (double& max, double& min) const = 0;
|
||||||
|
|
||||||
virtual void start_track_drag (TimeAxisView&, int y, Gtk::Widget&, bool can_change_cursor) = 0;
|
virtual void start_track_drag (TimeAxisView&, int y, Gtk::Widget&, bool can_change_cursor) = 0;
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#include "pbd/convert.h"
|
#include "pbd/convert.h"
|
||||||
#include "quantize_dialog.h"
|
#include "quantize_dialog.h"
|
||||||
#include "public_editor.h"
|
#include "editing_context.h"
|
||||||
|
|
||||||
#include "pbd/i18n.h"
|
#include "pbd/i18n.h"
|
||||||
#include "pbd/integer_division.h"
|
#include "pbd/integer_division.h"
|
||||||
@ -71,7 +71,7 @@ static const int _grid_beats[] = {
|
|||||||
|
|
||||||
std::vector<std::string> QuantizeDialog::grid_strings;
|
std::vector<std::string> QuantizeDialog::grid_strings;
|
||||||
|
|
||||||
QuantizeDialog::QuantizeDialog (PublicEditor& e)
|
QuantizeDialog::QuantizeDialog (EditingContext& e)
|
||||||
: ArdourDialog (_("Quantize"), false, false)
|
: ArdourDialog (_("Quantize"), false, false)
|
||||||
, editor (e)
|
, editor (e)
|
||||||
, strength_adjustment (100.0, 0.0, 100.0, 1.0, 10.0)
|
, strength_adjustment (100.0, 0.0, 100.0, 1.0, 10.0)
|
||||||
|
@ -38,12 +38,12 @@ namespace ARDOUR {
|
|||||||
class MidiModel;
|
class MidiModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PublicEditor;
|
class EditingContext;
|
||||||
|
|
||||||
class QuantizeDialog : public ArdourDialog
|
class QuantizeDialog : public ArdourDialog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QuantizeDialog (PublicEditor&);
|
QuantizeDialog (EditingContext&);
|
||||||
~QuantizeDialog ();
|
~QuantizeDialog ();
|
||||||
|
|
||||||
Temporal::Beats start_grid_size() const;
|
Temporal::Beats start_grid_size() const;
|
||||||
@ -55,7 +55,7 @@ public:
|
|||||||
float swing () const;
|
float swing () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PublicEditor& editor;
|
EditingContext& editor;
|
||||||
|
|
||||||
Gtk::ComboBoxText start_grid_combo;
|
Gtk::ComboBoxText start_grid_combo;
|
||||||
Gtk::ComboBoxText end_grid_combo;
|
Gtk::ComboBoxText end_grid_combo;
|
||||||
|
@ -147,11 +147,13 @@ TriggerPage::TriggerPage ()
|
|||||||
table->attach (_audio_trig_box, col, col + 1, 0, 1, Gtk::FILL, Gtk::SHRINK | Gtk::FILL);
|
table->attach (_audio_trig_box, col, col + 1, 0, 1, Gtk::FILL, Gtk::SHRINK | Gtk::FILL);
|
||||||
++col;
|
++col;
|
||||||
|
|
||||||
#ifdef MIDI_PROPERTIES_BOX_IMPLEMENTED
|
|
||||||
col = 2;
|
col = 2;
|
||||||
table->attach (_midi_trig_box, col, col + 1, 0, 1, Gtk::FILL, Gtk::SHRINK);
|
table->attach (_midi_trig_box, col, col + 1, 0, 1, Gtk::FILL, Gtk::SHRINK);
|
||||||
++col;
|
++col;
|
||||||
#endif
|
|
||||||
|
col = 3;
|
||||||
|
table->attach (_midi_trim_box, col, col + 1, 0, 1, Gtk::EXPAND, Gtk::SHRINK);
|
||||||
|
++col;
|
||||||
|
|
||||||
_parameter_box.pack_start (*table);
|
_parameter_box.pack_start (*table);
|
||||||
|
|
||||||
@ -282,6 +284,7 @@ TriggerPage::set_session (Session* s)
|
|||||||
_audio_trig_box.set_session (s);
|
_audio_trig_box.set_session (s);
|
||||||
|
|
||||||
_midi_trig_box.set_session (s);
|
_midi_trig_box.set_session (s);
|
||||||
|
_midi_trim_box.set_session (s);
|
||||||
|
|
||||||
update_title ();
|
update_title ();
|
||||||
start_updating ();
|
start_updating ();
|
||||||
@ -386,6 +389,7 @@ TriggerPage::selection_changed ()
|
|||||||
_audio_trig_box.hide ();
|
_audio_trig_box.hide ();
|
||||||
|
|
||||||
_midi_trig_box.hide ();
|
_midi_trig_box.hide ();
|
||||||
|
_midi_trim_box.hide ();
|
||||||
|
|
||||||
_parameter_box.hide ();
|
_parameter_box.hide ();
|
||||||
|
|
||||||
@ -404,6 +408,9 @@ TriggerPage::selection_changed ()
|
|||||||
} else {
|
} else {
|
||||||
_midi_trig_box.set_trigger (ref);
|
_midi_trig_box.set_trigger (ref);
|
||||||
_midi_trig_box.show ();
|
_midi_trig_box.show ();
|
||||||
|
|
||||||
|
// _midi_trim_box.set_trigger (ref);
|
||||||
|
_midi_trim_box.show ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_parameter_box.show ();
|
_parameter_box.show ();
|
||||||
|
@ -133,10 +133,10 @@ private:
|
|||||||
#if REGION_PROPERTIES_BOX_TODO
|
#if REGION_PROPERTIES_BOX_TODO
|
||||||
AudioRegionOperationsBox _audio_ops_box;
|
AudioRegionOperationsBox _audio_ops_box;
|
||||||
AudioClipEditorBox _audio_trim_box;
|
AudioClipEditorBox _audio_trim_box;
|
||||||
|
#endif
|
||||||
|
|
||||||
MidiRegionOperationsBox _midi_ops_box;
|
MidiRegionOperationsBox _midi_ops_box;
|
||||||
MidiClipEditorBox _midi_trim_box;
|
MidiClipEditorBox _midi_trim_box;
|
||||||
#endif
|
|
||||||
|
|
||||||
RouteProcessorSelection _selection;
|
RouteProcessorSelection _selection;
|
||||||
std::list<TriggerStrip*> _strips;
|
std::list<TriggerStrip*> _strips;
|
||||||
|
@ -172,6 +172,7 @@ gtk2_ardour_sources = [
|
|||||||
'midi_time_axis.cc',
|
'midi_time_axis.cc',
|
||||||
'midi_tracer.cc',
|
'midi_tracer.cc',
|
||||||
'midi_velocity_dialog.cc',
|
'midi_velocity_dialog.cc',
|
||||||
|
'midi_view_background.cc',
|
||||||
'mini_timeline.cc',
|
'mini_timeline.cc',
|
||||||
'missing_file_dialog.cc',
|
'missing_file_dialog.cc',
|
||||||
'missing_filesource_dialog.cc',
|
'missing_filesource_dialog.cc',
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
#include "temporal/beats.h"
|
#include "temporal/beats.h"
|
||||||
#include "evoral/Sequence.h"
|
#include "evoral/Sequence.h"
|
||||||
|
|
||||||
|
#include "ardour/libardour_visibility.h"
|
||||||
|
|
||||||
namespace PBD {
|
namespace PBD {
|
||||||
class Command;
|
class Command;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user