ardour
export_multiplication.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008-2012 Paul Davis
3  Author: Sakari Bergen
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 /* This file is not used at the moment. It includes code related to export a
22  * multiplication graph system that can be used together with the ExportMultiplicator
23  * class in the gtk2_ardour folder.
24  * - Sakari Bergen 6.8.2008 -
25  */
26 
27 void
28 ExportProfileManager::register_all_configs ()
29 {
30  list<TimespanNodePtr>::iterator tsl_it; // timespan list node iterator
31  for (tsl_it = graph.timespans.begin(); tsl_it != graph.timespans.end(); ++tsl_it) {
32  list<GraphNode *>::const_iterator cc_it; // channel config node iterator
33  for (cc_it = (*tsl_it)->get_children().begin(); cc_it != (*tsl_it)->get_children().end(); ++cc_it) {
34  list<GraphNode *>::const_iterator f_it; // format node iterator
35  for (f_it = (*cc_it)->get_children().begin(); f_it != (*cc_it)->get_children().end(); ++f_it) {
36  list<GraphNode *>::const_iterator fn_it; // filename node iterator
37  for (fn_it = (*f_it)->get_children().begin(); fn_it != (*f_it)->get_children().end(); ++fn_it) {
38  /* Finally loop through each timespan in the timespan list */
39 
40  TimespanNodePtr ts_node;
41  if (!(ts_node = boost::dynamic_pointer_cast<TimespanNode> (*tsl_it))) {
42  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
43  }
44 
45  TimespanListPtr ts_list = ts_node->data()->timespans;
46  TimespanList::iterator ts_it;
47  for (ts_it = ts_list->begin(); ts_it != ts_list->end(); ++ts_it) {
48 
49  TimespanPtr timespan = *ts_it;
50 
51  ChannelConfigNode * cc_node;
52  if (!(cc_node = dynamic_cast<ChannelConfigNode *> (*cc_it))) {
53  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
54  }
55  ChannelConfigPtr channel_config = cc_node->data()->config;
56 
57  FormatNode * f_node;
58  if (!(f_node = dynamic_cast<FormatNode *> (*f_it))) {
59  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
60  }
61  FormatPtr format = f_node->data()->format;
62 
63  FilenameNode * fn_node;
64  if (!(fn_node = dynamic_cast<FilenameNode *> (*fn_it))) {
65  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
66  }
67  FilenamePtr filename = fn_node->data()->filename;
68 
69  handler->add_export_config (timespan, channel_config, format, filename);
70  }
71  }
72  }
73  }
74  }
75 }
76 
77 void
78 ExportProfileManager::create_empty_config ()
79 {
80  TimespanNodePtr timespan = TimespanNode::create (new TimespanState ());
81  timespan->data()->timespans->push_back (handler->add_timespan());
82 
83  ChannelConfigNodePtr channel_config = ChannelConfigNode::create (new ChannelConfigState(handler->add_channel_config()));
84 
85  FormatNodePtr format;
86  load_formats ();
87  if (!format_list.empty()) {
88  format = FormatNode::create (new FormatState (*format_list.begin ()));
89  } else {
90  format = FormatNode::create (new FormatState (handler->add_format ()));
91  }
92 
93  FilenameNodePtr filename = FilenameNode::create (new FilenameState (handler->add_filename()));
94 
95  /* Bring everything together */
96 
97  timespan->add_child (channel_config.get(), 0);
98  channel_config->add_child (format.get(), 0);
99  format->add_child (filename.get(), 0);
100 
101  graph.timespans.push_back (timespan);
102  graph.channel_configs.push_back (channel_config);
103  graph.formats.push_back (format);
104  graph.filenames.push_back (filename);
105 }
106 
107 /*** GraphNode ***/
108 
109 uint32_t ExportProfileManager::GraphNode::id_counter = 0;
110 
111 ExportProfileManager::GraphNode::GraphNode ()
112 {
113  _id = ++id_counter;
114 }
115 
116 ExportProfileManager::GraphNode::~GraphNode ()
117 {
118  while (!children.empty()) {
119  remove_child (children.front());
120  }
121 
122  while (!parents.empty()) {
123  parents.front()->remove_child (this);
124  }
125 }
126 
127 void
128 ExportProfileManager::GraphNode::add_parent (GraphNode * parent)
129 {
130  for (list<GraphNode *>::iterator it = parents.begin(); it != parents.end(); ++it) {
131  if (*it == parent) {
132  return;
133  }
134  }
135 
136  parents.push_back (parent);
137 }
138 
139 void
140 ExportProfileManager::GraphNode::add_child (GraphNode * child, GraphNode * left_sibling)
141 {
142  for (list<GraphNode *>::iterator it = children.begin(); it != children.end(); ++it) {
143  if (*it == child) {
144  return;
145  }
146  }
147 
148  if (left_sibling) {
149  insert_after (children, left_sibling, child);
150  } else {
151  children.push_back (child);
152  }
153 
154  child->add_parent (this);
155 }
156 
157 bool
158 ExportProfileManager::GraphNode::is_ancestor_of (GraphNode const * node) const
159 {
160  for (list<GraphNode *>::const_iterator it = children.begin(); it != children.end(); ++it) {
161  if (*it == node || (*it)->is_ancestor_of (node)) {
162  return true;
163  }
164  }
165 
166  return false;
167 }
168 
169 bool
170 ExportProfileManager::GraphNode::is_descendant_of (GraphNode const * node) const
171 {
172  for (list<GraphNode *>::const_iterator it = parents.begin(); it != parents.end(); ++it) {
173  if (*it == node || (*it)->is_descendant_of (node)) {
174  return true;
175  }
176  }
177 
178  return false;
179 }
180 
181 void
183 {
184  if (_selected == value) { return; }
185 
186  _selected = value;
187  SelectChanged (value);
188 }
189 
190 void
191 ExportProfileManager::GraphNode::remove_parent (GraphNode * parent)
192 {
193  for (list<GraphNode *>::iterator it = parents.begin(); it != parents.end(); ++it) {
194  if (*it == parent) {
195  parents.erase (it);
196  break;
197  }
198  }
199 }
200 
201 void
202 ExportProfileManager::GraphNode::remove_child (GraphNode * child)
203 {
204  for (list<GraphNode *>::iterator it = children.begin(); it != children.end(); ++it) {
205  if (*it == child) {
206  children.erase (it);
207  break;
208  }
209  }
210 
211  child->remove_parent (this);
212 }
213 
214 void
216 {
217  TimespanNode * ts_node;
218  if ((ts_node = dynamic_cast<TimespanNode *> (node))) {
219  split_timespan (ts_node->self_ptr(), position);
220  return;
221  }
222 
223  ChannelConfigNode * cc_node;
224  if ((cc_node = dynamic_cast<ChannelConfigNode *> (node))) {
225  split_channel_config (cc_node->self_ptr(), position);
226  return;
227  }
228 
229  FormatNode * f_node;
230  if ((f_node = dynamic_cast<FormatNode *> (node))) {
231  split_format (f_node->self_ptr(), position);
232  return;
233  }
234 
235  FilenameNode * fn_node;
236  if ((fn_node = dynamic_cast<FilenameNode *> (node))) {
237  split_filename (fn_node->self_ptr(), position);
238  return;
239  }
240 }
241 
242 void
244 {
245  TimespanNode * ts_node;
246  if ((ts_node = dynamic_cast<TimespanNode *> (node))) {
247  remove_timespan (ts_node->self_ptr());
248  return;
249  }
250 
251  ChannelConfigNode * cc_node;
252  if ((cc_node = dynamic_cast<ChannelConfigNode *> (node))) {
253  remove_channel_config (cc_node->self_ptr());
254  return;
255  }
256 
257  FormatNode * f_node;
258  if ((f_node = dynamic_cast<FormatNode *> (node))) {
259  remove_format (f_node->self_ptr());
260  return;
261  }
262 
263  FilenameNode * fn_node;
264  if ((fn_node = dynamic_cast<FilenameNode *> (node))) {
265  remove_filename (fn_node->self_ptr());
266  return;
267  }
268 }
269 
270 void
272 {
273  for (list<TimespanNodePtr>::iterator it = graph.timespans.begin(); it != graph.timespans.end(); ) {
274  list<TimespanNodePtr>::iterator tmp = it;
275  ++it;
276 
277  if ((*tmp)->get_children().empty()) {
278  graph.timespans.erase (tmp);
279  }
280  }
281 
282  for (list<ChannelConfigNodePtr>::iterator it = graph.channel_configs.begin(); it != graph.channel_configs.end(); ) {
283  list<ChannelConfigNodePtr>::iterator tmp = it;
284  ++it;
285 
286  if ((*tmp)->get_parents().empty()) {
287  graph.channel_configs.erase (tmp);
288  }
289  }
290 
291  for (list<FormatNodePtr>::iterator it = graph.formats.begin(); it != graph.formats.end(); ) {
292  list<FormatNodePtr>::iterator tmp = it;
293  ++it;
294 
295  if ((*tmp)->get_parents().empty()) {
296  graph.formats.erase (tmp);
297  }
298  }
299 
300  for (list<FilenameNodePtr>::iterator it = graph.filenames.begin(); it != graph.filenames.end(); ) {
301  list<FilenameNodePtr>::iterator tmp = it;
302  ++it;
303 
304  if ((*tmp)->get_parents().empty()) {
305  graph.filenames.erase (tmp);
306  }
307  }
308 
309  GraphChanged();
310 }
311 
312 template<typename T>
313 void
314 ExportProfileManager::insert_after (list<T> & the_list, T const & position, T const & element)
315 {
316  typename list<T>::iterator it;
317  for (it = the_list.begin(); it != the_list.end(); ++it) {
318  if (*it == position) {
319  the_list.insert (++it, element);
320  return;
321  }
322  }
323 
324  std::cerr << "invalid position given to ExportProfileManager::insert_after (aborting)" << std::endl;
325 
326  abort();
327 }
328 
329 template<typename T>
330 void
331 ExportProfileManager::remove_by_element (list<T> & the_list, T const & element)
332 {
333  typename list<T>::iterator it;
334  for (it = the_list.begin(); it != the_list.end(); ++it) {
335  if (*it == element) {
336  the_list.erase (it);
337  return;
338  }
339  }
340 }
341 
342 bool
343 ExportProfileManager::nodes_have_one_common_child (list<GraphNode *> const & the_list)
344 {
345  return end_of_common_child_range (the_list, the_list.begin()) == --the_list.end();
346 }
347 
348 list<ExportProfileManager::GraphNode *>::const_iterator
349 ExportProfileManager::end_of_common_child_range (list<GraphNode *> const & the_list, list<GraphNode *>::const_iterator beginning)
350 {
351  if ((*beginning)->get_children().size() != 1) { return beginning; }
352  GraphNode * child = (*beginning)->get_children().front();
353 
354  list<GraphNode *>::const_iterator it = beginning;
355  while (it != the_list.end() && (*it)->get_children().size() == 1 && (*it)->get_children().front() == child) {
356  ++it;
357  }
358 
359  return --it;
360 }
361 
362 void
363 ExportProfileManager::split_node_at_position (GraphNode * old_node, GraphNode * new_node, float position)
364 {
365  list<GraphNode *> const & node_parents = old_node->get_parents();
366  uint32_t split_index = (int) (node_parents.size() * position + 0.5);
367  split_index = std::max ((uint32_t) 1, std::min (split_index, node_parents.size() - 1));
368 
369  list<GraphNode *>::const_iterator it = node_parents.begin();
370  for (uint32_t index = 1; it != node_parents.end(); ++index) {
371  if (index > split_index) {
372  list<GraphNode *>::const_iterator tmp = it++;
373  (*tmp)->add_child (new_node, old_node);
374  (*tmp)->remove_child (old_node);
375  } else {
376  ++it;
377  }
378  }
379 }
380 
381 void
383 {
384  TimespanNodePtr new_timespan = duplicate_timespan_node (node);
385  insert_after (graph.timespans, node, new_timespan);
386 
387  /* Note: Since a timespan selector allows all combinations of ranges
388  * there is no reason for a channel configuration to have two parents
389  */
390 
391  duplicate_timespan_children (node->self_ptr(), new_timespan);
392 
393  GraphChanged();
394 }
395 
396 void
398 {
400  insert_after (graph.channel_configs, node, new_config);
401 
402  /* Channel configs have only one parent, see above! */
403  node->get_parents().front()->add_child (new_config.get(), node.get());
404 
405  if (node->get_children().size() == 1) {
406  new_config->add_child (node->first_child(), 0);
407  } else {
408  duplicate_channel_config_children (node, new_config);
409  }
410 
411  GraphChanged();
412 }
413 
414 void
416 {
417  FormatNodePtr new_format = duplicate_format_node (node);
418  insert_after (graph.formats, node, new_format);
419 
420  list<GraphNode *> const & node_parents = node->get_parents();
421  if (node_parents.size() == 1) {
422  node_parents.front()->add_child (new_format.get(), 0);
423  } else {
424  node->sort_parents (graph.channel_configs);
425  split_node_at_position (node.get(), new_format.get(), position);
426  }
427 
428  if (node->get_children().size() == 1) {
429  new_format->add_child (node->first_child(), 0);
430  } else {
431  duplicate_format_children (node, new_format);
432  }
433 
434  GraphChanged();
435 }
436 
437 void
439 {
440  FilenameNodePtr new_filename = duplicate_filename_node (node);
441  insert_after (graph.filenames, node, new_filename);
442 
443  list<GraphNode *> const & node_parents = node->get_parents();
444 
445  if (node_parents.size() == 1) {
446  node_parents.front()->add_child (new_filename.get(), 0);
447  } else {
448  node->sort_parents (graph.formats);
449  split_node_at_position (node.get(), new_filename.get(), position);
450  }
451 
452  GraphChanged();
453 }
454 
455 void
457 {
458  list<GraphNode *> const & source_children = source->get_children();
459  bool one_grandchild = nodes_have_one_common_child (source_children);
460  GraphNode * child_insertion_point = 0;
461 
462  ChannelConfigNodePtr node_insertion_point;
463  ChannelConfigNode * node_insertion_ptr;
464  if (!insertion_point) { insertion_point = source->last_child(); }
465  if (!(node_insertion_ptr = dynamic_cast<ChannelConfigNode *> (insertion_point))) {
466  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
467  }
468  node_insertion_point = node_insertion_ptr->self_ptr();
469 
470  /* Keep track of common children */
471 
472  list<GraphNode *>::const_iterator common_children_begin = source_children.begin();
473  list<GraphNode *>::const_iterator common_children_end = end_of_common_child_range (source_children, source_children.begin());
474  GraphNode * common_child = 0;
475 
476  for (list<GraphNode *>::const_iterator it = source_children.begin(); it != source_children.end(); ++it) {
477  /* Duplicate node */
478 
479  ChannelConfigNode * node;
480  ChannelConfigNodePtr new_node;
481 
482  if (!(node = dynamic_cast<ChannelConfigNode *> (*it))) {
483  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
484  }
485 
486  new_node = duplicate_channel_config_node (node->self_ptr());
487 
488  /* Insert in gaph's list and update insertion position */
489 
490  insert_after (graph.channel_configs, node_insertion_point, new_node);
491  node_insertion_point = new_node;
492 
493  /* Handle children */
494 
495  target->add_child (new_node.get(), child_insertion_point);
496  child_insertion_point = new_node.get();
497 
498  if (one_grandchild) {
499  new_node->add_child (node->first_child(), 0);
500  } else {
501  list<GraphNode *>::const_iterator past_end = common_children_end;
502  if (it == ++past_end) { // At end => start new range
503  common_children_begin = it;
504  common_children_end = end_of_common_child_range (source_children, it);
505  }
506 
507  if (it == common_children_begin) { // At beginning => do duplication
508  GraphNode * grand_child_ins_pt = common_child;
509  if (!grand_child_ins_pt) {
510  grand_child_ins_pt = source->last_child()->last_child();
511  }
512  duplicate_channel_config_children (node->self_ptr(), new_node, grand_child_ins_pt);
513  common_child = new_node->first_child();
514  } else { // Somewhere in between end and beginning => share child
515  new_node->add_child (common_child, 0);
516  }
517  }
518  }
519 }
520 
521 void
523 {
524  list<GraphNode *> const & source_children = source->get_children();
525  bool one_grandchild = nodes_have_one_common_child (source_children);
526  GraphNode * child_insertion_point = 0;
527 
528  FormatNodePtr node_insertion_point;
529  FormatNode * node_insertion_ptr;
530  if (!insertion_point) { insertion_point = source->last_child(); }
531  if (!(node_insertion_ptr = dynamic_cast<FormatNode *> (insertion_point))) {
532  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
533  }
534  node_insertion_point = node_insertion_ptr->self_ptr();
535 
536  /* Keep track of common children */
537 
538  list<GraphNode *>::const_iterator common_children_begin = source_children.begin();
539  list<GraphNode *>::const_iterator common_children_end = end_of_common_child_range (source_children, source_children.begin());
540  GraphNode * common_child = 0;
541 
542  for (list<GraphNode *>::const_iterator it = source_children.begin(); it != source_children.end(); ++it) {
543  /* Duplicate node */
544 
545  FormatNode * node;
546  FormatNodePtr new_node;
547 
548  if (!(node = dynamic_cast<FormatNode *> (*it))) {
549  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
550  }
551 
552  new_node = duplicate_format_node (node->self_ptr());
553 
554  /* Insert in gaph's list and update insertion position */
555 
556  insert_after (graph.formats, node_insertion_point, new_node);
557  node_insertion_point = new_node;
558 
559  /* Handle children */
560 
561  target->add_child (new_node.get(), child_insertion_point);
562  child_insertion_point = new_node.get();
563 
564  if (one_grandchild) {
565  new_node->add_child (node->first_child(), 0);
566  } else {
567  list<GraphNode *>::const_iterator past_end = common_children_end;
568  if (it == ++past_end) { // At end => start new range
569  common_children_begin = it;
570  common_children_end = end_of_common_child_range (source_children, it);
571  }
572 
573  if (it == common_children_begin) { // At beginning => do duplication
574  GraphNode * grand_child_ins_pt = common_child;
575  if (!grand_child_ins_pt) {
576  grand_child_ins_pt = source->get_parents().back()->last_child()->last_child()->last_child();
577  }
578  duplicate_format_children (node->self_ptr(), new_node, grand_child_ins_pt);
579  common_child = new_node->first_child();
580  } else { // Somewhere in between end and beginning => share child
581  new_node->add_child (common_child, 0);
582  }
583  }
584  }
585 }
586 
587 void
589 {
590  GraphNode * child_insertion_point = 0;
591 
592  FilenameNodePtr node_insertion_point;
593  FilenameNode * node_insertion_ptr;
594  if (!insertion_point) { insertion_point = source->last_child(); }
595  if (!(node_insertion_ptr = dynamic_cast<FilenameNode *> (insertion_point))) {
596  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
597  }
598  node_insertion_point = node_insertion_ptr->self_ptr();
599 
600  for (list<GraphNode *>::const_iterator it = source->get_children().begin(); it != source->get_children().end(); ++it) {
601  /* Duplicate node */
602 
603  FilenameNode * node;
604  FilenameNodePtr new_node;
605 
606  if (!(node = dynamic_cast<FilenameNode *> (*it))) {
607  throw ExportFailed (X_("Programming error, Invalid pointer cast in ExportProfileManager"));
608  }
609 
610  new_node = duplicate_filename_node (node->self_ptr());
611 
612  /* Insert in gaph's list and update insertion position */
613 
614  insert_after (graph.filenames, node_insertion_point, new_node);
615  node_insertion_point = new_node;
616 
617  /* Handle children */
618 
619  target->add_child (new_node.get(), child_insertion_point);
620  child_insertion_point = new_node.get();
621  }
622 }
623 
626 {
627  TimespanStatePtr state = node->data();
628  TimespanStatePtr new_state (new TimespanState ());
629  TimespanNodePtr new_node = TimespanNode::create (new_state);
630 
631  for (TimespanList::iterator it = state->timespans->begin(); it != state->timespans->end(); ++it) {
632  new_state->timespans->push_back (handler->add_timespan_copy (*it));
633  }
634 
635  new_state->time_format = state->time_format;
636  new_state->marker_format = state->marker_format;
637 
638  return new_node;
639 }
640 
643 {
644  ChannelConfigStatePtr state = node->data();
645  ChannelConfigStatePtr new_state (new ChannelConfigState (handler->add_channel_config_copy (state->config)));
646  ChannelConfigNodePtr new_node = ChannelConfigNode::create (new_state);
647 
648  return new_node;
649 }
650 
653 {
654  FormatStatePtr state = node->data();
655  FormatStatePtr new_state (new FormatState (handler->add_format_copy (state->format)));
656  FormatNodePtr new_node = FormatNode::create (new_state);
657 
658  return new_node;
659 }
660 
663 {
664  FilenameStatePtr state = node->data();
665  FilenameStatePtr new_state (new FilenameState (handler->add_filename_copy (state->filename)));
666  FilenameNodePtr new_node = FilenameNode::create (new_state);
667 
668  return new_node;
669 }
670 
671 void
673 {
675  purge_graph ();
676 }
677 
678 void
680 {
682  purge_graph ();
683 }
684 
685 void
687 {
689  purge_graph ();
690 }
691 
692 void
694 {
696  purge_graph ();
697 }
SelfPtr self_ptr()
boost::shared_ptr< FormatNode > FormatNodePtr
A graph node that contains data.
boost::shared_ptr< TimespanNode > TimespanNodePtr
boost::shared_ptr< FilenameNode > FilenameNodePtr
void remove_filename(FilenameNodePtr node)
GraphNode * first_child() const
void split_timespan(TimespanNodePtr node, float position=0.5)
void remove_parent(GraphNode *parent)
void add_parent(GraphNode *parent)
list< FormatNodePtr > formats
boost::shared_ptr< ChannelConfigNode > ChannelConfigNodePtr
void purge_graph()
static void remove_by_element(list< T > &the_list, T const &element)
bool nodes_have_one_common_child(list< GraphNode * > const &the_list)
list< ChannelConfigNodePtr > channel_configs
FormatNodePtr duplicate_format_node(FormatNodePtr node)
list< GraphNode * > const & get_parents() const
list< TimespanNodePtr > timespans
list< GraphNode * >::const_iterator end_of_common_child_range(list< GraphNode * > const &the_list, list< GraphNode * >::const_iterator beginning)
#define X_(Text)
Definition: i18n.h:13
list< GraphNode * > const & get_children() const
void remove_node(GraphNode *node)
void split_format(FormatNodePtr node, float position=0.5)
bool is_ancestor_of(GraphNode const *node) const
static void insert_after(list< T > &the_list, T const &position, T const &element)
void split_channel_config(ChannelConfigNodePtr node, float position=0.5)
void remove_timespan(TimespanNodePtr node)
FilenameNodePtr duplicate_filename_node(FilenameNodePtr node)
void duplicate_timespan_children(TimespanNodePtr source, TimespanNodePtr target, GraphNode *insertion_point=0)
list< FilenameNodePtr > filenames
T * get() const
Definition: shared_ptr.hpp:268
MultiplicationGraph graph
void duplicate_format_children(FormatNodePtr source, FormatNodePtr target, GraphNode *insertion_point=0)
void remove_format(FormatNodePtr node)
void duplicate_channel_config_children(ChannelConfigNodePtr source, ChannelConfigNodePtr target, GraphNode *insertion_point=0)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
LIBARDOUR_API PBD::PropertyDescriptor< bool > select
Definition: route_group.cc:48
bool is_descendant_of(GraphNode const *node) const
static SelfPtr create(T *data)
void split_filename(FilenameNodePtr node, float position=0.5)
ChannelConfigNodePtr duplicate_channel_config_node(ChannelConfigNodePtr node)
PBD::Signal0< void > GraphChanged
A node in the hierarchical graph that represents a multiplicatable export item.
void split_node(GraphNode *node, float position)
void remove_channel_config(ChannelConfigNodePtr node)
void split_node_at_position(GraphNode *old_node, GraphNode *new_node, float position)
TimespanNodePtr duplicate_timespan_node(TimespanNodePtr node)