From 0569107ddc0d2a8df6ca0a2c8cc16ebe8f3dee99 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 13 May 2009 21:34:09 +0000 Subject: more work on the new all-Processor-all-The-Time redesign of Route - LOTS OF BREAKAGE STILL EXPECTED ; change all(?) methods that pass a start/end frame in to use sframes_t not nframes_t git-svn-id: svn://localhost/ardour2/branches/3.0@5074 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/audio_region_view.h | 1 + gtk2_ardour/audio_streamview.cc | 39 +-- gtk2_ardour/canvas-waveview.c | 1 + gtk2_ardour/editor_ops.cc | 183 ++++++----- gtk2_ardour/port_matrix_grid.cc | 8 + gtk2_ardour/processor_box.cc | 54 +++- gtk2_ardour/processor_box.h | 1 + gtk2_ardour/streamview.cc | 24 +- gtk2_ardour/streamview.h | 5 +- libs/ardour/amp.cc | 14 +- libs/ardour/ardour/amp.h | 3 +- libs/ardour/ardour/audio_track.h | 4 +- libs/ardour/ardour/configuration_vars.h | 1 + libs/ardour/ardour/control_outputs.h | 27 +- libs/ardour/ardour/delivery.h | 79 +++++ libs/ardour/ardour/io.h | 4 +- libs/ardour/ardour/io_processor.h | 6 +- libs/ardour/ardour/meter.h | 3 +- libs/ardour/ardour/midi_diskstream.h | 1 + libs/ardour/ardour/midi_state_tracker.h | 3 +- libs/ardour/ardour/midi_track.h | 7 +- libs/ardour/ardour/panner.h | 2 +- libs/ardour/ardour/playlist.h | 2 + libs/ardour/ardour/plugin_insert.h | 2 +- libs/ardour/ardour/port_insert.h | 2 +- libs/ardour/ardour/processor.h | 19 +- libs/ardour/ardour/return.h | 2 +- libs/ardour/ardour/route.h | 40 ++- libs/ardour/ardour/send.h | 9 +- libs/ardour/ardour/session.h | 10 +- libs/ardour/ardour/track.h | 8 +- libs/ardour/audio_track.cc | 4 +- libs/ardour/audioengine.cc | 5 +- libs/ardour/control_outputs.cc | 55 +--- libs/ardour/delivery.cc | 203 ++++++++++++ libs/ardour/enums.cc | 8 + libs/ardour/io.cc | 9 +- libs/ardour/io_processor.cc | 86 +++++- libs/ardour/meter.cc | 14 +- libs/ardour/midi_diskstream.cc | 169 ++++++++++ libs/ardour/midi_state_tracker.cc | 19 ++ libs/ardour/midi_track.cc | 6 +- libs/ardour/panner.cc | 2 +- libs/ardour/playlist.cc | 29 +- libs/ardour/plugin_insert.cc | 2 +- libs/ardour/plugin_manager.cc | 1 - libs/ardour/port_insert.cc | 2 +- libs/ardour/processor.cc | 19 +- libs/ardour/return.cc | 2 +- libs/ardour/route.cc | 533 +++++++++++++++++--------------- libs/ardour/send.cc | 44 +-- libs/ardour/session.cc | 92 +++--- libs/ardour/session_transport.cc | 4 + libs/ardour/track.cc | 12 +- libs/ardour/wscript | 2 +- libs/pbd/id.cc | 6 + libs/pbd/pbd/id.h | 2 + 57 files changed, 1250 insertions(+), 644 deletions(-) create mode 100644 libs/ardour/ardour/delivery.h create mode 100644 libs/ardour/delivery.cc diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h index 33d7c2ac1e..35e93b985f 100644 --- a/gtk2_ardour/audio_region_view.h +++ b/gtk2_ardour/audio_region_view.h @@ -28,6 +28,7 @@ #include "region_view.h" #include "route_time_axis.h" + #include "time_axis_view_item.h" #include "automation_line.h" #include "enums.h" diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc index 8dcee5aaab..772b455f97 100644 --- a/gtk2_ardour/audio_streamview.cc +++ b/gtk2_ardour/audio_streamview.cc @@ -108,30 +108,32 @@ RegionView* AudioStreamView::add_region_view_internal (boost::shared_ptr r, bool wait_for_waves, bool recording) { AudioRegionView *region_view = 0; - boost::shared_ptr region = boost::dynamic_pointer_cast (r); if (region == 0) { return NULL; } - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if ((*i)->region() == r) { - - /* great. we already have a AudioRegionView for this Region. use it again. */ - - (*i)->set_valid (true); - - // this might not be necessary - AudioRegionView* const arv = dynamic_cast(*i); - if (arv) { - arv->set_waveform_scale (_waveform_scale); - arv->set_waveform_shape (_waveform_shape); - } +// if(!recording){ +// for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { +// if ((*i)->region() == r) { +// cerr << "audio_streamview in add_region_view_internal region found" << endl; + /* great. we already have a AudioRegionView for this Region. use it again. */ - return NULL; - } - } +// (*i)->set_valid (true); + + // this might not be necessary +// AudioRegionView* const arv = dynamic_cast(*i); + +// if (arv) { +// arv->set_waveform_scale (_waveform_scale); +// arv->set_waveform_shape (_waveform_shape); +// } + +// return NULL; +// } +// } +// } switch (_trackview.audio_track()->mode()) { @@ -173,6 +175,7 @@ AudioStreamView::add_region_view_internal (boost::shared_ptr r, bool wai otherwise, we set it to the current value */ if (region_views.size() == 1) { + if (region_view->waveform_logscaled()) { _waveform_scale = LogWaveform; } else { @@ -191,7 +194,6 @@ AudioStreamView::add_region_view_internal (boost::shared_ptr r, bool wai } /* follow global waveform setting */ - region_view->set_waveform_visible(_trackview.editor().show_waveforms()); /* catch regionview going away */ @@ -396,6 +398,7 @@ AudioStreamView::redisplay_diskstream () } // Add and display region and crossfade views, and flag them as valid + if (_trackview.is_audio_track()) { _trackview.get_diskstream()->playlist()->foreach_region( static_cast(this), diff --git a/gtk2_ardour/canvas-waveview.c b/gtk2_ardour/canvas-waveview.c index 5563fe5a78..8b2a7c8af7 100644 --- a/gtk2_ardour/canvas-waveview.c +++ b/gtk2_ardour/canvas-waveview.c @@ -764,6 +764,7 @@ gnome_canvas_waveview_set_property (GObject *object, waveview->length_function = g_value_get_pointer(value); redraw = TRUE; break; + case PROP_SOURCEFILE_LENGTH_FUNCTION: waveview->sourcefile_length_function = g_value_get_pointer(value); redraw = TRUE; diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index b1ad57f9cd..7e1a303e73 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -199,74 +199,6 @@ Editor::split_regions_at (nframes64_t where, RegionSelection& regions) _new_regionviews_show_envelope = false; } - -/** Remove `clicked_regionview' */ -void -Editor::remove_clicked_region () -{ - if (clicked_routeview == 0 || clicked_regionview == 0) { - return; - } - - boost::shared_ptr playlist = clicked_routeview->playlist(); - - begin_reversible_command (_("remove region")); - XMLNode &before = playlist->get_state(); - playlist->remove_region (clicked_regionview->region()); - XMLNode &after = playlist->get_state(); - session->add_command(new MementoCommand(*playlist, &before, &after)); - commit_reversible_command (); -} - - -/** Remove the selected regions */ -void -Editor::remove_selected_regions () -{ - RegionSelection rs; - get_regions_for_action (rs); - - if (!session) { - return; - } - - if (rs.empty()) { - return; - } - - begin_reversible_command (_("remove region")); - - list > regions_to_remove; - - for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { - // we can't just remove the region(s) in this loop because - // this removes them from the RegionSelection, and they thus - // disappear from underneath the iterator, and the ++i above - // SEGVs in a puzzling fashion. - - // so, first iterate over the regions to be removed from rs and - // add them to the regions_to_remove list, and then - // iterate over the list to actually remove them. - - regions_to_remove.push_back ((*i)->region()); - } - - for (list >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) { - boost::shared_ptr playlist = (*rl)->playlist(); - if (!playlist) { - // is this check necessary? - continue; - } - - XMLNode &before = playlist->get_state(); - playlist->remove_region (*rl); - XMLNode &after = playlist->get_state(); - session->add_command(new MementoCommand(*playlist, &before, &after)); - } - - commit_reversible_command (); -} - boost::shared_ptr Editor::select_region_for_operation (int dir, TimeAxisView **tv) { @@ -4076,13 +4008,106 @@ struct PlaylistMapping { PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {} }; +/** Remove `clicked_regionview' */ +void +Editor::remove_clicked_region () +{ + if (clicked_routeview == 0 || clicked_regionview == 0) { + return; + } + + boost::shared_ptr playlist = clicked_routeview->playlist(); + + begin_reversible_command (_("remove region")); + XMLNode &before = playlist->get_state(); + playlist->remove_region (clicked_regionview->region()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand(*playlist, &before, &after)); + commit_reversible_command (); +} + + +/** Remove the selected regions */ +void +Editor::remove_selected_regions () +{ + RegionSelection rs; + get_regions_for_action (rs); + + if (!session) { + return; + } + + if (rs.empty()) { + return; + } + + begin_reversible_command (_("remove region")); + + list > regions_to_remove; + + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { + // we can't just remove the region(s) in this loop because + // this removes them from the RegionSelection, and they thus + // disappear from underneath the iterator, and the ++i above + // SEGVs in a puzzling fashion. + + // so, first iterate over the regions to be removed from rs and + // add them to the regions_to_remove list, and then + // iterate over the list to actually remove them. + + regions_to_remove.push_back ((*i)->region()); + } + + vector playlists; + + for (list >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) { + + boost::shared_ptr playlist = (*rl)->playlist(); + + if (!playlist) { + // is this check necessary? + continue; + } + + vector::iterator i; + + //only take state if this is a new playlist. + for (i = playlists.begin(); i != playlists.end(); ++i) { + if ((*i).playlist == playlist) { + break; + } + } + + if (i == playlists.end()) { + + PlaylistState before; + before.playlist = playlist; + before.before = &playlist->get_state(); + + playlist->freeze (); + playlists.push_back(before); + } + + playlist->remove_region (*rl); + } + + vector::iterator pl; + + for (pl = playlists.begin(); pl != playlists.end(); ++pl) { + (*pl).playlist->thaw (); + session->add_command(new MementoCommand(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state())); + } + + commit_reversible_command (); +} /** Cut, copy or clear selected regions. * @param op Operation (Cut, Copy or Clear) */ void Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs) -{ +{ /* we can't use a std::map here because the ordering is important, and we can't trivially sort a map when we want ordered access to both elements. i think. */ @@ -4106,15 +4131,21 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs) boost::shared_ptr pl = (*x)->region()->playlist(); if (pl) { + set::iterator fl; - PlaylistState before; - before.playlist = pl; - before.before = &pl->get_state(); - - insert_result = freezelist.insert (before); - - if (insert_result.second) { + //only take state if this is a new playlist. + for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) { + if ((*fl).playlist == pl) { + break; + } + } + + if (fl == freezelist.end()) { + PlaylistState before; + before.playlist = pl; + before.before = &pl->get_state(); pl->freeze (); + insert_result = freezelist.insert (before); } } } diff --git a/gtk2_ardour/port_matrix_grid.cc b/gtk2_ardour/port_matrix_grid.cc index bbf5447160..7c94beaeac 100644 --- a/gtk2_ardour/port_matrix_grid.cc +++ b/gtk2_ardour/port_matrix_grid.cc @@ -141,6 +141,8 @@ PortMatrixGrid::render (cairo_t* cr) case PortMatrixNode::PARTIAL: draw_association_indicator (cr, bx, by, 0.5); break; + default: + break; } by += row_height(); @@ -179,6 +181,9 @@ PortMatrixGrid::render (cairo_t* cr) case PortMatrixNode::NOT_ASSOCIATED: break; + + default: + break; } y += row_height(); @@ -483,6 +488,9 @@ PortMatrixGrid::bundle_to_bundle_state (boost::shared_ptr a, boo have_diagonal_not_association = true; } break; + + default: + break; } } } diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index f9b4cc0e6e..a259a25695 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -433,7 +433,9 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins) processor->activate (); } - if (_route->add_processor (processor, &err_streams, 0, _placement)) { + assign_default_sort_key (processor); + + if (_route->add_processor (processor, &err_streams)) { weird_plugin_dialog (**p, err_streams, _route); // XXX SHAREDPTR delete plugin here .. do we even need to care? } else { @@ -497,7 +499,9 @@ ProcessorBox::choose_insert () processor->ActiveChanged.connect (bind ( mem_fun(*this, &ProcessorBox::show_processor_active), boost::weak_ptr(processor))); - _route->add_processor (processor, 0, 0, _placement); + + assign_default_sort_key (processor); + _route->add_processor (processor); } void @@ -549,7 +553,8 @@ ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr break; case IOSelector::Accepted: - _route->add_processor (processor, 0, 0, _placement); + assign_default_sort_key (processor); + _route->add_processor (processor); if (Profile->get_sae()) { processor->activate (); } @@ -606,7 +611,8 @@ ProcessorBox::return_io_finished (IOSelector::Result r, boost::weak_ptradd_processor (processor, 0, 0, _placement); + assign_default_sort_key (processor); + _route->add_processor (processor); if (Profile->get_sae()) { processor->activate (); } @@ -636,10 +642,10 @@ ProcessorBox::redisplay_processors () switch (_placement) { case PreFader: - build_processor_tooltip(processor_eventbox, _("Pre-fader inserts, sends & plugins:")); + build_processor_tooltip (processor_eventbox, _("Pre-fader inserts, sends & plugins:")); break; case PostFader: - build_processor_tooltip(processor_eventbox, _("Post-fader inserts, sends & plugins:")); + build_processor_tooltip (processor_eventbox, _("Post-fader inserts, sends & plugins:")); break; } } @@ -790,9 +796,15 @@ ProcessorBox::row_deleted (const Gtk::TreeModel::Path& path) void ProcessorBox::compute_processor_sort_keys () { - uint32_t sort_key = 0; + uint32_t sort_key; Gtk::TreeModel::Children children = model->children(); + if (_placement == PreFader) { + sort_key = 0; + } else { + sort_key = _route->fader_sort_key() + 1; + } + for (Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) { boost::shared_ptr r = (*iter)[columns.processor]; r->set_sort_key (sort_key); @@ -1013,6 +1025,17 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist) } else if (type->value() == "meter") { p = _route->shared_peak_meter(); + } else if (type->value() == "main-outs") { + /* do not copy-n-paste main outs */ + continue; + + } else if (type->value() == "amp") { + /* do not copy-n-paste amp */ + continue; + + } else if (type->value() == "listen") { + p.reset (new Delivery (_session, **niter)); + } else { p.reset (new PluginInsert (_session, **niter)); } @@ -1024,7 +1047,13 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist) } } - if (_route->add_processors (copies, 0, _placement)) { + if (copies.empty()) { + return; + } + + assign_default_sort_key (copies.front()); + + if (_route->add_processors (copies, 0, copies.front()->sort_key())) { string msg = _( "Copying the set of processors on the clipboard failed,\n\ @@ -1539,3 +1568,12 @@ ProcessorBox::generate_processor_title (boost::shared_ptr pi) return string_compose(_("%1: %2 (by %3)"), _route->name(), pi->name(), maker); } +void +ProcessorBox::assign_default_sort_key (boost::shared_ptr p) +{ + p->set_sort_key (_placement == PreFader ? 0 : 9999); + cerr << "default sort key for " + << _placement << " = " << p->sort_key() + << endl; +} + diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h index 3286c14e6c..f5af4c49dc 100644 --- a/gtk2_ardour/processor_box.h +++ b/gtk2_ardour/processor_box.h @@ -168,6 +168,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject void processors_reordered (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&, int*); void compute_processor_sort_keys (); + void assign_default_sort_key (boost::shared_ptr); std::vector processor_active_connections; std::vector processor_name_connections; diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc index 6425b84c27..2127d1354c 100644 --- a/gtk2_ardour/streamview.cc +++ b/gtk2_ardour/streamview.cc @@ -168,10 +168,20 @@ StreamView::set_samples_per_unit (gdouble spp) return 0; } +void +StreamView::add_region_view_weak (boost::weak_ptr r) +{ + boost::shared_ptr sp (r.lock()); + + if (sp) { + add_region_view (sp); + } +} + void StreamView::add_region_view (boost::shared_ptr r) { - // ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_region_view), r)); + ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::add_region_view), r)); add_region_view_internal (r, true); if (_layer_display == Stacked) { @@ -284,6 +294,7 @@ void StreamView::playlist_modified_weak (boost::weak_ptr ds) { boost::shared_ptr sp (ds.lock()); + if (sp) { playlist_modified (sp); } @@ -300,7 +311,7 @@ StreamView::playlist_modified (boost::shared_ptr ds) _layers = ds->playlist()->top_layer() + 1; update_contents_height (); update_coverage_frames (); - redisplay_diskstream (); + //redisplay_diskstream (); } } @@ -342,8 +353,13 @@ StreamView::playlist_changed (boost::shared_ptr ds) /* catch changes */ playlist_connections.push_back (ds->playlist()->Modified.connect (bind ( - mem_fun (*this, &StreamView::playlist_modified_weak), - ds))); + mem_fun (*this, &StreamView::playlist_modified_weak), ds))); + + playlist_connections.push_back (ds->playlist()->RegionAdded.connect ( + mem_fun (*this, &StreamView::add_region_view_weak))); + + playlist_connections.push_back (ds->playlist()->RegionRemoved.connect ( + mem_fun (*this, &StreamView::remove_region_view))); } void diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h index 546d51dee2..bb6047df23 100644 --- a/gtk2_ardour/streamview.h +++ b/gtk2_ardour/streamview.h @@ -93,7 +93,10 @@ public: void get_inverted_selectables (Selection&, std::list& results); virtual void update_contents_metrics(boost::shared_ptr r) {} + + void add_region_view_weak (boost::weak_ptr r); void add_region_view (boost::shared_ptr); + void region_layered (RegionView*); virtual void update_contents_height (); @@ -114,7 +117,7 @@ protected: void update_rec_box (); virtual RegionView* add_region_view_internal (boost::shared_ptr, - bool wait_for_waves, bool recording = false) = 0; + bool wait_for_waves, bool recording = false) = 0; virtual void remove_region_view (boost::weak_ptr ); void display_diskstream (boost::shared_ptr); diff --git a/libs/ardour/amp.cc b/libs/ardour/amp.cc index aa20f3e389..591fcd8569 100644 --- a/libs/ardour/amp.cc +++ b/libs/ardour/amp.cc @@ -57,7 +57,7 @@ Amp::configure_io (ChanCount in, ChanCount out) } void -Amp::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) +Amp::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { gain_t* gab = _session.gain_automation_buffer(); @@ -201,15 +201,9 @@ Amp::apply_simple_gain (BufferSet& bufs, nframes_t nframes, gain_t target) XMLNode& Amp::state (bool full_state) { - return get_state(); -} - -XMLNode& -Amp::get_state() -{ - XMLNode* node = new XMLNode(state_node_name); - node->add_property("type", "amp"); - return *node; + XMLNode& node (Processor::state (full_state)); + node.add_property("type", "amp"); + return node; } } // namespace ARDOUR diff --git a/libs/ardour/ardour/amp.h b/libs/ardour/ardour/amp.h index fa9de724ad..152b89a431 100644 --- a/libs/ardour/ardour/amp.h +++ b/libs/ardour/ardour/amp.h @@ -39,7 +39,7 @@ public: bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool configure_io (ChanCount in, ChanCount out); - void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); + void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); bool apply_gain() const { return _apply_gain; } void apply_gain(bool yn) { _apply_gain = yn; } @@ -61,7 +61,6 @@ public: } XMLNode& state (bool full); - XMLNode& get_state(); static void apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity); diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index 145272b331..5813c2d697 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -39,7 +39,7 @@ class AudioTrack : public Track int set_mode (TrackMode m); bool can_use_mode (TrackMode m, bool& bounce_required); - int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input); boost::shared_ptr audio_diskstream() const; @@ -47,7 +47,7 @@ class AudioTrack : public Track int use_diskstream (std::string name); int use_diskstream (const PBD::ID& id); - int export_stuff (BufferSet& bufs, nframes_t nframes, nframes_t end_frame, bool enable_processing = true); + int export_stuff (BufferSet& bufs, sframes_t start_frame, nframes_t nframes, bool enable_processing = true); void freeze (InterThreadInfo&); void unfreeze (); diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h index 3091538e38..f49663b55b 100644 --- a/libs/ardour/ardour/configuration_vars.h +++ b/libs/ardour/ardour/configuration_vars.h @@ -19,6 +19,7 @@ /* IO connection */ +CONFIG_VARIABLE (bool, auto_connect_master, "auto-connect-master", true) CONFIG_VARIABLE (AutoConnectOption, output_auto_connect, "output-auto-connect", AutoConnectOption (0)) CONFIG_VARIABLE (AutoConnectOption, input_auto_connect, "input-auto-connect", AutoConnectOption (0)) diff --git a/libs/ardour/ardour/control_outputs.h b/libs/ardour/ardour/control_outputs.h index 72d9534ddf..0a09ab10f4 100644 --- a/libs/ardour/ardour/control_outputs.h +++ b/libs/ardour/ardour/control_outputs.h @@ -26,26 +26,19 @@ namespace ARDOUR { -class BufferSet; -class IO; +/* this exists for one reason only: so that it can override the "type" + property in the state of the Delivery processor. we need this + because ControlOutputs are "unique" because they deliver to + an IO object that is private to a Route and so cannot be looked + up in the Session etc. +*/ -class ControlOutputs : public IOProcessor { +class ControlOutputs : public Delivery { public: - ControlOutputs(Session& s, IO* io); - - bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; - bool configure_io (ChanCount in, ChanCount out); - - void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); - - bool deliver() const { return _deliver; } - void deliver(bool yn) { _deliver = yn; } - - XMLNode& state (bool full); - XMLNode& get_state(); + ControlOutputs(Session& s); + XMLNode& get_state (); -private: - bool _deliver; + static const std::string processor_type_name; }; diff --git a/libs/ardour/ardour/delivery.h b/libs/ardour/ardour/delivery.h new file mode 100644 index 0000000000..8d083695b1 --- /dev/null +++ b/libs/ardour/ardour/delivery.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2006 Paul Davis + + 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., + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_delivery_h__ +#define __ardour_delivery_h__ + +#include +#include "ardour/types.h" +#include "ardour/chan_count.h" +#include "ardour/io_processor.h" + +namespace ARDOUR { + +class BufferSet; +class IO; + +class Delivery : public IOProcessor { +public: + enum Role { + Send = 0x1, + Solo = 0x2, + Listen = 0x4, + Main = 0x8 + }; + + Delivery (Session& s, IO* io, const std::string& name, Role); + Delivery (Session& s, const std::string& name, Role); + Delivery (Session&, const XMLNode&); + + bool visible() const; + + Role role() const { return _role; } + + bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; + bool configure_io (ChanCount in, ChanCount out); + + void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); + + void set_metering (bool yn); + + bool muted_by_self() const { return _muted_by_self; } + bool muted_by_others() const { return _muted_by_others; } + + void set_self_mute (bool); + void set_nonself_mute (bool); + + sigc::signal SelfMuteChange; + sigc::signal OtherMuteChange; + + XMLNode& state (bool full); + int set_state (const XMLNode&); + +private: + Role _role; + bool _metering; + bool _muted_by_self; + bool _muted_by_others; +}; + + +} // namespace ARDOUR + +#endif // __ardour__h__ + diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 8b236eadff..297a4ee82c 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -100,8 +100,8 @@ class IO : public SessionObject, public AutomatableControls, public Latent virtual void silence (nframes_t); void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO); - void deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); - void just_meter_input (nframes_t start_frame, nframes_t end_frame, nframes_t nframes); + void deliver_output (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); + void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes); BufferSet& output_buffers() { return *_output_buffers; } diff --git a/libs/ardour/ardour/io_processor.h b/libs/ardour/ardour/io_processor.h index 7f847c9221..896de52a3b 100644 --- a/libs/ardour/ardour/io_processor.h +++ b/libs/ardour/ardour/io_processor.h @@ -49,6 +49,8 @@ class IOProcessor : public Processor ARDOUR::DataType default_type = DataType::AUDIO); virtual ~IOProcessor (); + bool set_name (const std::string& str); + virtual ChanCount output_streams() const; virtual ChanCount input_streams () const; virtual ChanCount natural_output_streams() const; @@ -56,10 +58,11 @@ class IOProcessor : public Processor boost::shared_ptr io() { return _io; } boost::shared_ptr io() const { return _io; } + void set_io (boost::shared_ptr); virtual void automation_snapshot (nframes_t now, bool force); - virtual void run_in_place (BufferSet& in, nframes_t start, nframes_t end, nframes_t nframes) = 0; + virtual void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0; void silence (nframes_t nframes); sigc::signal AutomationPlaybackChanged; @@ -74,6 +77,7 @@ class IOProcessor : public Processor private: /* disallow copy construction */ IOProcessor (const IOProcessor&); + bool _own_io; }; diff --git a/libs/ardour/ardour/meter.h b/libs/ardour/ardour/meter.h index 0a49ddf99f..250fb3111e 100644 --- a/libs/ardour/ardour/meter.h +++ b/libs/ardour/ardour/meter.h @@ -44,7 +44,7 @@ public: bool configure_io (ChanCount in, ChanCount out); /** Compute peaks */ - void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); + void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); float peak_power (uint32_t n) { if (n < _visible_peak_power.size()) { @@ -63,7 +63,6 @@ public: } XMLNode& state (bool full); - XMLNode& get_state(); private: friend class IO; diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index a7b4f5e120..d5c2d0cdb3 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -180,6 +180,7 @@ class MidiDiskstream : public Diskstream nframes_t _last_flush_frame; NoteMode _note_mode; MidiStateTracker _midi_state_tracker; + MidiStateTracker _incoming_midi_state_tracker; volatile gint _frames_written_to_ringbuffer; volatile gint _frames_read_from_ringbuffer; }; diff --git a/libs/ardour/ardour/midi_state_tracker.h b/libs/ardour/ardour/midi_state_tracker.h index 3f74d67b17..4c15ab1e0f 100644 --- a/libs/ardour/ardour/midi_state_tracker.h +++ b/libs/ardour/ardour/midi_state_tracker.h @@ -24,7 +24,6 @@ #include "ardour/midi_buffer.h" - namespace ARDOUR { @@ -38,6 +37,8 @@ public: bool track (const MidiBuffer::iterator& from, const MidiBuffer::iterator& to); void resolve_notes (MidiBuffer& buffer, nframes_t time); + void dump (std::ostream&); + void reset (); private: void track_note_onoffs(const Evoral::MIDIEvent& event); diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index fe8290d5d9..e7ffd40d67 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -38,7 +38,7 @@ public: MidiTrack (Session&, const XMLNode&); ~MidiTrack (); - int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input); boost::shared_ptr midi_diskstream() const; @@ -48,8 +48,7 @@ public: void set_latency_delay (nframes_t); - int export_stuff (BufferSet& bufs, - nframes_t nframes, nframes_t end_frame); + int export_stuff (BufferSet& bufs, nframes_t nframes, sframes_t end_frame); void freeze (InterThreadInfo&); void unfreeze (); @@ -85,7 +84,7 @@ protected: int _set_state (const XMLNode&, bool call_base); private: - void write_controller_messages(MidiBuffer& buf, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); + void write_controller_messages(MidiBuffer& buf, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); int set_diskstream (boost::shared_ptr ds); void use_new_diskstream (); diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h index be3de9a5a3..9bc1817af0 100644 --- a/libs/ardour/ardour/panner.h +++ b/libs/ardour/ardour/panner.h @@ -215,7 +215,7 @@ class Panner : public Processor bool is_out_of_place () const { return true; } bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const { return true; }; - void run_out_of_place(BufferSet& src, BufferSet& dest, nframes_t start_frame, nframes_t end_frames, nframes_t nframes); + void run_out_of_place(BufferSet& src, BufferSet& dest, sframes_t start_frame, sframes_t end_frames, nframes_t nframes); //void* get_inline_gui() const = 0; //void* get_full_gui() const = 0; diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index 15aa041ed6..8be95ca74b 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -129,6 +129,8 @@ class Playlist : public SessionObject, sigc::signal InUse; sigc::signal Modified; + sigc::signal > RegionAdded; + sigc::signal > RegionRemoved; sigc::signal NameChanged; sigc::signal LengthChanged; sigc::signal > const &> RangesMoved; diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index 59ab6de2d8..01cf9bedfd 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -54,7 +54,7 @@ class PluginInsert : public Processor XMLNode& get_state(void); int set_state(const XMLNode&); - void run_in_place (BufferSet& in, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); + void run_in_place (BufferSet& in, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); void silence (nframes_t nframes); void activate (); diff --git a/libs/ardour/ardour/port_insert.h b/libs/ardour/ardour/port_insert.h index ce21d9f223..56aa43c6c5 100644 --- a/libs/ardour/ardour/port_insert.h +++ b/libs/ardour/ardour/port_insert.h @@ -50,7 +50,7 @@ class PortInsert : public IOProcessor void init (); - void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); + void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); nframes_t signal_latency() const; diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h index 757af64c87..68fdb5c6a6 100644 --- a/libs/ardour/ardour/processor.h +++ b/libs/ardour/ardour/processor.h @@ -60,6 +60,8 @@ class Processor : public SessionObject, public AutomatableControls, public Laten ChanCount in; ChanCount out; }; + + virtual bool visible() const { return true; } uint32_t sort_key() const { return _sort_key; } void set_sort_key (uint32_t key); @@ -76,12 +78,12 @@ class Processor : public SessionObject, public AutomatableControls, public Laten virtual void set_block_size (nframes_t nframes) {} virtual void run_in_place (BufferSet& bufs, - nframes_t start_frame, nframes_t end_frame, - nframes_t nframes) { assert(is_in_place()); } + sframes_t start_frame, sframes_t end_frame, + nframes_t nframes) { assert(is_in_place()); } virtual void run_out_of_place (BufferSet& input, BufferSet& output, - nframes_t start_frame, nframes_t end_frame, - nframes_t nframes) { assert(is_out_of_place()); } + sframes_t start_frame, sframes_t end_frame, + nframes_t nframes) { assert(is_out_of_place()); } virtual void silence (nframes_t nframes) {} @@ -103,9 +105,14 @@ class Processor : public SessionObject, public AutomatableControls, public Laten virtual ChanCount input_streams () const { return _configured_input; } virtual ChanCount output_streams() const { return _configured_output; } + /* note: derived classes should implement state(), NOT get_state(), to allow + us to merge C++ inheritance and XML lack-of-inheritance reasonably + smoothly. + */ + virtual XMLNode& state (bool full); - virtual XMLNode& get_state (void); - virtual int set_state (const XMLNode&); + XMLNode& get_state (void); + int set_state (const XMLNode&); void *get_gui () const { return _gui; } void set_gui (void *p) { _gui = p; } diff --git a/libs/ardour/ardour/return.h b/libs/ardour/ardour/return.h index af55df59ed..2b6cd0b69e 100644 --- a/libs/ardour/ardour/return.h +++ b/libs/ardour/ardour/return.h @@ -41,7 +41,7 @@ public: uint32_t bit_slot() const { return _bitslot; } - void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); + void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); void activate() {} void deactivate () {} diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 9537097f74..aee361d3a5 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -45,7 +45,7 @@ namespace ARDOUR { class Amp; -class ControlOutputs; +class Delivery; class IOProcessor; class Processor; class RouteGroup; @@ -84,6 +84,8 @@ class Route : public IO std::string comment() { return _comment; } void set_comment (std::string str, void *src); + bool set_name (const std::string& str); + long order_key (const char* name) const; void set_order_key (const char* name, long n); @@ -94,13 +96,13 @@ class Route : public IO /* these are the core of the API of a Route. see the protected sections as well */ - virtual int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + virtual int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input); - virtual int no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + virtual int no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool state_changing, bool can_record, bool rec_monitors_input); - virtual int silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + virtual int silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool can_record, bool rec_monitors_input); virtual void toggle_monitor_input (); @@ -173,9 +175,16 @@ class Route : public IO return *i; } } + + uint32_t fader_sort_key() const; ChanCount max_processor_streams () const { return processor_max_streams; } ChanCount pre_fader_streams() const; + + /* special processors */ + + boost::shared_ptr control_outs() const { return _control_outs; } + boost::shared_ptr main_outs() const { return _main_outs; } /** A record of the stream configuration at some point in the processor list. * Used to return where and why an processor list configuration request failed. @@ -187,8 +196,8 @@ class Route : public IO ChanCount count; ///< Input requested of processor }; - int add_processor (boost::shared_ptr, ProcessorStreams* err = 0, ProcessorList::iterator* iter=0, Placement=PreFader); - int add_processors (const ProcessorList&, ProcessorStreams* err = 0, Placement placement=PreFader); + int add_processor (boost::shared_ptr, ProcessorStreams* err = 0, ProcessorList::iterator* iter=0); + int add_processors (const ProcessorList&, ProcessorStreams* err = 0, uint32_t first_sort_key = 0); int remove_processor (boost::shared_ptr, ProcessorStreams* err = 0); int sort_processors (ProcessorStreams* err = 0); void disable_processors (Placement); @@ -237,9 +246,9 @@ class Route : public IO int save_as_template (const std::string& path, const std::string& name); sigc::signal SelectedChanged; - - int set_control_outs (const std::vector& ports); - boost::shared_ptr control_outs() { return _control_outs; } + + int listen_via (boost::shared_ptr, const std::string& name); + void drop_listen (boost::shared_ptr); bool feeds (boost::shared_ptr); std::set > fed_by; @@ -288,11 +297,11 @@ class Route : public IO protected: nframes_t check_initial_delay (nframes_t, nframes_t&); - void passthru (nframes_t start_frame, nframes_t end_frame, - nframes_t nframes, int declick); + void passthru (sframes_t start_frame, sframes_t end_frame, + nframes_t nframes, int declick); virtual void process_output_buffers (BufferSet& bufs, - nframes_t start_frame, nframes_t end_frame, + sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool with_processors, int declick); Flag _flags; @@ -308,7 +317,8 @@ class Route : public IO nframes_t _roll_delay; ProcessorList _processors; Glib::RWLock _processor_lock; - boost::shared_ptr _control_outs; + boost::shared_ptr _main_outs; + boost::shared_ptr _control_outs; // XXX to be removed/generalized by listen points RouteGroup *_edit_group; RouteGroup *_mix_group; std::string _comment; @@ -336,7 +346,7 @@ class Route : public IO virtual XMLNode& state(bool); - void passthru_silence (nframes_t start_frame, nframes_t end_frame, + void passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, int declick); void silence (nframes_t nframes); @@ -354,6 +364,8 @@ class Route : public IO virtual int _set_state (const XMLNode&, bool call_base); virtual void _set_processor_states (const XMLNodeList&); + boost::shared_ptr add_listener (boost::shared_ptr, const std::string&); + private: void init (); diff --git a/libs/ardour/ardour/send.h b/libs/ardour/ardour/send.h index 825506f0e2..7bdc7ed02f 100644 --- a/libs/ardour/ardour/send.h +++ b/libs/ardour/ardour/send.h @@ -27,11 +27,11 @@ #include "pbd/stateful.h" #include "ardour/ardour.h" #include "ardour/audioengine.h" -#include "ardour/io_processor.h" +#include "ardour/delivery.h" namespace ARDOUR { -class Send : public IOProcessor +class Send : public Delivery { public: Send (Session&); @@ -40,13 +40,9 @@ class Send : public IOProcessor uint32_t bit_slot() const { return _bitslot; } - void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes); - void activate() {} void deactivate () {} - void set_metering (bool yn); - XMLNode& state(bool full); XMLNode& get_state(void); int set_state(const XMLNode& node); @@ -63,7 +59,6 @@ class Send : public IOProcessor /* disallow copy construction */ Send (const Send&); - bool _metering; uint32_t _bitslot; }; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 31bbded03b..344b79bcd1 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1020,12 +1020,10 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable bool _silent; volatile double _transport_speed; double _last_transport_speed; - // fixed point transport speed for varispeed playback - uint64_t phi; - // fixed point target transport speed for varispeed playback when tempo changes - uint64_t target_phi; - // fixed point phase for varispeed playback - uint64_t phase; + // varispeed playback + uint64_t phi; // fixed point transport speed + uint64_t target_phi; // fixed point target transport speed + uint64_t phase; // fixed point phase bool auto_play_legal; nframes_t _last_slave_transport_frame; nframes_t maximum_output_latency; diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index 700380417b..aca7c6f968 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -45,13 +45,13 @@ class Track : public Route virtual bool can_use_mode (TrackMode m, bool& bounce_required) { return false; } sigc::signal TrackModeChanged; - int no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, - bool state_changing, bool can_record, bool rec_monitors_input); + int no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, + bool state_changing, bool can_record, bool rec_monitors_input); - int silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + int silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool can_record, bool rec_monitors_input); - virtual int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + virtual int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input) = 0; void toggle_monitor_input (); diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index 79b1240ab0..4a3fa04d1c 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -454,7 +454,7 @@ AudioTrack::set_state_part_two () } int -AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int declick, +AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input) { int dret; @@ -624,7 +624,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, } int -AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes, bool enable_processing) +AudioTrack::export_stuff (BufferSet& buffers, sframes_t start, nframes_t nframes, bool enable_processing) { gain_t gain_buffer[nframes]; float mix_buffer[nframes]; diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 91cea6ba71..3e1ba8b2d9 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -41,6 +41,9 @@ #include "ardour/utils.h" #include "ardour/event_type_map.h" #include "ardour/io.h" +#include "ardour/amp.h" +#include "ardour/port_set.h" +#include "ardour/buffer_set.h" #include "ardour/timestamps.h" @@ -420,7 +423,7 @@ AudioEngine::process_callback (nframes_t nframes) port->get_buffer(nframes).silence(nframes); } } - } + } // Finalize ports diff --git a/libs/ardour/control_outputs.cc b/libs/ardour/control_outputs.cc index 2acd3c6d9e..8efb75145c 100644 --- a/libs/ardour/control_outputs.cc +++ b/libs/ardour/control_outputs.cc @@ -16,64 +16,23 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include #include "ardour/control_outputs.h" -#include "ardour/audio_buffer.h" -#include "ardour/buffer_set.h" -#include "ardour/configuration.h" -#include "ardour/io.h" -#include "ardour/session.h" using namespace std; +using namespace ARDOUR; -namespace ARDOUR { +const std::string ControlOutputs::processor_type_name = "control-outputs"; -ControlOutputs::ControlOutputs(Session& s, IO* io) - : IOProcessor(s, io, "Control Outs") - , _deliver(true) +ControlOutputs::ControlOutputs(Session& s, IO* io, const std::string& name) + : Delivery (s, io, name) { } -bool -ControlOutputs::can_support_io_configuration (const ChanCount& in, ChanCount& out) const -{ - out = in; - return true; -} - -bool -ControlOutputs::configure_io (ChanCount in, ChanCount out) -{ - if (out != in) { // always 1:1 - return false; - } - - return Processor::configure_io (in, out); -} - -void -ControlOutputs::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) -{ - if (_deliver) { - _io->deliver_output (bufs, start_frame, end_frame, nframes); - } else { - _io->silence (nframes); - } -} - -XMLNode& -ControlOutputs::state (bool full_state) -{ - return get_state(); -} - XMLNode& ControlOutputs::get_state() { - XMLNode* node = new XMLNode(state_node_name); - node->add_property("type", "control-outputs"); - return *node; + XMLNode& node (Delivery::get_state()); + node.add_property ("type", processor_type_name); + return node; } -} // namespace ARDOUR diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc new file mode 100644 index 0000000000..bf15242094 --- /dev/null +++ b/libs/ardour/delivery.cc @@ -0,0 +1,203 @@ +/* + Copyright (C) 2009 Paul Davis + + 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., + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include "pbd/enumwriter.h" +#include "ardour/delivery.h" +#include "ardour/audio_buffer.h" +#include "ardour/buffer_set.h" +#include "ardour/configuration.h" +#include "ardour/io.h" +#include "ardour/meter.h" +#include "ardour/session.h" + +using namespace std; +using namespace ARDOUR; + +/* deliver to an existing IO object */ + +Delivery::Delivery (Session& s, IO* io, const string& name, Role r) + : IOProcessor(s, io, name) + , _role (r) + , _metering (false) + , _muted_by_self (false) + , _muted_by_others (false) +{ +} + +/* deliver to a new IO object */ + +Delivery::Delivery (Session& s, const string& name, Role r) + : IOProcessor(s, name) + , _role (r) + , _metering (false) + , _muted_by_self (false) + , _muted_by_others (false) +{ +} + +/* reconstruct from XML */ + +Delivery::Delivery (Session& s, const XMLNode& node) + : IOProcessor (s, "reset") + , _role (Role (0)) + , _metering (false) + , _muted_by_self (false) + , _muted_by_others (false) +{ + if (set_state (node)) { + throw failed_constructor (); + } +} + + +bool +Delivery::visible () const +{ + if (_role & (Main|Solo)) { + return false; + } + + return true; +} + +bool +Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) const +{ + out = in; + return true; +} + +bool +Delivery::configure_io (ChanCount in, ChanCount out) +{ + if (out != in) { // always 1:1 + return false; + } + + return Processor::configure_io (in, out); +} + +void +Delivery::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) +{ + if (_io->n_outputs().get (_io->default_type()) == 0) { + return; + } + + if (!active() || _muted_by_self || _muted_by_others) { + silence (nframes); + if (_metering) { + _io->peak_meter().reset(); + } + } else { + + // we have to copy the input, because IO::deliver_output may alter the buffers + // in-place, which a send must never do. + + BufferSet& sendbufs = _session.get_mix_buffers (bufs.count()); + + sendbufs.read_from(bufs, nframes); + assert(sendbufs.count() == bufs.count()); + + _io->deliver_output (sendbufs, start_frame, end_frame, nframes); + + if (_metering) { + if (_io->effective_gain() == 0) { + _io->peak_meter().reset(); + } else { + _io->peak_meter().run_in_place(_io->output_buffers(), start_frame, end_frame, nframes); + } + } + } +} + +void +Delivery::set_metering (bool yn) +{ + _metering = yn; + + if (!_metering) { + /* XXX possible thread hazard here */ + _io->peak_meter().reset(); + } +} +void +Delivery::set_self_mute (bool yn) +{ + if (yn != _muted_by_self) { + _muted_by_self = yn; + SelfMuteChange (); // emit signal + } +} + +void +Delivery::set_nonself_mute (bool yn) +{ + if (yn != _muted_by_others) { + _muted_by_others = yn; + OtherMuteChange (); // emit signal + } +} + +XMLNode& +Delivery::state (bool full_state) +{ + XMLNode& node (IOProcessor::state (full_state)); + + if (_role & Main) { + node.add_property("type", "main-outs"); + } else if (_role & Listen) { + node.add_property("type", "listen"); + } else { + node.add_property("type", "delivery"); + } + + node.add_property("metering", (_metering ? "yes" : "no")); + node.add_property("self-muted", (_muted_by_self ? "yes" : "no")); + node.add_property("other-muted", (_muted_by_others ? "yes" : "no")); + node.add_property("role", enum_2_string(_role)); + + return node; +} + +int +Delivery::set_state (const XMLNode& node) +{ + const XMLProperty* prop; + + if ((prop = node.property ("role")) != 0) { + _role = Role (string_2_enum (prop->value(), _role)); + } + + if ((prop = node.property ("metering")) != 0) { + set_metering (prop->value() == "yes"); + } + + if ((prop = node.property ("self-muted")) != 0) { + set_self_mute (prop->value() == "yes"); + } + + if ((prop = node.property ("other-muted")) != 0) { + set_nonself_mute (prop->value() == "yes"); + } + + return 0; +} diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 841b2ad185..7767381499 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -20,6 +20,7 @@ #include "pbd/enumwriter.h" #include "ardour/types.h" +#include "ardour/delivery.h" #include "ardour/session.h" #include "ardour/location.h" #include "ardour/audiofilesource.h" @@ -103,6 +104,7 @@ setup_enum_writer () ExportFormatBase::SampleRate _ExportFormatBase_SampleRate; ExportFormatBase::SRCQuality _ExportFormatBase_SRCQuality; ExportProfileManager::TimeFormat _ExportProfileManager_TimeFormat; + Delivery::Role _Delivery_Role; #define REGISTER(e) enum_writer->register_distinct (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear() @@ -499,4 +501,10 @@ setup_enum_writer () REGISTER_CLASS_ENUM (ExportProfileManager, Frames); REGISTER_CLASS_ENUM (ExportProfileManager, Off); REGISTER (_ExportProfileManager_TimeFormat); + + REGISTER_CLASS_ENUM (Delivery, Solo); + REGISTER_CLASS_ENUM (Delivery, Send); + REGISTER_CLASS_ENUM (Delivery, Listen); + REGISTER_CLASS_ENUM (Delivery, Main); + REGISTER_BITS (_Delivery_Role); } diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 88b8aceb3f..cdd80b747d 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -221,7 +221,7 @@ IO::silence (nframes_t nframes) * to the outputs, eg applying gain or pan or whatever else needs to be done. */ void -IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) +IO::deliver_output (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { // Attach output buffers to port buffers output_buffers().attach_buffers (_outputs, nframes, _output_offset); @@ -317,7 +317,7 @@ IO::collect_input (BufferSet& outs, nframes_t nframes, ChanCount offset) } void -IO::just_meter_input (nframes_t start_frame, nframes_t end_frame, nframes_t nframes) +IO::just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { BufferSet& bufs = _session.get_scratch_buffers (n_inputs()); collect_input (bufs, nframes); @@ -866,7 +866,6 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src) { bool in_changed = false; bool out_changed = false; - bool need_pan_reset = false; assert(in != ChanCount::INFINITE); assert(out != ChanCount::INFINITE); @@ -887,10 +886,6 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src) Port* port; - if (n_outputs() != out) { - need_pan_reset = true; - } - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { const size_t nin = in.get(*t); diff --git a/libs/ardour/io_processor.cc b/libs/ardour/io_processor.cc index 53fbda24c7..2eac9dc88b 100644 --- a/libs/ardour/io_processor.cc +++ b/libs/ardour/io_processor.cc @@ -36,6 +36,7 @@ #include "ardour/port_insert.h" #include "ardour/plugin_insert.h" #include "ardour/io.h" +#include "ardour/route.h" #include "i18n.h" @@ -43,24 +44,22 @@ using namespace std; using namespace ARDOUR; using namespace PBD; +/* create an IOProcessor that proxies to a new IO object */ + IOProcessor::IOProcessor (Session& s, const string& proc_name, const string io_name, DataType dtype) : Processor(s, proc_name) - , _io (new IO(s, io_name != "" ? io_name : proc_name, dtype)) + , _io (new IO(s, io_name.empty() ? proc_name : io_name, dtype)) { - _active = false; - _sort_key = 0; - _gui = 0; - _extra_xml = 0; + _own_io = true; } +/* create an IOProcessor that proxies to an existing IO object */ + IOProcessor::IOProcessor (Session& s, IO* io, const string& proc_name, DataType dtype) : Processor(s, proc_name) , _io (io) { - _active = false; - _sort_key = 0; - _gui = 0; - _extra_xml = 0; + _own_io = false; } IOProcessor::~IOProcessor () @@ -68,12 +67,27 @@ IOProcessor::~IOProcessor () notify_callbacks (); } +void +IOProcessor::set_io (boost::shared_ptr io) +{ + /* CALLER MUST HOLD PROCESS LOCK */ + + _io = io; + _own_io = false; +} + XMLNode& IOProcessor::state (bool full_state) { - XMLNode& node = Processor::state(full_state); + XMLNode& node (Processor::state (full_state)); - node.add_child_nocopy (_io->state (full_state)); + if (_own_io) { + node.add_child_nocopy (_io->state (full_state)); + node.add_property ("own-io", "yes"); + } else { + node.add_property ("own-io", "no"); + node.add_property ("io", _io->name()); + } return node; } @@ -86,6 +100,35 @@ IOProcessor::set_state (const XMLNode& node) Processor::set_state(node); + if ((prop = node.property ("own-io")) != 0) { + _own_io = prop->value() == "yes"; + } + + /* don't attempt to set state for a proxied IO that we don't own */ + + if (!_own_io) { + + /* look up the IO object we're supposed to proxy to */ + + if ((prop = node.property ("io")) == 0) { + fatal << "IOProcessor has no named IO object" << endmsg; + /*NOTREACHED*/ + } + + boost::shared_ptr r = _session.route_by_name (prop->value()); + + if (!r) { + fatal << string_compose ("IOProcessor uses an unknown IO object called %1", prop->value()) << endmsg; + /*NOTREACHED*/ + } + + /* gotcha */ + + _io = boost::static_pointer_cast (r); + + return 0; + } + XMLNodeList nlist = node.children(); XMLNodeIterator niter; @@ -112,7 +155,7 @@ IOProcessor::set_state (const XMLNode& node) // legacy sessions: use IO name if ((prop = node.property ("name")) == 0) { - set_name(_io->name()); + set_name (_io->name()); } } else { @@ -126,7 +169,9 @@ IOProcessor::set_state (const XMLNode& node) void IOProcessor::silence (nframes_t nframes) { - _io->silence (nframes); + if (_own_io) { + _io->silence (nframes); + } } ChanCount @@ -156,6 +201,19 @@ IOProcessor::natural_input_streams () const void IOProcessor::automation_snapshot (nframes_t now, bool force) { - _io->automation_snapshot(now, force); + if (_own_io) { + _io->automation_snapshot(now, force); + } } +bool +IOProcessor::set_name (const std::string& name) +{ + bool ret = SessionObject::set_name (name); + + if (ret && _own_io) { + ret = _io->set_name (name); + } + + return ret; +} diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc index d8fee1ac47..371e0c5a90 100644 --- a/libs/ardour/meter.cc +++ b/libs/ardour/meter.cc @@ -38,7 +38,7 @@ namespace ARDOUR { * be set to 0. */ void -PeakMeter::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) +PeakMeter::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { const uint32_t n_audio = min(_configured_input.n_audio(), bufs.count().n_audio()); const uint32_t n_midi = min(_configured_input.n_midi(), bufs.count().n_midi()); @@ -171,15 +171,9 @@ PeakMeter::meter () XMLNode& PeakMeter::state (bool full_state) { - return get_state(); -} - -XMLNode& -PeakMeter::get_state() -{ - XMLNode* node = new XMLNode(state_node_name); - node->add_property("type", "meter"); - return *node; + XMLNode& node (Processor::state (full_state)); + node.add_property("type", "meter"); + return node; } } // namespace ARDOUR diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index f8d9f1eb58..6eaf01c819 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -52,6 +52,8 @@ #include "ardour/smf_source.h" #include "ardour/utils.h" +#include "midi++/types.h" + #include "i18n.h" #include @@ -419,6 +421,173 @@ MidiDiskstream::check_record_status (nframes_t transport_frame, nframes_t nframe last_possibly_recording = possibly_recording; } +static void +trace_midi (ostream& o, MIDI::byte *msg, size_t len) +{ + using namespace MIDI; + eventType type; + const char trace_prefix = ':'; + + type = (eventType) (msg[0]&0xF0); + + switch (type) { + case off: + o << trace_prefix + << "Channel " + << (msg[0]&0xF)+1 + << " NoteOff NoteNum " + << (int) msg[1] + << " Vel " + << (int) msg[2] + << endl; + break; + + case on: + o << trace_prefix + << "Channel " + << (msg[0]&0xF)+1 + << " NoteOn NoteNum " + << (int) msg[1] + << " Vel " + << (int) msg[2] + << endl; + break; + + case polypress: + o << trace_prefix + << "Channel " + << (msg[0]&0xF)+1 + << " PolyPressure" + << (int) msg[1] + << endl; + break; + + case MIDI::controller: + o << trace_prefix + << "Channel " + << (msg[0]&0xF)+1 + << " Controller " + << (int) msg[1] + << " Value " + << (int) msg[2] + << endl; + break; + + case program: + o << trace_prefix + << "Channel " + << (msg[0]&0xF)+1 + << " Program Change ProgNum " + << (int) msg[1] + << endl; + break; + + case chanpress: + o << trace_prefix + << "Channel " + << (msg[0]&0xF)+1 + << " Channel Pressure " + << (int) msg[1] + << endl; + break; + + case MIDI::pitchbend: + o << trace_prefix + << "Channel " + << (msg[0]&0xF)+1 + << " Pitch Bend " + << ((msg[2]<<7)|msg[1]) + << endl; + break; + + case MIDI::sysex: + if (len == 1) { + switch (msg[0]) { + case 0xf8: + o << trace_prefix + << "Clock" + << endl; + break; + case 0xfa: + o << trace_prefix + << "Start" + << endl; + break; + case 0xfb: + o << trace_prefix + << "Continue" + << endl; + break; + case 0xfc: + o << trace_prefix + << "Stop" + << endl; + break; + case 0xfe: + o << trace_prefix + << "Active Sense" + << endl; + break; + case 0xff: + o << trace_prefix + << "System Reset" + << endl; + break; + default: + o << trace_prefix + << "System Exclusive (1 byte : " << hex << (int) *msg << dec << ')' + << endl; + break; + } + } else { + o << trace_prefix + << "System Exclusive (" << len << ") = [ " << hex; + for (unsigned int i = 0; i < len; ++i) { + o << (int) msg[i] << ' '; + } + o << dec << ']' << endl; + + } + break; + + case MIDI::song: + o << trace_prefix << "Song" << endl; + break; + + case MIDI::tune: + o << trace_prefix << "Tune" << endl; + break; + + case MIDI::eox: + o << trace_prefix << "End-of-System Exclusive" << endl; + break; + + case MIDI::timing: + o << trace_prefix << "Timing" << endl; + break; + + case MIDI::start: + o << trace_prefix << "Start" << endl; + break; + + case MIDI::stop: + o << trace_prefix << "Stop" << endl; + break; + + case MIDI::contineu: + o << trace_prefix << "Continue" << endl; + break; + + case active: + o << trace_prefix << "Active Sense" << endl; + break; + + default: + o << trace_prefix << "Unrecognized MIDI message" << endl; + break; + } +} + int MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input) { diff --git a/libs/ardour/midi_state_tracker.cc b/libs/ardour/midi_state_tracker.cc index 2cb602db6f..66d356f9a6 100644 --- a/libs/ardour/midi_state_tracker.cc +++ b/libs/ardour/midi_state_tracker.cc @@ -30,6 +30,12 @@ MidiStateTracker::MidiStateTracker () _active_notes.reset(); } +void +MidiStateTracker::reset () +{ + _active_notes.reset (); +} + void MidiStateTracker::track_note_onoffs (const Evoral::MIDIEvent& event) { @@ -79,3 +85,16 @@ MidiStateTracker::resolve_notes (MidiBuffer &dst, nframes_t time) } } +void +MidiStateTracker::dump (ostream& o) +{ + o << "******\n"; + for (int c = 0; c < 16; ++c) { + for (int x = 0; x < 128; ++x) { + if (_active_notes[c * 128 + x]) { + o << "Channel " << c+1 << " Note " << x << " is on\n"; + } + } + } + o << "+++++\n"; +} diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 030e8ff905..6697e3b704 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -363,7 +363,7 @@ MidiTrack::set_state_part_two () } int -MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int declick, +MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input) { int dret; @@ -450,7 +450,7 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, } void -MidiTrack::write_controller_messages(MidiBuffer& output_buf, nframes_t start, nframes_t end, nframes_t nframes) +MidiTrack::write_controller_messages(MidiBuffer& output_buf, sframes_t start, sframes_t end, nframes_t nframes) { // Append immediate events (UI controls) @@ -460,7 +460,7 @@ MidiTrack::write_controller_messages(MidiBuffer& output_buf, nframes_t start, nf } int -MidiTrack::export_stuff (BufferSet& bufs, nframes_t nframes, nframes_t end_frame) +MidiTrack::export_stuff (BufferSet& bufs, nframes_t nframes, sframes_t end_frame) { return -1; } diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index 83923a44d6..73326e12a4 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -1419,7 +1419,7 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes } void -Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) +Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { if (outbufs.count().n_audio() == 0) { // Failing to deliver audio we were asked to deliver is a bug diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index a4a0a62e98..a78addf481 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -342,6 +342,7 @@ Playlist::notify_region_removed (boost::shared_ptr r) pending_length = false; LengthChanged (); /* EMIT SIGNAL */ pending_modified = false; + RegionRemoved (boost::weak_ptr (r)); /* EMIT SIGNAL */ Modified (); /* EMIT SIGNAL */ } } @@ -360,7 +361,6 @@ Playlist::notify_region_moved (boost::shared_ptr r) list< Evoral::RangeMove > m; m.push_back (move); RangesMoved (m); - } } @@ -380,6 +380,7 @@ Playlist::notify_region_added (boost::shared_ptr r) pending_length = false; LengthChanged (); /* EMIT SIGNAL */ pending_modified = false; + RegionAdded (boost::weak_ptr (r)); /* EMIT SIGNAL */ Modified (); /* EMIT SIGNAL */ } } @@ -420,21 +421,26 @@ Playlist::flush_notifications () // pending_bounds.sort (cmp); for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) { + if (Config->get_layer_model() == MoveAddHigher) { timestamp_layer_op (*r); } + pending_length = true; dependent_checks_needed.insert (*r); - n++; - } - for (s = pending_adds.begin(); s != pending_adds.end(); ++s) { - dependent_checks_needed.insert (*s); n++; } for (s = pending_removes.begin(); s != pending_removes.end(); ++s) { remove_dependents (*s); + RegionRemoved (boost::weak_ptr (*s)); /* EMIT SIGNAL */ + n++; + } + + for (s = pending_adds.begin(); s != pending_adds.end(); ++s) { + RegionAdded (boost::weak_ptr (*s)); /* EMIT SIGNAL */ + dependent_checks_needed.insert (*s); n++; } @@ -449,8 +455,7 @@ Playlist::flush_notifications () relayer (); } pending_modified = false; - Modified (); /* EMIT SIGNAL */ - + Modified (); /* EMIT SIGNAL */ } for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) { @@ -537,6 +542,7 @@ Playlist::add_region_internal (boost::shared_ptr region, nframes_t posit } RegionSortByPosition cmp; + nframes_t old_length = 0; if (!holding_state()) { @@ -567,7 +573,9 @@ Playlist::add_region_internal (boost::shared_ptr region, nframes_t posit notify_region_added (region); if (!holding_state ()) { + check_dependents (region, false); + if (old_length != _get_maximum_extent()) { notify_length_changed (); } @@ -1345,15 +1353,14 @@ Playlist::clear (bool with_signals) std::list::iterator i = region_state_changed_connections.begin (); i != region_state_changed_connections.end (); ++i - ) { - - i->disconnect (); - + ) { + i->disconnect (); } for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { pending_removes.insert (*i); } + regions.clear (); } diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index b6e3671ff2..6a6e9cf100 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -371,7 +371,7 @@ PluginInsert::silence (nframes_t nframes) } void -PluginInsert::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) +PluginInsert::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { if (active()) { diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index 0b5b9276f1..c0c854180f 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -127,7 +127,6 @@ PluginManager::PluginManager () } #ifdef HAVE_SLV2 - cerr << "LV2: Creating world" << endl; _lv2_world = new LV2World(); #endif diff --git a/libs/ardour/port_insert.cc b/libs/ardour/port_insert.cc index 73a70861ea..9d0d65ccd5 100644 --- a/libs/ardour/port_insert.cc +++ b/libs/ardour/port_insert.cc @@ -72,7 +72,7 @@ PortInsert::init () } void -PortInsert::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) +PortInsert::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { if (_io->n_outputs().n_total() == 0) { return; diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc index b48b0aebb0..84fb43d68c 100644 --- a/libs/ardour/processor.cc +++ b/libs/ardour/processor.cc @@ -64,6 +64,7 @@ Processor::Processor(Session& session, const string& name) , _active(false) , _next_ab_is_active(false) , _configured(false) + , _sort_key (0) , _gui(0) { } @@ -99,17 +100,16 @@ Processor::state (bool full_state) { XMLNode* node = new XMLNode (state_node_name); stringstream sstr; - - // FIXME: This conflicts with "id" used by plugin for name in legacy sessions (ugh). - // Do we need to serialize this? - /* char buf[64]; + + // NOTE: This conflicts with "id" used by plugin for name in legacy sessions + id().print (buf, sizeof (buf)); node->add_property("id", buf); - */ - node->add_property("name", _name); node->add_property("active", active() ? "yes" : "no"); + snprintf (buf, sizeof (buf), "%u", _sort_key); + node->add_property("sort-key", buf); if (_extra_xml){ node->add_child_copy (*_extra_xml); @@ -144,11 +144,16 @@ Processor::set_state (const XMLNode& node) const XMLProperty *legacy_active = 0; const XMLProperty *legacy_placement = 0; - // may not exist for legacy sessions + // may not exist for legacy 3.0 sessions if ((prop = node.property ("name")) != 0) { set_name(prop->value()); } + // may not exist for legacy 3.0 sessions + if ((prop = node.property ("id")) != 0) { + _id = prop->value(); + } + XMLNodeList nlist = node.children(); XMLNodeIterator niter; diff --git a/libs/ardour/return.cc b/libs/ardour/return.cc index fdc2b259e1..1f228d01ca 100644 --- a/libs/ardour/return.cc +++ b/libs/ardour/return.cc @@ -106,7 +106,7 @@ Return::set_state(const XMLNode& node) } void -Return::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) +Return::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { if (active()) { _io->collect_input (bufs, nframes, _configured_input); diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 931ae9a996..db06368371 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "pbd/xml++.h" @@ -35,7 +36,6 @@ #include "ardour/buffer.h" #include "ardour/buffer_set.h" #include "ardour/configuration.h" -#include "ardour/control_outputs.h" #include "ardour/cycle_timer.h" #include "ardour/dB.h" #include "ardour/ladspa_plugin.h" @@ -64,7 +64,7 @@ uint32_t Route::order_key_cnt = 0; sigc::signal Route::SyncOrderKeys; Route::Route (Session& sess, string name, Flag flg, - DataType default_type, ChanCount in, ChanCount out) + DataType default_type, ChanCount in, ChanCount out) : IO (sess, name, default_type, in, ChanCount::INFINITE, out, ChanCount::INFINITE) , _flags (flg) , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)) @@ -73,6 +73,7 @@ Route::Route (Session& sess, string name, Flag flg, _configured_inputs = in; _configured_outputs = out; init (); + } Route::Route (Session& sess, const XMLNode& node, DataType default_type) @@ -123,11 +124,19 @@ Route::init () input_changed.connect (mem_fun (this, &Route::input_change_handler)); output_changed.connect (mem_fun (this, &Route::output_change_handler)); + + /* add standard processors: amp, meter, main outs */ + + /* amp & meter belong to IO but need to be added to our processor list */ _amp->set_sort_key (0); _meter->set_sort_key (1); - add_processor (_amp, NULL); - add_processor (_meter, NULL); + add_processor (_amp); + add_processor (_meter); + + _main_outs.reset (new Delivery (_session, this, _name, Delivery::Main)); + ProcessorList::iterator i = _processors.end(); + add_processor (_main_outs, 0, &i); } Route::~Route () @@ -294,8 +303,8 @@ Route::set_gain (gain_t val, void *src) */ void Route::process_output_buffers (BufferSet& bufs, - nframes_t start_frame, nframes_t end_frame, nframes_t nframes, - bool with_processors, int declick) + sframes_t start_frame, sframes_t end_frame, nframes_t nframes, + bool with_processors, int declick) { ProcessorList::iterator i; bool mute_declick_applied = false; @@ -345,9 +354,8 @@ Route::process_output_buffers (BufferSet& bufs, || Config->get_monitoring_model() == SoftwareMonitoring); // mute at the amp if... - _amp->apply_mute( - !_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader, - mute_gain, dmg); + _amp->apply_mute (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader, + mute_gain, dmg); _amp->set_gain (_gain, dg); @@ -356,16 +364,31 @@ Route::process_output_buffers (BufferSet& bufs, SET UP CONTROL OUTPUTS ----------------------------------------------------------------------------------------- */ - boost::shared_ptr co = _control_outs; + boost::shared_ptr co = _control_outs; if (co) { // deliver control outputs unless we're ... - co->deliver (!( - dsg == 0 || // muted by solo of another track - (dmg == 0 && _mute_affects_control_outs) || // or muted by mute of this track - !recording_without_monitoring )); // or rec-enabled w/o s/w monitoring + bool self_mute = ((dmg == 0 && _mute_affects_control_outs) || // or muted by mute of this track + !recording_without_monitoring); // or rec-enabled w/o s/w monitoring + bool other_mute = (dsg == 0); // muted by solo of another track + + co->set_self_mute (self_mute); + co->set_nonself_mute (other_mute); } - + /* ------------------------------------------------------------------------------------------- + SET UP MAIN OUTPUT STAGE + ----------------------------------------------------------------------------------------- */ + + bool solo_audible = dsg > 0; + bool mute_audible = dmg > 0 || !_mute_affects_main_outs; + + bool silent_anyway = (_gain == 0 && !_amp->apply_gain_automation()); + bool muted_by_other_solo = (!solo_audible && (Config->get_solo_model() != SoloBus)); + bool muted_by_self = !mute_audible; + + _main_outs->set_nonself_mute (recording_without_monitoring || muted_by_other_solo || silent_anyway); + _main_outs->set_self_mute (muted_by_self); + /* ------------------------------------------------------------------------------------------- GLOBAL DECLICK (for transport changes etc.) ----------------------------------------------------------------------------------------- */ @@ -413,33 +436,23 @@ Route::process_output_buffers (BufferSet& bufs, } } - /* ------------------------------------------------------------------------------------------- - PROCESSORS (including Amp (fader) and Meter) + and go .... ----------------------------------------------------------------------------------------- */ - if (with_processors) { - Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); - if (rm.locked()) { - //if (!bufs.is_silent()) { - for (i = _processors.begin(); i != _processors.end(); ++i) { - bufs.set_count(ChanCount::max(bufs.count(), (*i)->input_streams())); - (*i)->run_in_place (bufs, start_frame, end_frame, nframes); - bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams())); - } - /*} else { - for (i = _processors.begin(); i != _processors.end(); ++i) { - (*i)->silence (nframes); - bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams())); - } - }*/ - } + Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); + + if (rm.locked()) { + for (i = _processors.begin(); i != _processors.end(); ++i) { + bufs.set_count(ChanCount::max(bufs.count(), (*i)->input_streams())); + (*i)->run_in_place (bufs, start_frame, end_frame, nframes); + bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams())); + } if (!_processors.empty()) { bufs.set_count(ChanCount::max(bufs.count(), _processors.back()->output_streams())); } } - /* ------------------------------------------------------------------------------------------- POST-FADER MUTING @@ -450,64 +463,11 @@ Route::process_output_buffers (BufferSet& bufs, mute_gain = dmg; mute_declick_applied = true; } + if (mute_gain == 0.0f && dmg == 0.0f) { bufs.is_silent(true); } - - /* ------------------------------------------------------------------------------------------- - MAIN OUTPUT STAGE - ----------------------------------------------------------------------------------------- */ - - bool solo_audible = dsg > 0; - bool mute_audible = dmg > 0 || !_mute_affects_main_outs; - - if (n_outputs().get(_default_type) == 0) { - - /* relax */ - - } else if (recording_without_monitoring) { - - IO::silence (nframes); - - } else { - - if ( // we're silent anyway - (_gain == 0 && !_amp->apply_gain_automation()) || - - // or muted by solo of another track, but not using control outs for solo - (!solo_audible && (Config->get_solo_model() != SoloBus)) || - - // or muted by mute of this track - !mute_audible - ) { - - /* don't use Route::silence() here, because that causes - all outputs (sends, port processors, etc. to be silent). - */ - IO::silence (nframes); - - } else { - - deliver_output(bufs, start_frame, end_frame, nframes); - - } - - } - - /* ------------------------------------------------------------------------------------------- - POST-FADER METERING - ----------------------------------------------------------------------------------------- */ - - /* TODO: Processor-list-ification needs to go further for this to be cleanly possible... - if (meter && (_meter_point == MeterPostFader)) { - if ((_gain == 0 && !apply_gain_automation) || dmg == 0) { - _meter->reset(); - } else { - _meter->run_in_place(output_buffers(), start_frame, end_frame, nframes); - } - }*/ - // at this point we've reached the desired mute gain regardless mute_gain = dmg; } @@ -527,7 +487,7 @@ Route::setup_peak_meters() } void -Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick) +Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, int declick) { BufferSet& bufs = _session.get_scratch_buffers(n_process_buffers()); @@ -539,7 +499,7 @@ Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, } void -Route::passthru_silence (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick) +Route::passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, int declick) { process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, true, declick); } @@ -643,13 +603,26 @@ dump_processors(const string& name, const list >& p cerr << "}" << endl; } + +struct ProcessorSortByKey { + bool operator() (boost::shared_ptr a, boost::shared_ptr b) { + return a->sort_key() < b->sort_key(); + } +}; + +uint32_t +Route::fader_sort_key() const +{ + return _amp->sort_key(); +} + /** Add a processor to the route. * If @a iter is not NULL, it must point to an iterator in _processors and the new * processor will be inserted immediately before this location. Otherwise, * @a position is used. */ int -Route::add_processor (boost::shared_ptr processor, ProcessorStreams* err, ProcessorList::iterator* iter, Placement placement) +Route::add_processor (boost::shared_ptr processor, ProcessorStreams* err, ProcessorList::iterator* iter) { ChanCount old_pms = processor_max_streams; @@ -657,6 +630,10 @@ Route::add_processor (boost::shared_ptr processor, ProcessorStreams* return 1; } + cerr << "Adding a processor called " << processor->name() << " sk = " << processor->sort_key() + << ((iter == 0) ? " NO given position " : " with given position") + << endl; + { Glib::RWLock::WriterLock lm (_processor_lock); @@ -665,8 +642,8 @@ Route::add_processor (boost::shared_ptr processor, ProcessorStreams* ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), processor); - if (processor == _amp || processor == _meter) { - // Ensure only one amp and one meter are in the list at any time + if (processor == _amp || processor == _meter || processor == _main_outs) { + // Ensure only one of these are in the list at any time if (loc != _processors.end()) { if (iter) { if (*iter == loc) { // Already in place, do nothing @@ -687,17 +664,21 @@ Route::add_processor (boost::shared_ptr processor, ProcessorStreams* } } - // Use position given by user if (iter) { + // Use position given by user loc = *iter; - - // Insert immediately before the amp - } else if (placement == PreFader) { - loc = find(_processors.begin(), _processors.end(), _amp); - - // Insert at end } else { - loc = _processors.end(); + if (processor->sort_key() == 0) { + /* generic pre-fader: insert immediately before the amp */ + loc = find(_processors.begin(), _processors.end(), _amp); + } else if (processor->sort_key() > _processors.size()) { + /* generic post-fader: insert at end */ + loc = _processors.end(); + } else { + /* find insert point */ + ProcessorSortByKey cmp; + loc = upper_bound (_processors.begin(), _processors.end(), processor, cmp); + } } // Update sort keys @@ -715,11 +696,12 @@ Route::add_processor (boost::shared_ptr processor, ProcessorStreams* // Set up processor list channels. This will set processor->[input|output]_streams(), // configure redirect ports properly, etc. if (configure_processors_unlocked (err)) { - dump_processors(_name, _processors); + dump_processors(_name + "bad config", _processors); ProcessorList::iterator ploc = loc; --ploc; _processors.erase(ploc); configure_processors_unlocked (0); // it worked before we tried to add it ... + cerr << "Bad IO config\n"; return -1; } @@ -733,8 +715,7 @@ Route::add_processor (boost::shared_ptr processor, ProcessorStreams* } // Ensure peak vector sizes before the plugin is activated - ChanCount potential_max_streams = ChanCount::max( - processor->input_streams(), processor->output_streams()); + ChanCount potential_max_streams = ChanCount::max (processor->input_streams(), processor->output_streams()); _meter->configure_io (potential_max_streams, potential_max_streams); @@ -749,15 +730,14 @@ Route::add_processor (boost::shared_ptr processor, ProcessorStreams* reset_panner (); } - dump_processors (_name, _processors); + dump_processors (_name + " added one", _processors); processors_changed (); /* EMIT SIGNAL */ - return 0; } int -Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Placement placement) +Route::add_processors (const ProcessorList& others, ProcessorStreams* err, uint32_t first_sort_key) { /* NOTE: this is intended to be used ONLY when copying processors from another Route. Hence the subtle @@ -773,10 +753,26 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Place { Glib::RWLock::WriterLock lm (_processor_lock); + ProcessorList::iterator loc; ProcessorList::iterator existing_end = _processors.end(); --existing_end; ChanCount potential_max_streams = ChanCount::max(input_minimum(), output_minimum()); + + if (first_sort_key == 0) { + /* generic pre-fader: insert immediately before the amp */ + cerr << "Add new procs at amp, sk = " << first_sort_key << endl; + loc = find(_processors.begin(), _processors.end(), _amp); + } else if (first_sort_key > _processors.size()) { + /* generic post-fader: insert at end */ + cerr << "Add new procs at end, sk = " << first_sort_key << endl; + loc = _processors.end(); + } else { + /* find insert point */ + ProcessorSortByKey cmp; + cerr << "Add new procs at sk = " << first_sort_key << endl; + loc = upper_bound (_processors.begin(), _processors.end(), others.front(), cmp); + } for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) { @@ -800,11 +796,7 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Place // Ensure peak vector sizes before the plugin is activated _meter->configure_io (potential_max_streams, potential_max_streams); - - ProcessorList::iterator loc = (placement == PreFader) - ? find(_processors.begin(), _processors.end(), _amp) - : _processors.end(); - + _processors.insert (loc, *i); if (configure_processors_unlocked (err)) { @@ -824,7 +816,7 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Place reset_panner (); } - dump_processors (_name, _processors); + dump_processors (_name + " added several", _processors); processors_changed (); /* EMIT SIGNAL */ return 0; @@ -1003,7 +995,8 @@ Route::clear_processors (Placement p) { Glib::RWLock::WriterLock lm (_processor_lock); ProcessorList new_list; - + ProcessorStreams err; + ProcessorList::iterator amp_loc = find(_processors.begin(), _processors.end(), _amp); if (p == PreFader) { // Get rid of PreFader processors @@ -1027,9 +1020,9 @@ Route::clear_processors (Placement p) } _processors = new_list; + configure_processors_unlocked (&err); // this can't fail } - /* FIXME: can't see how this test can ever fire */ if (processor_max_streams != old_pms) { reset_panner (); } @@ -1046,7 +1039,9 @@ Route::clear_processors (Placement p) int Route::remove_processor (boost::shared_ptr processor, ProcessorStreams* err) { - if (processor == _amp || processor == _meter) { + /* these can never be removed */ + + if (processor == _amp || processor == _meter || processor == _main_outs) { return 0; } @@ -1063,18 +1058,13 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream ProcessorList::iterator i; bool removed = false; - for (i = _processors.begin(); i != _processors.end(); ++i) { + for (i = _processors.begin(); i != _processors.end(); ) { if (*i == processor) { - ProcessorList::iterator tmp; - /* move along, see failure case for configure_processors() where we may need to reprocessor the processor. */ - tmp = i; - ++tmp; - /* stop redirects that send signals to JACK ports from causing noise as a result of no longer being run. @@ -1086,12 +1076,13 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream redirect->io()->disconnect_inputs (this); redirect->io()->disconnect_outputs (this); } - - _processors.erase (i); - - i = tmp; + + i = _processors.erase (i); removed = true; break; + + } else { + ++i; } _user_latency = 0; @@ -1130,7 +1121,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream processor->drop_references (); - dump_processors (_name, _processors); + dump_processors (_name + " removed one", _processors); processors_changed (); /* EMIT SIGNAL */ return 0; @@ -1252,17 +1243,11 @@ Route::all_processors_active (Placement p, bool state) _session.set_dirty (); } -struct ProcessorSorter { - bool operator() (boost::shared_ptr a, boost::shared_ptr b) { - return a->sort_key() < b->sort_key(); - } -}; - int Route::sort_processors (ProcessorStreams* err) { { - ProcessorSorter comparator; + ProcessorSortByKey comparator; Glib::RWLock::WriterLock lm (_processor_lock); ChanCount old_pms = processor_max_streams; @@ -1270,6 +1255,8 @@ Route::sort_processors (ProcessorStreams* err) ProcessorList as_it_was_before = _processors; + dump_processors (_name + " PRESORT", _processors); + _processors.sort (comparator); if (configure_processors_unlocked (err)) { @@ -1279,6 +1266,7 @@ Route::sort_processors (ProcessorStreams* err) } } + dump_processors (_name + " sorted", _processors); reset_panner (); processors_changed (); /* EMIT SIGNAL */ @@ -1356,12 +1344,6 @@ Route::state(bool full_state) remote_control_node->add_property (X_("id"), buf); node->add_child_nocopy (*remote_control_node); - if (_control_outs) { - XMLNode* cnode = new XMLNode (X_("ControlOuts")); - cnode->add_child_nocopy (_control_outs->io()->state (full_state)); - node->add_child_nocopy (*cnode); - } - if (_comment.length()) { XMLNode *cmt = node->add_child ("Comment"); cmt->add_content (_comment); @@ -1517,7 +1499,17 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator* ite } else if (prop->value() == "amp") { processor = _amp; + + } else if (prop->value() == "listen" || prop->value() == "deliver") { + /* XXX need to generalize */ + + processor = _control_outs; + + } else if (prop->value() == "main-outs") { + + processor = _main_outs; + } else { error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; @@ -1712,27 +1704,8 @@ Route::_set_state (const XMLNode& node, bool call_base) } } else if (child->name() == X_("ControlOuts")) { - - string coutname = _name; - coutname += _("[control]"); - _control_outs = boost::shared_ptr ( - new ControlOutputs (_session, new IO (_session, coutname))); - - /* fix up the control out name in the XML before setting it. - Otherwise track templates don't work because the control - outs end up with the stored template name, rather than - the new name of the track based on the template. - */ - - XMLProperty* prop = (*child->children().begin())->property ("name"); - if (prop) { - prop->set_value (coutname); - } - - _control_outs->io()->set_state (**(child->children().begin())); - _control_outs->set_sort_key (_meter->sort_key() + 1); - add_processor (_control_outs, 0); + /* ignore this - deprecated */ } else if (child->name() == X_("Comment")) { @@ -1779,7 +1752,6 @@ void Route::_set_processor_states(const XMLNodeList &nlist) { XMLNodeConstIterator niter; - char buf[64]; ProcessorList::iterator i, o; @@ -1790,21 +1762,12 @@ Route::_set_processor_states(const XMLNodeList &nlist) bool processorInStateList = false; - (*i)->id().print (buf, sizeof (buf)); - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - // legacy sessions (IOProcessor as a child of Processor, both is-a IO) - XMLNode* ioproc_node = (*niter)->child(X_("IOProcessor")); - if (ioproc_node && strncmp(buf, ioproc_node->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) { + XMLProperty* id_prop = (*niter)->property(X_("id")); + if (id_prop && (*i)->id() == id_prop->value()) { processorInStateList = true; break; - } else { - XMLProperty* id_prop = (*niter)->property(X_("id")); - if (id_prop && strncmp(buf, id_prop->value().c_str(), sizeof(buf)) == 0) { - processorInStateList = true; - } - break; } } @@ -1815,56 +1778,53 @@ Route::_set_processor_states(const XMLNodeList &nlist) i = tmp; } - Placement placement = PreFader; - // Iterate through state list and make sure all processors are on the track and in the correct order, // set the state of existing processors according to the new state on the same go i = _processors.begin(); - for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) { - // Check whether the next processor in the list + for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) { + + XMLProperty* prop = (*niter)->property ("type"); + o = i; - while (o != _processors.end()) { - (*o)->id().print (buf, sizeof (buf)); - XMLNode* ioproc_node = (*niter)->child(X_("IOProcessor")); - if (ioproc_node && strncmp(buf, ioproc_node->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) { - break; - } else { + if (prop->value() != "meter" && prop->value() != "amp" && prop->value() != "main-outs") { + + // Check whether the next processor in the list + + while (o != _processors.end()) { XMLProperty* id_prop = (*niter)->property(X_("id")); - if (id_prop && strncmp(buf, id_prop->value().c_str(), sizeof(buf)) == 0) { + if (id_prop && (*o)->id() == id_prop->value()) { break; } + + ++o; } - - ++o; } // If the processor (*niter) is not on the route, // create it and move it to the correct location if (o == _processors.end()) { + if (add_processor_from_xml (**niter, &i)) { --i; // move iterator to the newly inserted processor } else { cerr << "Error restoring route: unable to restore processor" << endl; } - // Otherwise, we found the processor (*niter) on the route, + // Otherwise, the processor already exists; just // ensure it is at the location provided in the XML state } else { if (i != o) { boost::shared_ptr tmp = (*o); - _processors.erase(o); // remove the old copy - _processors.insert(i, tmp); // insert the processor at the correct location + cerr << "move proc from state\n"; + _processors.erase (o); // remove the old copy + _processors.insert (i, tmp); // insert the processor at the correct location --i; // move iterator to the correct processor } - (*i)->set_state((**niter)); - } - - if (*i == _amp) { - placement = PostFader; + (*i)->set_state (**niter); } } } @@ -1882,22 +1842,19 @@ Route::silence (nframes_t nframes) if (!_silent) { IO::silence (nframes); - - if (_control_outs) { - _control_outs->io()->silence (nframes); - } - + { Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); if (lm.locked()) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { boost::shared_ptr pi; + if (!_active && (pi = boost::dynamic_pointer_cast (*i)) != 0) { // skip plugins, they don't need anything when we're not active continue; } - + (*i)->silence (nframes); } @@ -1910,52 +1867,109 @@ Route::silence (nframes_t nframes) } } -int -Route::set_control_outs (const vector& ports) +boost::shared_ptr +Route::add_listener (boost::shared_ptr io, const string& listen_name) { - vector::const_iterator i; - - if (is_control() || is_master()) { - /* no control outs for these two special busses */ - return 0; - } + string name = _name; + name += '['; + name += listen_name; + name += ']'; - if (ports.empty()) { - return 0; - } - - string coutname = _name; - coutname += _("[control]"); - - IO* out_io = new IO (_session, coutname); - boost::shared_ptr out_proc(new ControlOutputs (_session, out_io)); + boost::shared_ptr listener (new Delivery (_session, name, Delivery::Listen)); /* As an IO, our control outs need as many IO outputs as we have outputs * (we track the changes in ::output_change_handler()). - * As a processor, the control outs is an identity processor + * As a processor, the listener is an identity processor * (i.e. it does not modify its input buffers whatsoever) */ - if (out_io->ensure_io (ChanCount::ZERO, n_outputs(), true, this)) { - return -1; + + if (listener->io()->ensure_io (ChanCount::ZERO, n_outputs(), true, this)) { + return boost::shared_ptr(); } + + listener->set_sort_key (_meter->sort_key() + 1); + add_processor (listener, NULL); + + return listener; +} + +int +Route::listen_via (boost::shared_ptr io, const string& listen_name) +{ + vector ports; + vector::const_iterator i; + + { + Glib::RWLock::ReaderLock rm (_processor_lock); + + for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) { + boost::shared_ptr d = boost::dynamic_pointer_cast(*x); + + if (d && d->io() == io) { + /* already listening via the specified IO: do nothing */ + return 0; + } + } + } + + uint32_t ni = io->n_inputs().n_total(); + + for (uint32_t n = 0; n < ni; ++n) { + ports.push_back (io->input(n)->name()); + } + + if (ports.empty()) { + return 0; + } + + boost::shared_ptr listen_point = add_listener (io, listen_name); + + /* XXX hack for now .... until we can generalize listen points */ + + _control_outs = listen_point; /* now connect to the named ports */ - for (size_t n = 0; n < n_outputs().n_total(); ++n) { - if (out_io->connect_output (out_io->output (n), ports[n % ports.size()], this)) { + ni = listen_point->io()->n_outputs().n_total(); + size_t psize = ports.size(); + + for (size_t n = 0; n < ni; ++n) { + if (listen_point->io()->connect_output (listen_point->io()->output (n), ports[n % psize], this)) { error << string_compose (_("could not connect %1 to %2"), - out_io->output(n)->name(), ports[n]) << endmsg; + listen_point->io()->output(n)->name(), ports[n % psize]) << endmsg; return -1; } } - _control_outs = out_proc; - _control_outs->set_sort_key (_meter->sort_key() + 1); - add_processor (_control_outs, NULL); - + return 0; } +void +Route::drop_listen (boost::shared_ptr io) +{ + ProcessorStreams err; + ProcessorList::iterator tmp; + + Glib::RWLock::ReaderLock rm (_processor_lock); + + for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) { + + tmp = x; + ++tmp; + + boost::shared_ptr d = boost::dynamic_pointer_cast(*x); + + if (d && d->io() == io) { + /* already listening via the specified IO: do nothing */ + remove_processor (*x, &err); + + } + + x = tmp; + } +} + void Route::set_edit_group (RouteGroup *eg, void *src) @@ -2041,33 +2055,17 @@ Route::feeds (boost::shared_ptr other) for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) { - boost::shared_ptr redirect = boost::dynamic_pointer_cast(*r); - - if ( ! redirect) + boost::shared_ptr proc = boost::dynamic_pointer_cast(*r); + + if (!proc) { continue; - - // TODO: support internal redirects here - - no = redirect->io()->n_outputs().n_total(); - - for (i = 0; i < no; ++i) { - for (j = 0; j < ni; ++j) { - if (redirect->io()->output(i)->connected_to (other->input (j)->name())) { - return true; - } - } } - } - - /* check for control room outputs which may also interconnect Routes */ - - if (_control_outs) { - - no = _control_outs->io()->n_outputs().n_total(); + + no = proc->io()->n_outputs().n_total(); for (i = 0; i < no; ++i) { for (j = 0; j < ni; ++j) { - if (_control_outs->io()->output(i)->connected_to (other->input (j)->name())) { + if (proc->io()->output(i)->connected_to (other->input (j)->name())) { return true; } } @@ -2185,7 +2183,7 @@ Route::pans_required () const } int -Route::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, +Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool session_state_changing, bool can_record, bool rec_monitors_input) { if (n_outputs().n_total() == 0) { @@ -2236,7 +2234,7 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame) } int -Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int declick, +Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input) { { @@ -2282,7 +2280,7 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int } int -Route::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, +Route::silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool can_record, bool rec_monitors_input) { silence (nframes); @@ -2602,3 +2600,36 @@ Route::save_as_template (const string& path, const string& name) tree.set_root (&node); return tree.write (path.c_str()); } + + +bool +Route::set_name (const string& str) +{ + bool ret; + string ioproc_name; + + if ((ret = IO::set_name (str)) == true) { + Glib::RWLock::ReaderLock lm (_processor_lock); + + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + + /* rename all delivery objects to reflect our new name */ + + boost::shared_ptr dp = boost::dynamic_pointer_cast (*i); + + if (dp) { + string dp_name = str; + dp_name += '['; + dp_name += "XXX FIX ME XXX"; + dp_name += ']'; + + if (!dp->set_name (dp_name)) { + ret = false; + } + } + } + + } + + return ret; +} diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc index 2c28fb5dcd..e4de26e864 100644 --- a/libs/ardour/send.cc +++ b/libs/ardour/send.cc @@ -36,17 +36,14 @@ using namespace ARDOUR; using namespace PBD; Send::Send (Session& s) - : IOProcessor (s, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1)) + : Delivery (s, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send) { - _metering = false; ProcessorCreated (this); /* EMIT SIGNAL */ } Send::Send (Session& s, const XMLNode& node) - : IOProcessor (s, "send") + : Delivery (s, "send", Delivery::Send) { - _metering = false; - if (set_state (node)) { throw failed_constructor(); } @@ -96,7 +93,7 @@ Send::set_state(const XMLNode& node) /* Send has regular IO automation (gain, pan) */ for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - if ((*niter)->name() == "IOProcessor") { + if ((*niter)->name() == IOProcessor::state_node_name) { insert_node = *niter; } else if ((*niter)->name() == X_("Automation")) { // _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation)); @@ -108,41 +105,6 @@ Send::set_state(const XMLNode& node) return 0; } -void -Send::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes) -{ - if (active()) { - - _io->deliver_output (bufs, start_frame, end_frame, nframes); - - if (_metering) { - if (_io->effective_gain() == 0) { - _io->peak_meter().reset(); - } else { - _io->peak_meter().run_in_place(_io->output_buffers(), start_frame, end_frame, nframes); - } - } - - } else { - _io->silence (nframes); - - if (_metering) { - _io->peak_meter().reset(); - } - } -} - -void -Send::set_metering (bool yn) -{ - _metering = yn; - - if (!_metering) { - /* XXX possible thread hazard here */ - _io->peak_meter().reset(); - } -} - bool Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 302bf87f64..3105b776dc 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -136,7 +136,6 @@ Session::Session (AudioEngine &eng, midi_requests (128), // the size of this should match the midi request pool size diskstreams (new DiskstreamList), routes (new RouteList), - auditioner ((Auditioner*) 0), _total_free_4k_blocks (0), _bundles (new BundleList), _bundle_xml_node (0), @@ -223,7 +222,6 @@ Session::Session (AudioEngine &eng, midi_requests (16), diskstreams (new DiskstreamList), routes (new RouteList), - auditioner ((Auditioner *) 0), _total_free_4k_blocks (0), _bundles (new BundleList), _bundle_xml_node (0), @@ -281,6 +279,7 @@ Session::Session (AudioEngine &eng, if (master_out_channels) { ChanCount count(DataType::AUDIO, master_out_channels); + cerr << "new MO with " << count << endl; shared_ptr r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO, count, count)); r->set_remote_control_id (control_id); @@ -526,8 +525,6 @@ Session::when_engine_running () { string first_physical_output; - /* we don't want to run execute this again */ - BootMessage (_("Set block size and sample rate")); set_block_size (_engine.frames_per_cycle()); @@ -609,7 +606,8 @@ Session::when_engine_running () mono and stereo bundles, so that the common cases of mono and stereo tracks get bundles to put in their mixer strip in / out menus. There may be a nicer way of achieving that; - it doesn't really scale that well to higher channel counts */ + it doesn't really scale that well to higher channel counts + */ for (uint32_t np = 0; np < n_physical_outputs; ++np) { char buf[32]; @@ -662,28 +660,37 @@ Session::when_engine_running () } } + /* create master/control ports */ + if (_master_out) { - /* create master/control ports */ - - if (_master_out) { - /* force the master to ignore any later call to this */ - if (_master_out->pending_state_node) { - _master_out->ports_became_legal(); - } - - /* no panner resets till we are through */ - _master_out->defer_pan_reset (); + /* force the master to ignore any later call to this + */ + if (_master_out->pending_state_node) { + _master_out->ports_became_legal(); + } + + /* create ports, without any connections + */ + _master_out->ensure_io (_master_out->input_minimum (), _master_out->output_minimum (), true, this); - /* create ports */ - _master_out->set_input_minimum(ChanCount(DataType::AUDIO, n_physical_inputs)); - _master_out->set_output_minimum(ChanCount(DataType::AUDIO, n_physical_outputs)); - _master_out->ensure_io ( - _master_out->input_minimum (), _master_out->output_minimum (), - true, this); + /* if requested auto-connect the outputs to the first N physical ports. + */ + if (Config->get_auto_connect_master()) { + uint32_t limit = _master_out->n_outputs().n_total(); - _master_out->allow_pan_reset (); + for (uint32_t n = 0; n < limit; ++n) { + Port* p = _master_out->output (n); + string connect_to = _engine.get_nth_physical_output (DataType (p->type()), n); + if (!connect_to.empty()) { + if (_master_out->connect_output (p, connect_to, this)) { + error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to) + << endmsg; + break; + } + } + } } } @@ -739,7 +746,7 @@ Session::hookup_io () _state_of_the_state = StateOfTheState (_state_of_the_state | InitialConnecting); - if (auditioner == 0) { + if (!auditioner) { /* we delay creating the auditioner till now because it makes its own connections to ports. @@ -759,23 +766,21 @@ Session::hookup_io () IO::enable_ports (); - if (_control_out) { - vector cports; - - _control_out->ensure_io( - _control_out->input_minimum(), _control_out->output_minimum(), - false, this); + /* Connect track to listen/solo etc. busses XXX generalize this beyond control_out */ - uint32_t ni = _control_out->n_inputs().get (DataType::AUDIO); + if (_control_out) { - for (uint32_t n = 0; n < ni; ++n) { - cports.push_back (_control_out->input(n)->name()); - } + _control_out->ensure_io (_control_out->input_minimum(), _control_out->output_minimum(), false, this); boost::shared_ptr r = routes.reader (); - + for (RouteList::iterator x = r->begin(); x != r->end(); ++x) { - (*x)->set_control_outs (cports); + + boost::shared_ptr t = boost::dynamic_pointer_cast (*x); + + if (t) { + t->listen_via (_control_out, X_("listen")); + } } } @@ -2081,15 +2086,8 @@ Session::add_routes (RouteList& new_routes, bool save) if (_control_out && IO::connecting_legal) { - vector cports; - uint32_t ni = _control_out->n_inputs().n_audio(); - - for (uint32_t n = 0; n < ni; ++n) { - cports.push_back (_control_out->input(n)->name()); - } - for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { - (*x)->set_control_outs (cports); + (*x)->listen_via (_control_out, "control"); } } @@ -2146,15 +2144,13 @@ Session::remove_route (shared_ptr route) } if (route == _control_out) { - _control_out = shared_ptr (); - /* cancel control outs for all routes */ - vector empty; - for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) { - (*r)->set_control_outs (empty); + (*r)->drop_listen (_control_out); } + + _control_out = shared_ptr (); } update_route_solo_state (); diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 55c09f7ed8..790d990bc2 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -805,6 +805,10 @@ Session::set_transport_speed (double speed, bool abort) } target_phi = (uint64_t) (0x1000000 * fabs(speed)); + + /* 8.0 max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability + and user needs. We really need CD-style "skip" playback for ffwd and rewind. + */ if (speed > 0) { speed = min (8.0, speed); diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 1e344403b1..fd9267ede4 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -214,8 +214,8 @@ Track::set_name (const string& str) } /* save state so that the statefile fully reflects any filename changes */ - - if ((ret = IO::set_name (str)) == 0) { + + if ((ret = Route::set_name (str)) == 0) { _session.save_state (""); } @@ -238,8 +238,8 @@ Track::zero_diskstream_id_in_xml (XMLNode& node) } int -Track::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, - bool session_state_changing, bool can_record, bool rec_monitors_input) +Track::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, + bool session_state_changing, bool can_record, bool rec_monitors_input) { if (n_outputs().n_total() == 0) { return 0; @@ -324,8 +324,8 @@ Track::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, } int -Track::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, - bool can_record, bool rec_monitors_input) +Track::silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, + bool can_record, bool rec_monitors_input) { if (n_outputs().n_total() == 0 && _processors.empty()) { return 0; diff --git a/libs/ardour/wscript b/libs/ardour/wscript index fc0e8107f9..85187680d8 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -99,12 +99,12 @@ def build(bld): chan_count.cc chan_mapping.cc configuration.cc - control_outputs.cc control_protocol_manager.cc control_protocol_search_path.cc crossfade.cc cycle_timer.cc default_click.cc + delivery.cc directory_names.cc diskstream.cc element_import_handler.cc diff --git a/libs/pbd/id.cc b/libs/pbd/id.cc index d24d22a0f9..ab9c7e7392 100644 --- a/libs/pbd/id.cc +++ b/libs/pbd/id.cc @@ -71,6 +71,12 @@ string ID::to_s() const return string(buf); } +bool +ID::operator== (const string& str) const +{ + return to_s() == str; +} + ID& ID::operator= (string str) { diff --git a/libs/pbd/pbd/id.h b/libs/pbd/pbd/id.h index 3f87a65e0d..d25ca81ef0 100644 --- a/libs/pbd/pbd/id.h +++ b/libs/pbd/pbd/id.h @@ -40,6 +40,8 @@ class ID { return _id != other._id; } + bool operator== (const std::string&) const; + ID& operator= (std::string); bool operator< (const ID& other) const { -- cgit v1.2.3