mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 07:45:00 +01:00
Eliminate a ton of unnecessary complete redrawing in MIDI stream views:
Only resize vertically (don't reaload model) on range changes. Keep track of range in model while loading (writing to model), rather than double display MIDI regions to find out. Don't go crazy and chew CPU blinking around and doing nothing on initial show of MIDI track context menu. Change radio 'full range' and 'contents range' menu items to non-radio actions that just set the range appropriately. Fix crashes on some esoteric case of control data I can't figure out, but fixed anyway, so I guess it all worked out well in the end for everybody. git-svn-id: svn://localhost/ardour2/branches/3.0@3794 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
234d56a8c4
commit
ffaf827d93
9 changed files with 230 additions and 134 deletions
|
|
@ -65,6 +65,8 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
|
||||||
, _force_channel(-1)
|
, _force_channel(-1)
|
||||||
, _last_channel_selection(0xFFFF)
|
, _last_channel_selection(0xFFFF)
|
||||||
, _default_note_length(0.0)
|
, _default_note_length(0.0)
|
||||||
|
, _current_range_min(0)
|
||||||
|
, _current_range_max(0)
|
||||||
, _active_notes(0)
|
, _active_notes(0)
|
||||||
, _note_group(new ArdourCanvas::Group(*parent))
|
, _note_group(new ArdourCanvas::Group(*parent))
|
||||||
, _delta_command(NULL)
|
, _delta_command(NULL)
|
||||||
|
|
@ -399,7 +401,7 @@ MidiRegionView::create_note_at(double x, double y, double length)
|
||||||
|
|
||||||
const boost::shared_ptr<Evoral::Note> new_note(new Evoral::Note(
|
const boost::shared_ptr<Evoral::Note> new_note(new Evoral::Note(
|
||||||
0, new_note_time, new_note_length, (uint8_t)note, 0x40));
|
0, new_note_time, new_note_length, (uint8_t)note, 0x40));
|
||||||
view->update_bounds(new_note->note());
|
view->update_note_range(new_note->note());
|
||||||
|
|
||||||
MidiModel::DeltaCommand* cmd = _model->new_delta_command("add note");
|
MidiModel::DeltaCommand* cmd = _model->new_delta_command("add note");
|
||||||
cmd->add(new_note);
|
cmd->add(new_note);
|
||||||
|
|
@ -419,7 +421,7 @@ MidiRegionView::clear_events()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i)
|
for (Events::iterator i = _events.begin(); i != _events.end(); ++i)
|
||||||
delete *i;
|
delete *i;
|
||||||
|
|
||||||
_events.clear();
|
_events.clear();
|
||||||
|
|
@ -613,25 +615,41 @@ MidiRegionView::reset_width_dependent_items (double pixel_width)
|
||||||
void
|
void
|
||||||
MidiRegionView::set_height (gdouble height)
|
MidiRegionView::set_height (gdouble height)
|
||||||
{
|
{
|
||||||
|
static const double FUDGE = 2;
|
||||||
|
const double old_height = _height;
|
||||||
RegionView::set_height(height);
|
RegionView::set_height(height);
|
||||||
|
_height = height - FUDGE;
|
||||||
|
|
||||||
// FIXME: ick
|
apply_note_range(midi_stream_view()->lowest_note(),
|
||||||
height -= 2;
|
midi_stream_view()->highest_note(),
|
||||||
|
height != old_height + FUDGE);
|
||||||
_height = height;
|
|
||||||
|
|
||||||
|
if (name_text) {
|
||||||
|
name_text->raise_to_top();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Apply the current note range from the stream view
|
||||||
|
* by repositioning/hiding notes as necessary
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MidiRegionView::apply_note_range (uint8_t min, uint8_t max, bool force)
|
||||||
|
{
|
||||||
if (_enable_display) {
|
if (_enable_display) {
|
||||||
|
if (!force && _current_range_min == min && _current_range_max == max) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_current_range_min = min;
|
||||||
|
_current_range_max = max;
|
||||||
|
|
||||||
_model->read_lock();
|
for (Events::const_iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||||
|
|
||||||
for (std::vector<CanvasNoteEvent*>::const_iterator i = _events.begin(); i != _events.end(); ++i) {
|
|
||||||
CanvasNoteEvent* event = *i;
|
CanvasNoteEvent* event = *i;
|
||||||
Item* item = dynamic_cast<Item*>(event);
|
Item* item = dynamic_cast<Item*>(event);
|
||||||
assert(item);
|
assert(item);
|
||||||
if (event && event->note()) {
|
if (event && event->note()) {
|
||||||
if (event->note()->note() < midi_stream_view()->lowest_note() ||
|
if (event->note()->note() < _current_range_min || event->note()->note() > _current_range_max) {
|
||||||
event->note()->note() > midi_stream_view()->highest_note()) {
|
|
||||||
|
|
||||||
if (canvas_item_visible(item)) {
|
if (canvas_item_visible(item)) {
|
||||||
item->hide();
|
item->hide();
|
||||||
}
|
}
|
||||||
|
|
@ -647,8 +665,7 @@ MidiRegionView::set_height (gdouble height)
|
||||||
|
|
||||||
note->property_y1() = y1;
|
note->property_y1() = y1;
|
||||||
note->property_y2() = y2;
|
note->property_y2() = y2;
|
||||||
}
|
} else if (CanvasHit* hit = dynamic_cast<CanvasHit*>(event)) {
|
||||||
if (CanvasHit* hit = dynamic_cast<CanvasHit*>(event)) {
|
|
||||||
double x = trackview.editor.frame_to_pixel((nframes64_t)
|
double x = trackview.editor.frame_to_pixel((nframes64_t)
|
||||||
event->note()->time() - _region->start());
|
event->note()->time() - _region->start());
|
||||||
const double diamond_size = midi_stream_view()->note_height() / 2.0;
|
const double diamond_size = midi_stream_view()->note_height() / 2.0;
|
||||||
|
|
@ -666,11 +683,6 @@ MidiRegionView::set_height (gdouble height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_model->read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name_text) {
|
|
||||||
name_text->raise_to_top();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -700,7 +712,7 @@ MidiRegionView::add_ghost (TimeAxisView& tv)
|
||||||
ghost->set_duration (_region->length() / samples_per_unit);
|
ghost->set_duration (_region->length() / samples_per_unit);
|
||||||
ghosts.push_back (ghost);
|
ghosts.push_back (ghost);
|
||||||
|
|
||||||
for (std::vector<CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||||
if ((note = dynamic_cast<CanvasNote*>(*i)) != 0) {
|
if ((note = dynamic_cast<CanvasNote*>(*i)) != 0) {
|
||||||
ghost->add_note(note);
|
ghost->add_note(note);
|
||||||
}
|
}
|
||||||
|
|
@ -977,7 +989,7 @@ MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (x1 < x2) {
|
if (x1 < x2) {
|
||||||
for (std::vector<CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// Events should always be sorted by increasing x1() here
|
// Events should always be sorted by increasing x1() here
|
||||||
assert((*i)->x1() >= last_x1);
|
assert((*i)->x1() >= last_x1);
|
||||||
|
|
@ -996,7 +1008,7 @@ MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (std::vector<CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// Events should always be sorted by increasing x1() here
|
// Events should always be sorted by increasing x1() here
|
||||||
assert((*i)->x1() >= last_x1);
|
assert((*i)->x1() >= last_x1);
|
||||||
|
|
@ -1106,7 +1118,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
|
||||||
|
|
||||||
// care about notes being moved beyond the upper/lower bounds on the canvas
|
// care about notes being moved beyond the upper/lower bounds on the canvas
|
||||||
if (lowest_note_in_selection < midi_stream_view()->lowest_note() ||
|
if (lowest_note_in_selection < midi_stream_view()->lowest_note() ||
|
||||||
highest_note_in_selection > midi_stream_view()->highest_note()) {
|
highest_note_in_selection > midi_stream_view()->highest_note()) {
|
||||||
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
|
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1378,8 +1390,7 @@ MidiRegionView::midi_channel_mode_changed(ChannelMode mode, uint16_t mask)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update notes for selection
|
// Update notes for selection
|
||||||
for (std::vector<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin();
|
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||||
i != _events.end(); ++i) {
|
|
||||||
(*i)->on_channel_selection_change(mask);
|
(*i)->on_channel_selection_change(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ class MidiRegionView : public RegionView
|
||||||
{ return midi_view()->midi_view(); }
|
{ return midi_view()->midi_view(); }
|
||||||
|
|
||||||
void set_height (double);
|
void set_height (double);
|
||||||
|
void apply_note_range(uint8_t lowest, uint8_t highest, bool force=false);
|
||||||
|
|
||||||
void set_frame_color();
|
void set_frame_color();
|
||||||
|
|
||||||
|
|
@ -223,13 +224,18 @@ class MidiRegionView : public RegionView
|
||||||
int8_t _force_channel;
|
int8_t _force_channel;
|
||||||
uint16_t _last_channel_selection;
|
uint16_t _last_channel_selection;
|
||||||
double _default_note_length;
|
double _default_note_length;
|
||||||
|
uint8_t _current_range_min;
|
||||||
|
uint8_t _current_range_max;
|
||||||
|
|
||||||
boost::shared_ptr<ARDOUR::MidiModel> _model;
|
typedef std::vector<ArdourCanvas::CanvasNoteEvent*> Events;
|
||||||
std::vector<ArdourCanvas::CanvasNoteEvent*> _events;
|
typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasProgramChange> > PgmChanges;
|
||||||
std::vector< boost::shared_ptr<ArdourCanvas::CanvasProgramChange> > _pgm_changes;
|
|
||||||
ArdourCanvas::CanvasNote** _active_notes;
|
boost::shared_ptr<ARDOUR::MidiModel> _model;
|
||||||
ArdourCanvas::Group* _note_group;
|
Events _events;
|
||||||
ARDOUR::MidiModel::DeltaCommand* _delta_command;
|
PgmChanges _pgm_changes;
|
||||||
|
ArdourCanvas::CanvasNote** _active_notes;
|
||||||
|
ArdourCanvas::Group* _note_group;
|
||||||
|
ARDOUR::MidiModel::DeltaCommand* _delta_command;
|
||||||
|
|
||||||
MouseState _mouse_state;
|
MouseState _mouse_state;
|
||||||
int _pressed_button;
|
int _pressed_button;
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,12 @@ using namespace Editing;
|
||||||
MidiStreamView::MidiStreamView (MidiTimeAxisView& tv)
|
MidiStreamView::MidiStreamView (MidiTimeAxisView& tv)
|
||||||
: StreamView (tv)
|
: StreamView (tv)
|
||||||
, note_range_adjustment(0.0f, 0.0f, 0.0f)
|
, note_range_adjustment(0.0f, 0.0f, 0.0f)
|
||||||
, _range(ContentsRange)
|
, _range_dirty(false)
|
||||||
, _range_sum_cache(-1.0)
|
, _range_sum_cache(-1.0)
|
||||||
, _lowest_note(60)
|
, _lowest_note(60)
|
||||||
, _highest_note(60)
|
, _highest_note(71)
|
||||||
|
, _data_note_min(60)
|
||||||
|
, _data_note_max(71)
|
||||||
{
|
{
|
||||||
if (tv.is_track())
|
if (tv.is_track())
|
||||||
stream_base_color = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
|
stream_base_color = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
|
||||||
|
|
@ -83,14 +85,45 @@ MidiStreamView::MidiStreamView (MidiTimeAxisView& tv)
|
||||||
_note_lines->signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_stream_view_event), _note_lines, &_trackview));
|
_note_lines->signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_stream_view_event), _note_lines, &_trackview));
|
||||||
_note_lines->lower_to_bottom();
|
_note_lines->lower_to_bottom();
|
||||||
|
|
||||||
note_range_adjustment.signal_value_changed().connect (mem_fun (*this, &MidiStreamView::note_range_adjustment_changed));
|
|
||||||
ColorsChanged.connect(mem_fun(*this, &MidiStreamView::draw_note_lines));
|
ColorsChanged.connect(mem_fun(*this, &MidiStreamView::draw_note_lines));
|
||||||
|
|
||||||
|
note_range_adjustment.set_page_size(_highest_note - _lowest_note);
|
||||||
|
note_range_adjustment.set_value(_lowest_note);
|
||||||
|
|
||||||
|
note_range_adjustment.signal_value_changed().connect (mem_fun (*this, &MidiStreamView::note_range_adjustment_changed));
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiStreamView::~MidiStreamView ()
|
MidiStreamView::~MidiStreamView ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
veto_note_range(uint8_t& min, uint8_t& max)
|
||||||
|
{
|
||||||
|
/* Legal notes, thanks */
|
||||||
|
if (max > 127)
|
||||||
|
max = 127;
|
||||||
|
if (min > 127)
|
||||||
|
min = 127;
|
||||||
|
|
||||||
|
/* Always display at least one octave in [0, 127] */
|
||||||
|
if (max == 127) {
|
||||||
|
if (min > (127 - 11)) {
|
||||||
|
min = 127 - 11;
|
||||||
|
}
|
||||||
|
} else if (max < min + 11) {
|
||||||
|
uint8_t d = 11 - (max - min);
|
||||||
|
if (max + d/2 > 127) {
|
||||||
|
min -= d;
|
||||||
|
} else {
|
||||||
|
min -= d / 2;
|
||||||
|
max += d / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(max - min >= 11);
|
||||||
|
assert(max < 127);
|
||||||
|
assert(min < 127);
|
||||||
|
}
|
||||||
|
|
||||||
RegionView*
|
RegionView*
|
||||||
MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd, bool recording)
|
MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd, bool recording)
|
||||||
|
|
@ -110,7 +143,7 @@ MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd,
|
||||||
/* great. we already have a MidiRegionView for this Region. use it again. */
|
/* great. we already have a MidiRegionView for this Region. use it again. */
|
||||||
|
|
||||||
(*i)->set_valid (true);
|
(*i)->set_valid (true);
|
||||||
(*i)->enable_display(wfd);
|
|
||||||
display_region(dynamic_cast<MidiRegionView*>(*i), wfd);
|
display_region(dynamic_cast<MidiRegionView*>(*i), wfd);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -122,20 +155,10 @@ MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd,
|
||||||
|
|
||||||
region_view->init (region_color, false);
|
region_view->init (region_color, false);
|
||||||
region_views.push_front (region_view);
|
region_views.push_front (region_view);
|
||||||
|
|
||||||
/* follow global waveform setting */
|
|
||||||
|
|
||||||
if (wfd) {
|
|
||||||
region_view->enable_display(true);
|
|
||||||
region_view->midi_region()->midi_source(0)->load_model();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* display events and find note range */
|
/* display events and find note range */
|
||||||
display_region(region_view, wfd);
|
display_region(region_view, wfd);
|
||||||
|
|
||||||
/* always display at least 1 octave range */
|
|
||||||
_highest_note = max(_highest_note, static_cast<uint8_t>(_lowest_note + 11));
|
|
||||||
|
|
||||||
/* catch regionview going away */
|
/* catch regionview going away */
|
||||||
region->GoingAway.connect (bind (mem_fun (*this, &MidiStreamView::remove_region_view), region));
|
region->GoingAway.connect (bind (mem_fun (*this, &MidiStreamView::remove_region_view), region));
|
||||||
|
|
||||||
|
|
@ -149,17 +172,18 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model)
|
||||||
{
|
{
|
||||||
if ( ! region_view)
|
if ( ! region_view)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
region_view->enable_display(true);
|
||||||
|
|
||||||
boost::shared_ptr<MidiSource> source(region_view->midi_region()->midi_source(0));
|
boost::shared_ptr<MidiSource> source(region_view->midi_region()->midi_source(0));
|
||||||
|
|
||||||
if (load_model)
|
if (load_model)
|
||||||
source->load_model();
|
source->load_model();
|
||||||
|
|
||||||
// Find our note range
|
_range_dirty = update_data_note_range(
|
||||||
if (source->model())
|
source->model()->lowest_note(),
|
||||||
for (size_t i=0; i < source->model()->n_notes(); ++i)
|
source->model()->highest_note());
|
||||||
update_bounds(source->model()->note_at(i)->note());
|
|
||||||
|
|
||||||
// Display region contents
|
// Display region contents
|
||||||
region_view->display_model(source->model());
|
region_view->display_model(source->model());
|
||||||
}
|
}
|
||||||
|
|
@ -171,6 +195,21 @@ MidiStreamView::display_diskstream (boost::shared_ptr<Diskstream> ds)
|
||||||
draw_note_lines();
|
draw_note_lines();
|
||||||
NoteRangeChanged();
|
NoteRangeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: code duplication with AudioStreamView
|
// FIXME: code duplication with AudioStreamView
|
||||||
void
|
void
|
||||||
|
|
@ -178,32 +217,49 @@ MidiStreamView::redisplay_diskstream ()
|
||||||
{
|
{
|
||||||
list<RegionView *>::iterator i, tmp;
|
list<RegionView *>::iterator i, tmp;
|
||||||
|
|
||||||
for (i = region_views.begin(); i != region_views.end(); ++i) {
|
_range_dirty = false;
|
||||||
(*i)->enable_display(true); // FIXME: double display, remove
|
_data_note_min = 127;
|
||||||
(*i)->set_valid (false);
|
_data_note_max = 0;
|
||||||
|
|
||||||
/* FIXME: slow. MidiRegionView needs a find_note_range method
|
|
||||||
* that finds the range without wasting time drawing the events */
|
|
||||||
|
|
||||||
|
for (i = region_views.begin(); i != region_views.end(); ++i) {
|
||||||
|
(*i)->set_valid (false);
|
||||||
|
(*i)->enable_display (false);
|
||||||
|
|
||||||
// Load model if it isn't already, to get note range
|
// Load model if it isn't already, to get note range
|
||||||
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
|
||||||
mrv->midi_region()->midi_source(0)->load_model();
|
if (mrv) {
|
||||||
|
mrv->midi_region()->midi_source(0)->load_model();
|
||||||
|
_range_dirty = update_data_note_range(
|
||||||
|
mrv->midi_region()->model()->lowest_note(),
|
||||||
|
mrv->midi_region()->model()->highest_note());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No notes, use default range
|
||||||
|
if (!_range_dirty) {
|
||||||
|
_data_note_min = 60;
|
||||||
|
_data_note_max = 71;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool range_changed = false;
|
||||||
|
|
||||||
|
// Extend visible range to show newly recorded data, if necessary
|
||||||
|
if (_data_note_min < _lowest_note) {
|
||||||
|
_lowest_note = _data_note_min;
|
||||||
|
range_changed = true;
|
||||||
|
}
|
||||||
|
if (_data_note_max > _highest_note) {
|
||||||
|
_highest_note = _data_note_max;
|
||||||
|
range_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
veto_note_range(_lowest_note, _highest_note);
|
||||||
|
|
||||||
if (_trackview.is_midi_track()) {
|
if (_trackview.is_midi_track()) {
|
||||||
_trackview.get_diskstream()->playlist()->foreach_region (
|
_trackview.get_diskstream()->playlist()->foreach_region (
|
||||||
static_cast<StreamView*>(this), &StreamView::add_region_view);
|
static_cast<StreamView*>(this), &StreamView::add_region_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Always display at least one octave */
|
|
||||||
if (_highest_note == 127) {
|
|
||||||
if (_lowest_note > (127 - 11)) {
|
|
||||||
_lowest_note = 127 - 11;
|
|
||||||
}
|
|
||||||
} else if (_highest_note < _lowest_note + 11) {
|
|
||||||
_highest_note = _lowest_note + 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegionViewList copy;
|
RegionViewList copy;
|
||||||
|
|
||||||
/* Place regions */
|
/* Place regions */
|
||||||
|
|
@ -256,15 +312,12 @@ MidiStreamView::redisplay_diskstream ()
|
||||||
|
|
||||||
/* Fix canvas layering */
|
/* Fix canvas layering */
|
||||||
for (RegionViewList::iterator j = copy.begin(); j != copy.end(); ++j) {
|
for (RegionViewList::iterator j = copy.begin(); j != copy.end(); ++j) {
|
||||||
(*j)->enable_display(true); // FIXME: do this?
|
|
||||||
region_layered (*j);
|
region_layered (*j);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update note range and draw note lines */
|
/* Update note range and re-draw note lines if necessary */
|
||||||
note_range_adjustment.set_page_size(_highest_note - _lowest_note);
|
apply_note_range(_lowest_note, _highest_note);
|
||||||
note_range_adjustment.set_value(_lowest_note);
|
|
||||||
NoteRangeChanged();
|
NoteRangeChanged();
|
||||||
draw_note_lines();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -285,12 +338,12 @@ MidiStreamView::draw_note_lines()
|
||||||
|
|
||||||
_note_lines->clear();
|
_note_lines->clear();
|
||||||
|
|
||||||
for(int i = _lowest_note; i <= _highest_note; ++i) {
|
for (int i = lowest_note(); i <= highest_note(); ++i) {
|
||||||
y = floor(note_to_y(i));
|
y = floor(note_to_y(i));
|
||||||
|
|
||||||
_note_lines->add_line(prev_y, 1.0, ARDOUR_UI::config()->canvasvar_PianoRollBlackOutline.get());
|
_note_lines->add_line(prev_y, 1.0, ARDOUR_UI::config()->canvasvar_PianoRollBlackOutline.get());
|
||||||
|
|
||||||
switch(i % 12) {
|
switch (i % 12) {
|
||||||
case 1:
|
case 1:
|
||||||
case 3:
|
case 3:
|
||||||
case 6:
|
case 6:
|
||||||
|
|
@ -303,56 +356,54 @@ MidiStreamView::draw_note_lines()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i == _highest_note) {
|
if (i == highest_note()) {
|
||||||
_note_lines->add_line(y, prev_y - y, color);
|
_note_lines->add_line(y, prev_y - y, color);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
_note_lines->add_line(y + 1.0, prev_y - y - 1.0, color);
|
_note_lines->add_line(y + 1.0, prev_y - y - 1.0, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_y = y;
|
prev_y = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStreamView::set_note_range(VisibleNoteRange r)
|
MidiStreamView::set_note_range(VisibleNoteRange r)
|
||||||
{
|
{
|
||||||
_range = r;
|
|
||||||
if (r == FullRange) {
|
if (r == FullRange) {
|
||||||
_lowest_note = 0;
|
_lowest_note = 0;
|
||||||
_highest_note = 127;
|
_highest_note = 127;
|
||||||
} else {
|
} else {
|
||||||
_lowest_note = 60;
|
_lowest_note = _data_note_min;
|
||||||
_highest_note = 60;
|
_highest_note = _data_note_max;
|
||||||
}
|
}
|
||||||
redisplay_diskstream();
|
|
||||||
|
apply_note_range(_lowest_note, _highest_note);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStreamView::set_note_range(uint8_t lowest, uint8_t highest) {
|
MidiStreamView::apply_note_range(uint8_t lowest, uint8_t highest)
|
||||||
if(_range == ContentsRange) {
|
{
|
||||||
_lowest_note = lowest;
|
_highest_note = highest;
|
||||||
_highest_note = highest;
|
_lowest_note = lowest;
|
||||||
|
note_range_adjustment.set_page_size(_highest_note - _lowest_note);
|
||||||
list<RegionView *>::iterator i;
|
note_range_adjustment.set_value(_lowest_note);
|
||||||
for (i = region_views.begin(); i != region_views.end(); ++i) {
|
draw_note_lines();
|
||||||
(*i)->set_height(height); // apply note range
|
|
||||||
}
|
for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
|
||||||
|
((MidiRegionView*)(*i))->apply_note_range(lowest, highest);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_note_lines();
|
|
||||||
NoteRangeChanged();
|
NoteRangeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStreamView::update_bounds(uint8_t note_num)
|
MidiStreamView::update_note_range(uint8_t note_num)
|
||||||
{
|
{
|
||||||
_lowest_note = min(_lowest_note, note_num);
|
assert(note_num <= 127);
|
||||||
_highest_note = max(_highest_note, 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 ()
|
||||||
{
|
{
|
||||||
|
|
@ -628,7 +679,6 @@ MidiStreamView::rec_data_range_ready (jack_nframes_t start, jack_nframes_t dur,
|
||||||
void
|
void
|
||||||
MidiStreamView::color_handler ()
|
MidiStreamView::color_handler ()
|
||||||
{
|
{
|
||||||
|
|
||||||
//case cMidiTrackBase:
|
//case cMidiTrackBase:
|
||||||
if (_trackview.is_midi_track()) {
|
if (_trackview.is_midi_track()) {
|
||||||
//canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
|
//canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
|
||||||
|
|
@ -641,27 +691,30 @@ MidiStreamView::color_handler ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiStreamView::note_range_adjustment_changed() {
|
MidiStreamView::note_range_adjustment_changed()
|
||||||
|
{
|
||||||
double sum = note_range_adjustment.get_value() + note_range_adjustment.get_page_size();
|
double sum = note_range_adjustment.get_value() + note_range_adjustment.get_page_size();
|
||||||
int lowest = (int) floor(note_range_adjustment.get_value());
|
int lowest = (int) floor(note_range_adjustment.get_value());
|
||||||
int highest;
|
int highest;
|
||||||
|
|
||||||
if(sum == _range_sum_cache) {
|
if (sum == _range_sum_cache) {
|
||||||
//cerr << "cached" << endl;
|
//cerr << "cached" << endl;
|
||||||
highest = (int) floor(sum);
|
highest = (int) floor(sum);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
//cerr << "recalc" << endl;
|
//cerr << "recalc" << endl;
|
||||||
highest = lowest + (int) floor(note_range_adjustment.get_page_size());
|
highest = lowest + (int) floor(note_range_adjustment.get_page_size());
|
||||||
_range_sum_cache = sum;
|
_range_sum_cache = sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lowest == lowest_note() && highest == highest_note()) {
|
if (lowest == _lowest_note && highest == _highest_note) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cerr << "note range changed: " << lowest << " " << highest << endl;
|
//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;
|
//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;
|
||||||
|
|
||||||
set_note_range(lowest, highest);
|
_lowest_note = lowest;
|
||||||
|
_highest_note = highest;
|
||||||
|
apply_note_range(lowest, highest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,14 +69,12 @@ class MidiStreamView : public StreamView
|
||||||
Gtk::Adjustment note_range_adjustment;
|
Gtk::Adjustment note_range_adjustment;
|
||||||
ArdourCanvas::Group* midi_underlay_group;
|
ArdourCanvas::Group* midi_underlay_group;
|
||||||
|
|
||||||
VisibleNoteRange note_range() { return _range; }
|
|
||||||
void set_note_range(VisibleNoteRange r);
|
void set_note_range(VisibleNoteRange r);
|
||||||
void set_note_range(uint8_t lowest, uint8_t highest);
|
|
||||||
|
|
||||||
uint8_t lowest_note() const { return (_range == FullRange) ? 0 : _lowest_note; }
|
inline uint8_t lowest_note() const { return _lowest_note; }
|
||||||
uint8_t highest_note() const { return (_range == FullRange) ? 127 : _highest_note; }
|
inline uint8_t highest_note() const { return _highest_note; }
|
||||||
|
|
||||||
void update_bounds(uint8_t note_num);
|
void update_note_range(uint8_t note_num);
|
||||||
|
|
||||||
void redisplay_diskstream ();
|
void redisplay_diskstream ();
|
||||||
|
|
||||||
|
|
@ -85,41 +83,57 @@ class MidiStreamView : public StreamView
|
||||||
|
|
||||||
inline double note_to_y(uint8_t note) const
|
inline double note_to_y(uint8_t note) const
|
||||||
{ return contents_height()
|
{ return contents_height()
|
||||||
- (note + 1 - _lowest_note) * note_height() + 1; }
|
- (note + 1 - lowest_note()) * note_height() + 1; }
|
||||||
|
|
||||||
inline uint8_t y_to_note(double y) const
|
inline uint8_t y_to_note(double y) const
|
||||||
{ return (uint8_t)((contents_height() - y - 1)
|
{ return (uint8_t)((contents_height() - y - 1)
|
||||||
/ contents_height() * (double)contents_note_range())
|
/ contents_height() * (double)contents_note_range())
|
||||||
+ _lowest_note; }
|
+ lowest_note(); }
|
||||||
|
|
||||||
inline double note_height() const
|
inline double note_height() const
|
||||||
{ return contents_height() / (double)contents_note_range(); }
|
{ return contents_height() / (double)contents_note_range(); }
|
||||||
|
|
||||||
inline uint8_t contents_note_range() const
|
inline uint8_t contents_note_range() const
|
||||||
{ return _highest_note - _lowest_note + 1; }
|
{ return highest_note() - lowest_note() + 1; }
|
||||||
|
|
||||||
sigc::signal<void> NoteRangeChanged;
|
sigc::signal<void> NoteRangeChanged;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setup_rec_box ();
|
void setup_rec_box ();
|
||||||
void rec_data_range_ready (jack_nframes_t start, jack_nframes_t dur, boost::weak_ptr<ARDOUR::Source> src);
|
|
||||||
void update_rec_regions (boost::shared_ptr<ARDOUR::MidiModel> data, jack_nframes_t start, jack_nframes_t dur);
|
void rec_data_range_ready (
|
||||||
|
jack_nframes_t start,
|
||||||
|
jack_nframes_t dur,
|
||||||
|
boost::weak_ptr<ARDOUR::Source> src);
|
||||||
|
|
||||||
|
void update_rec_regions (
|
||||||
|
boost::shared_ptr<ARDOUR::MidiModel> data,
|
||||||
|
jack_nframes_t start,
|
||||||
|
jack_nframes_t dur);
|
||||||
|
|
||||||
RegionView* add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_waves, bool recording = false);
|
RegionView* add_region_view_internal (
|
||||||
void display_region(MidiRegionView* region_view, bool load_model);
|
boost::shared_ptr<ARDOUR::Region>,
|
||||||
void display_diskstream (boost::shared_ptr<ARDOUR::Diskstream> ds);
|
bool wait_for_waves,
|
||||||
|
bool recording = false);
|
||||||
|
|
||||||
|
void display_region(MidiRegionView* region_view, bool load_model);
|
||||||
|
void display_diskstream (boost::shared_ptr<ARDOUR::Diskstream> ds);
|
||||||
|
|
||||||
void update_contents_height ();
|
void update_contents_height ();
|
||||||
void draw_note_lines();
|
void draw_note_lines();
|
||||||
|
void apply_note_range(uint8_t lowest, uint8_t highest);
|
||||||
|
bool update_data_note_range(uint8_t min, uint8_t max);
|
||||||
|
|
||||||
void color_handler ();
|
void color_handler ();
|
||||||
|
|
||||||
void note_range_adjustment_changed();
|
void note_range_adjustment_changed();
|
||||||
|
|
||||||
VisibleNoteRange _range;
|
bool _range_dirty;
|
||||||
double _range_sum_cache;
|
double _range_sum_cache;
|
||||||
uint8_t _lowest_note;
|
uint8_t _lowest_note; ///< currently visible
|
||||||
uint8_t _highest_note;
|
uint8_t _highest_note; ///< currently visible
|
||||||
|
uint8_t _data_note_min; ///< in data
|
||||||
|
uint8_t _data_note_max; ///< in data
|
||||||
ArdourCanvas::Lineset* _note_lines;
|
ArdourCanvas::Lineset* _note_lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,9 @@ using namespace Editing;
|
||||||
|
|
||||||
|
|
||||||
MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
|
MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
|
||||||
: AxisView(sess) // FIXME: won't compile without this, why??
|
: AxisView(sess) // virtually inherited
|
||||||
, RouteTimeAxisView(ed, sess, rt, canvas)
|
, RouteTimeAxisView(ed, sess, rt, canvas)
|
||||||
|
, _ignore_signals(false)
|
||||||
, _range_scroomer(0)
|
, _range_scroomer(0)
|
||||||
, _piano_roll_header(0)
|
, _piano_roll_header(0)
|
||||||
, _note_mode(Sustained)
|
, _note_mode(Sustained)
|
||||||
|
|
@ -200,18 +201,14 @@ MidiTimeAxisView::append_extra_display_menu_items ()
|
||||||
MenuList& range_items = range_menu->items();
|
MenuList& range_items = range_menu->items();
|
||||||
range_menu->set_name ("ArdourContextMenu");
|
range_menu->set_name ("ArdourContextMenu");
|
||||||
|
|
||||||
RadioMenuItem::Group range_group;
|
range_items.push_back (MenuElem (_("Show Full Range"), bind (
|
||||||
|
|
||||||
range_items.push_back (RadioMenuElem (range_group, _("Show Full Range"), bind (
|
|
||||||
mem_fun(*this, &MidiTimeAxisView::set_note_range),
|
mem_fun(*this, &MidiTimeAxisView::set_note_range),
|
||||||
MidiStreamView::FullRange)));
|
MidiStreamView::FullRange)));
|
||||||
|
|
||||||
range_items.push_back (RadioMenuElem (range_group, _("Fit Contents"), bind (
|
range_items.push_back (MenuElem (_("Fit Contents"), bind (
|
||||||
mem_fun(*this, &MidiTimeAxisView::set_note_range),
|
mem_fun(*this, &MidiTimeAxisView::set_note_range),
|
||||||
MidiStreamView::ContentsRange)));
|
MidiStreamView::ContentsRange)));
|
||||||
|
|
||||||
((Gtk::CheckMenuItem&)range_items.back()).set_active(true);
|
|
||||||
|
|
||||||
items.push_back (MenuElem (_("Note range"), *range_menu));
|
items.push_back (MenuElem (_("Note range"), *range_menu));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,10 +270,8 @@ MidiTimeAxisView::set_note_mode(NoteMode mode)
|
||||||
void
|
void
|
||||||
MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
|
MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
|
||||||
{
|
{
|
||||||
//if (midi_view()->note_range() != range) {
|
if (!_ignore_signals)
|
||||||
midi_view()->set_note_range(range);
|
midi_view()->set_note_range(range);
|
||||||
midi_view()->redisplay_diskstream();
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
||||||
|
|
||||||
void channel_selector_toggled();
|
void channel_selector_toggled();
|
||||||
|
|
||||||
|
bool _ignore_signals;
|
||||||
Gtk::Menu _subplugin_menu;
|
Gtk::Menu _subplugin_menu;
|
||||||
|
|
||||||
MidiScroomer* _range_scroomer;
|
MidiScroomer* _range_scroomer;
|
||||||
PianoRollHeader* _piano_roll_header;
|
PianoRollHeader* _piano_roll_header;
|
||||||
ARDOUR::NoteMode _note_mode;
|
ARDOUR::NoteMode _note_mode;
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,9 @@ public:
|
||||||
void add_note_unlocked(const boost::shared_ptr<Note> note);
|
void add_note_unlocked(const boost::shared_ptr<Note> note);
|
||||||
void remove_note_unlocked(const boost::shared_ptr<const Note> note);
|
void remove_note_unlocked(const boost::shared_ptr<const Note> note);
|
||||||
|
|
||||||
|
uint8_t lowest_note() const { return _lowest_note; }
|
||||||
|
uint8_t highest_note() const { return _highest_note; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable const_iterator _read_iter;
|
mutable const_iterator _read_iter;
|
||||||
bool _edited;
|
bool _edited;
|
||||||
|
|
@ -198,6 +201,9 @@ private:
|
||||||
mutable nframes_t _next_read;
|
mutable nframes_t _next_read;
|
||||||
bool _percussive;
|
bool _percussive;
|
||||||
|
|
||||||
|
uint8_t _lowest_note;
|
||||||
|
uint8_t _highest_note;
|
||||||
|
|
||||||
typedef std::priority_queue<
|
typedef std::priority_queue<
|
||||||
boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
|
boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >,
|
||||||
LaterNoteEndComparator>
|
LaterNoteEndComparator>
|
||||||
|
|
|
||||||
|
|
@ -1043,6 +1043,10 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double end, d
|
||||||
const ControlEvent* first = NULL;
|
const ControlEvent* first = NULL;
|
||||||
const ControlEvent* next = NULL;
|
const ControlEvent* next = NULL;
|
||||||
|
|
||||||
|
/* No events past start (maybe?) */
|
||||||
|
if (next && next->when < start)
|
||||||
|
return false;
|
||||||
|
|
||||||
/* Step is after first */
|
/* Step is after first */
|
||||||
if (range.first == _events.begin() || (*range.first)->when == start) {
|
if (range.first == _events.begin() || (*range.first)->when == start) {
|
||||||
first = *range.first;
|
first = *range.first;
|
||||||
|
|
@ -1068,7 +1072,7 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double end, d
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abs(first->value - next->value) <= 1) {
|
if (fabs(first->value - next->value) <= 1) {
|
||||||
if (next->when <= end && (!inclusive || next->when > start)) {
|
if (next->when <= end && (!inclusive || next->when > start)) {
|
||||||
x = next->when;
|
x = next->when;
|
||||||
y = next->value;
|
y = next->value;
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,8 @@ Sequence::Sequence(const TypeMap& type_map, size_t size)
|
||||||
, _end_iter(*this, DBL_MAX)
|
, _end_iter(*this, DBL_MAX)
|
||||||
, _next_read(UINT32_MAX)
|
, _next_read(UINT32_MAX)
|
||||||
, _percussive(false)
|
, _percussive(false)
|
||||||
|
, _lowest_note(127)
|
||||||
|
, _highest_note(0)
|
||||||
{
|
{
|
||||||
debugout << "Sequence (size " << size << ") constructed: " << this << endl;
|
debugout << "Sequence (size " << size << ") constructed: " << this << endl;
|
||||||
assert(_end_iter._is_end);
|
assert(_end_iter._is_end);
|
||||||
|
|
@ -568,6 +570,11 @@ Sequence::append_note_on_unlocked(uint8_t chan, EventTime time, uint8_t note_num
|
||||||
assert(_writing);
|
assert(_writing);
|
||||||
_edited = true;
|
_edited = true;
|
||||||
|
|
||||||
|
if (note_num < _lowest_note)
|
||||||
|
_lowest_note = note_num;
|
||||||
|
if (note_num > _highest_note)
|
||||||
|
_highest_note = note_num;
|
||||||
|
|
||||||
boost::shared_ptr<Note> new_note(new Note(chan, time, 0, note_num, velocity));
|
boost::shared_ptr<Note> new_note(new Note(chan, time, 0, note_num, velocity));
|
||||||
_notes.push_back(new_note);
|
_notes.push_back(new_note);
|
||||||
if (!_percussive) {
|
if (!_percussive) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue