ardour/gtk2_ardour/ghostregion.h

155 lines
4.2 KiB
C
Raw Normal View History

/*
* Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
* Copyright (C) 2006-2015 Tim Mayberry <mojofunk@gmail.com>
* Copyright (C) 2008-2014 David Robillard <d@drobilla.net>
* Copyright (C) 2009-2011 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
* Copyright (C) 2016-2017 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.
*/
#ifndef __ardour_gtk_ghost_region_h__
#define __ardour_gtk_ghost_region_h__
#include <vector>
#include <boost/unordered_map.hpp>
2023-01-08 11:52:20 -05:00
#include "pbd/signals.h"
2023-01-08 11:52:20 -05:00
#include "gtkmm2ext/colors.h"
namespace ArdourWaveView {
class WaveView;
}
2023-01-08 11:52:20 -05:00
namespace ArdourCanvas {
class Container;
class Rectangle;
class Item;
class Polygon;
}
class NoteBase;
class Note;
class Hit;
class MidiStreamView;
class TimeAxisView;
Remove GhostRegion::CatchDeletion signal to reduce session close times Currently when a GhostRegion is deleted by its "parent" RegionView it emits the static GhostRegion::CatchDeletion signal which is connected to the RegionView::remove_ghost method of every RegionView instance. With a static GhostRegion::CatchDeletion signal a particular test session causes 31 Million calls of RegionView::remove_ghost on Session deletion and the session takes 70 seconds to close with a debug build. The lifetime of a ghost region is tied to both the TimeAxisView(TAV) and RegionView(RV) in that when a RegionView is deleted all GhostRegion instances associated with the RegionView should be deleted or when a TimeAxisView is deleted all ghost regions that are contained in the view should be deleted. This means that there needs to be notification between GhostRegion and both classes. Instead of using a signal for this as we know there are only two listeners and GhostRegion already holds a reference to the TimeAxisView, also take a reference to the parent RegionView in the GhostRegion constructor and use it to notify the RegionView when GhostRegion destructor is called so it can drop any references it holds. Using a direct function call in the GhostRegion destructor to notify the TimeAxisView and RegionView "parents" brings the unload/close time down for the test session from 70 seconds to 4.5 seconds. The GhostRegion also references canvas items that are added to the TimeAxisView canvas group or at least a canvas group that it manages. So when the TimeAxisView is destroyed and the canvas group that is the parent of those items is destroyed, the GhostRegion's canvas items will also be deleted/destroyed by the parent canvas item/group. This means the GhostRegions must be destroyed when the TimeAxisView they are contained in is destroyed or there will be dangling references to canvas items that have already been deleted and trying to delete them again will be bad.
2015-10-22 07:56:02 -04:00
class RegionView;
class MidiRegionView;
class GhostRegion : virtual public sigc::trackable
{
public:
Remove GhostRegion::CatchDeletion signal to reduce session close times Currently when a GhostRegion is deleted by its "parent" RegionView it emits the static GhostRegion::CatchDeletion signal which is connected to the RegionView::remove_ghost method of every RegionView instance. With a static GhostRegion::CatchDeletion signal a particular test session causes 31 Million calls of RegionView::remove_ghost on Session deletion and the session takes 70 seconds to close with a debug build. The lifetime of a ghost region is tied to both the TimeAxisView(TAV) and RegionView(RV) in that when a RegionView is deleted all GhostRegion instances associated with the RegionView should be deleted or when a TimeAxisView is deleted all ghost regions that are contained in the view should be deleted. This means that there needs to be notification between GhostRegion and both classes. Instead of using a signal for this as we know there are only two listeners and GhostRegion already holds a reference to the TimeAxisView, also take a reference to the parent RegionView in the GhostRegion constructor and use it to notify the RegionView when GhostRegion destructor is called so it can drop any references it holds. Using a direct function call in the GhostRegion destructor to notify the TimeAxisView and RegionView "parents" brings the unload/close time down for the test session from 70 seconds to 4.5 seconds. The GhostRegion also references canvas items that are added to the TimeAxisView canvas group or at least a canvas group that it manages. So when the TimeAxisView is destroyed and the canvas group that is the parent of those items is destroyed, the GhostRegion's canvas items will also be deleted/destroyed by the parent canvas item/group. This means the GhostRegions must be destroyed when the TimeAxisView they are contained in is destroyed or there will be dangling references to canvas items that have already been deleted and trying to delete them again will be bad.
2015-10-22 07:56:02 -04:00
GhostRegion(RegionView& rv,
ArdourCanvas::Container* parent,
TimeAxisView& tv,
TimeAxisView& source_tv,
double initial_unit_pos);
virtual ~GhostRegion();
virtual void set_samples_per_pixel (double) = 0;
virtual void set_height();
virtual void set_colors();
void set_duration(double units);
virtual void set_selected (bool) {}
guint source_track_color(unsigned char alpha = 0xff);
bool is_automation_ghost();
Remove GhostRegion::CatchDeletion signal to reduce session close times Currently when a GhostRegion is deleted by its "parent" RegionView it emits the static GhostRegion::CatchDeletion signal which is connected to the RegionView::remove_ghost method of every RegionView instance. With a static GhostRegion::CatchDeletion signal a particular test session causes 31 Million calls of RegionView::remove_ghost on Session deletion and the session takes 70 seconds to close with a debug build. The lifetime of a ghost region is tied to both the TimeAxisView(TAV) and RegionView(RV) in that when a RegionView is deleted all GhostRegion instances associated with the RegionView should be deleted or when a TimeAxisView is deleted all ghost regions that are contained in the view should be deleted. This means that there needs to be notification between GhostRegion and both classes. Instead of using a signal for this as we know there are only two listeners and GhostRegion already holds a reference to the TimeAxisView, also take a reference to the parent RegionView in the GhostRegion constructor and use it to notify the RegionView when GhostRegion destructor is called so it can drop any references it holds. Using a direct function call in the GhostRegion destructor to notify the TimeAxisView and RegionView "parents" brings the unload/close time down for the test session from 70 seconds to 4.5 seconds. The GhostRegion also references canvas items that are added to the TimeAxisView canvas group or at least a canvas group that it manages. So when the TimeAxisView is destroyed and the canvas group that is the parent of those items is destroyed, the GhostRegion's canvas items will also be deleted/destroyed by the parent canvas item/group. This means the GhostRegions must be destroyed when the TimeAxisView they are contained in is destroyed or there will be dangling references to canvas items that have already been deleted and trying to delete them again will be bad.
2015-10-22 07:56:02 -04:00
RegionView& parent_rv;
/** TimeAxisView that is the AutomationTimeAxisView that we are on */
TimeAxisView& trackview;
/** TimeAxisView that we are a ghost for */
TimeAxisView& source_trackview;
ArdourCanvas::Container* group;
ArdourCanvas::Rectangle* base_rect;
};
class AudioGhostRegion : public GhostRegion {
public:
Remove GhostRegion::CatchDeletion signal to reduce session close times Currently when a GhostRegion is deleted by its "parent" RegionView it emits the static GhostRegion::CatchDeletion signal which is connected to the RegionView::remove_ghost method of every RegionView instance. With a static GhostRegion::CatchDeletion signal a particular test session causes 31 Million calls of RegionView::remove_ghost on Session deletion and the session takes 70 seconds to close with a debug build. The lifetime of a ghost region is tied to both the TimeAxisView(TAV) and RegionView(RV) in that when a RegionView is deleted all GhostRegion instances associated with the RegionView should be deleted or when a TimeAxisView is deleted all ghost regions that are contained in the view should be deleted. This means that there needs to be notification between GhostRegion and both classes. Instead of using a signal for this as we know there are only two listeners and GhostRegion already holds a reference to the TimeAxisView, also take a reference to the parent RegionView in the GhostRegion constructor and use it to notify the RegionView when GhostRegion destructor is called so it can drop any references it holds. Using a direct function call in the GhostRegion destructor to notify the TimeAxisView and RegionView "parents" brings the unload/close time down for the test session from 70 seconds to 4.5 seconds. The GhostRegion also references canvas items that are added to the TimeAxisView canvas group or at least a canvas group that it manages. So when the TimeAxisView is destroyed and the canvas group that is the parent of those items is destroyed, the GhostRegion's canvas items will also be deleted/destroyed by the parent canvas item/group. This means the GhostRegions must be destroyed when the TimeAxisView they are contained in is destroyed or there will be dangling references to canvas items that have already been deleted and trying to delete them again will be bad.
2015-10-22 07:56:02 -04:00
AudioGhostRegion(RegionView& rv,
TimeAxisView& tv,
TimeAxisView& source_tv,
double initial_unit_pos);
void set_samples_per_pixel (double);
void set_height();
void set_colors();
std::vector<ArdourWaveView::WaveView*> waves;
};
class MidiGhostRegion : public GhostRegion {
public:
class GhostEvent : public sigc::trackable
{
public:
2023-01-10 23:41:47 -05:00
GhostEvent (::NoteBase *, ArdourCanvas::Container *);
GhostEvent (::NoteBase *, ArdourCanvas::Container *, ArdourCanvas::Item* i);
virtual ~GhostEvent ();
NoteBase* event;
ArdourCanvas::Item* item;
bool is_hit;
int velocity_while_editing;
};
MidiGhostRegion(MidiRegionView& rv,
Remove GhostRegion::CatchDeletion signal to reduce session close times Currently when a GhostRegion is deleted by its "parent" RegionView it emits the static GhostRegion::CatchDeletion signal which is connected to the RegionView::remove_ghost method of every RegionView instance. With a static GhostRegion::CatchDeletion signal a particular test session causes 31 Million calls of RegionView::remove_ghost on Session deletion and the session takes 70 seconds to close with a debug build. The lifetime of a ghost region is tied to both the TimeAxisView(TAV) and RegionView(RV) in that when a RegionView is deleted all GhostRegion instances associated with the RegionView should be deleted or when a TimeAxisView is deleted all ghost regions that are contained in the view should be deleted. This means that there needs to be notification between GhostRegion and both classes. Instead of using a signal for this as we know there are only two listeners and GhostRegion already holds a reference to the TimeAxisView, also take a reference to the parent RegionView in the GhostRegion constructor and use it to notify the RegionView when GhostRegion destructor is called so it can drop any references it holds. Using a direct function call in the GhostRegion destructor to notify the TimeAxisView and RegionView "parents" brings the unload/close time down for the test session from 70 seconds to 4.5 seconds. The GhostRegion also references canvas items that are added to the TimeAxisView canvas group or at least a canvas group that it manages. So when the TimeAxisView is destroyed and the canvas group that is the parent of those items is destroyed, the GhostRegion's canvas items will also be deleted/destroyed by the parent canvas item/group. This means the GhostRegions must be destroyed when the TimeAxisView they are contained in is destroyed or there will be dangling references to canvas items that have already been deleted and trying to delete them again will be bad.
2015-10-22 07:56:02 -04:00
TimeAxisView& tv,
TimeAxisView& source_tv,
double initial_unit_pos);
~MidiGhostRegion();
MidiStreamView* midi_view();
void set_height();
void set_samples_per_pixel (double spu);
void set_colors();
2023-01-10 23:41:47 -05:00
virtual void update_contents_height();
2023-01-08 11:52:20 -05:00
virtual void add_note(NoteBase*);
virtual void update_note (GhostEvent* note);
virtual void update_hit (GhostEvent* hit);
virtual void remove_note (NoteBase*);
virtual void note_selected (NoteBase*) {}
void model_changed();
void view_changed();
void clear_events();
2023-01-10 23:41:47 -05:00
protected:
ArdourCanvas::Container* _note_group;
Gtkmm2ext::Color _outline;
ArdourCanvas::Rectangle* _tmp_rect;
ArdourCanvas::Polygon* _tmp_poly;
MidiRegionView& parent_mrv;
2023-06-20 15:46:24 -04:00
/* must match typedef in NoteBase */
typedef Evoral::Note<Temporal::Beats> NoteType;
MidiGhostRegion::GhostEvent* find_event (std::shared_ptr<NoteType>);
typedef boost::unordered_map<std::shared_ptr<NoteType>, MidiGhostRegion::GhostEvent* > EventList;
EventList events;
EventList::iterator _optimization_iterator;
};
#endif /* __ardour_gtk_ghost_region_h__ */