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
This commit is contained in:
Paul Davis 2009-05-13 21:34:09 +00:00
parent 7188ec3990
commit 0569107ddc
57 changed files with 1251 additions and 645 deletions

View File

@ -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"

View File

@ -108,30 +108,32 @@ RegionView*
AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
{
AudioRegionView *region_view = 0;
boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
if (region == 0) {
return NULL;
}
for (list<RegionView *>::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<AudioRegionView*>(*i);
if (arv) {
arv->set_waveform_scale (_waveform_scale);
arv->set_waveform_shape (_waveform_shape);
}
// if(!recording){
// for (list<RegionView *>::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<AudioRegionView*>(*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<Region> 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<Region> 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<StreamView*>(this),

View File

@ -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;

View File

@ -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> 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>(*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<boost::shared_ptr<Region> > 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<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
boost::shared_ptr<Playlist> 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>(*playlist, &before, &after));
}
commit_reversible_command ();
}
boost::shared_ptr<Region>
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> 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>(*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<boost::shared_ptr<Region> > 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<PlaylistState> playlists;
for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
if (!playlist) {
// is this check necessary?
continue;
}
vector<PlaylistState>::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<PlaylistState>::iterator pl;
for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
(*pl).playlist->thaw ();
session->add_command(new MementoCommand<Playlist>(*(*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<Playlist> pl = (*x)->region()->playlist();
if (pl) {
set<PlaylistState, lt_playlist>::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);
}
}
}

View File

@ -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<ARDOUR::Bundle> a, boo
have_diagonal_not_association = true;
}
break;
default:
break;
}
}
}

View File

@ -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>(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<Processor>
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_ptr<Processo
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 ();
}
@ -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<Processor> 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<PluginInsert> pi)
return string_compose(_("%1: %2 (by %3)"), _route->name(), pi->name(), maker);
}
void
ProcessorBox::assign_default_sort_key (boost::shared_ptr<Processor> p)
{
p->set_sort_key (_placement == PreFader ? 0 : 9999);
cerr << "default sort key for "
<< _placement << " = " << p->sort_key()
<< endl;
}

View File

@ -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<ARDOUR::Processor>);
std::vector<sigc::connection> processor_active_connections;
std::vector<sigc::connection> processor_name_connections;

View File

@ -168,10 +168,20 @@ StreamView::set_samples_per_unit (gdouble spp)
return 0;
}
void
StreamView::add_region_view_weak (boost::weak_ptr<Region> r)
{
boost::shared_ptr<Region> sp (r.lock());
if (sp) {
add_region_view (sp);
}
}
void
StreamView::add_region_view (boost::shared_ptr<Region> 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<Diskstream> ds)
{
boost::shared_ptr<Diskstream> sp (ds.lock());
if (sp) {
playlist_modified (sp);
}
@ -300,7 +311,7 @@ StreamView::playlist_modified (boost::shared_ptr<Diskstream> 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<Diskstream> 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

View File

@ -93,7 +93,10 @@ public:
void get_inverted_selectables (Selection&, std::list<Selectable* >& results);
virtual void update_contents_metrics(boost::shared_ptr<ARDOUR::Region> r) {}
void add_region_view_weak (boost::weak_ptr<ARDOUR::Region> r);
void add_region_view (boost::shared_ptr<ARDOUR::Region>);
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<ARDOUR::Region>,
bool wait_for_waves, bool recording = false) = 0;
bool wait_for_waves, bool recording = false) = 0;
virtual void remove_region_view (boost::weak_ptr<ARDOUR::Region> );
void display_diskstream (boost::shared_ptr<ARDOUR::Diskstream>);

View File

@ -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

View File

@ -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);

View File

@ -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<AudioDiskstream> 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 ();

View File

@ -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))

View File

@ -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);
ControlOutputs(Session& s);
XMLNode& get_state ();
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();
private:
bool _deliver;
static const std::string processor_type_name;
};

View File

@ -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 <string>
#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<void> SelfMuteChange;
sigc::signal<void> 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__

View File

@ -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; }

View File

@ -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> io() { return _io; }
boost::shared_ptr<const IO> io() const { return _io; }
void set_io (boost::shared_ptr<IO>);
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<void,IOProcessor*,bool> AutomationPlaybackChanged;
@ -74,6 +77,7 @@ class IOProcessor : public Processor
private:
/* disallow copy construction */
IOProcessor (const IOProcessor&);
bool _own_io;
};

View File

@ -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;

View File

@ -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;
};

View File

@ -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<MidiBuffer::TimeType>& event);

View File

@ -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<MidiDiskstream> 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<MidiDiskstream> ds);
void use_new_diskstream ();

View File

@ -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;

View File

@ -129,6 +129,8 @@ class Playlist : public SessionObject,
sigc::signal<void,bool> InUse;
sigc::signal<void> Modified;
sigc::signal<void, boost::weak_ptr<Region> > RegionAdded;
sigc::signal<void, boost::weak_ptr<Region> > RegionRemoved;
sigc::signal<void> NameChanged;
sigc::signal<void> LengthChanged;
sigc::signal<void, std::list< Evoral::RangeMove<nframes_t> > const &> RangesMoved;

View File

@ -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 ();

View File

@ -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;

View File

@ -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; }

View File

@ -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 () {}

View File

@ -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<Delivery> control_outs() const { return _control_outs; }
boost::shared_ptr<Delivery> 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<Processor>, 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<Processor>, 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<Processor>, 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<void,void*> SelectedChanged;
int set_control_outs (const std::vector<std::string>& ports);
boost::shared_ptr<ControlOutputs> control_outs() { return _control_outs; }
int listen_via (boost::shared_ptr<IO>, const std::string& name);
void drop_listen (boost::shared_ptr<IO>);
bool feeds (boost::shared_ptr<Route>);
std::set<boost::shared_ptr<Route> > 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<ControlOutputs> _control_outs;
boost::shared_ptr<Delivery> _main_outs;
boost::shared_ptr<Delivery> _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<Delivery> add_listener (boost::shared_ptr<IO>, const std::string&);
private:
void init ();

View File

@ -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;
};

View File

@ -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;

View File

@ -45,13 +45,13 @@ class Track : public Route
virtual bool can_use_mode (TrackMode m, bool& bounce_required) { return false; }
sigc::signal<void> 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 ();

View File

@ -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];

View File

@ -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

View File

@ -16,64 +16,23 @@
675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cmath>
#include <algorithm>
#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

203
libs/ardour/delivery.cc Normal file
View File

@ -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 <cmath>
#include <algorithm>
#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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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> 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<Route> 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<IO> (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;
}

View File

@ -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

View File

@ -52,6 +52,8 @@
#include "ardour/smf_source.h"
#include "ardour/utils.h"
#include "midi++/types.h"
#include "i18n.h"
#include <locale.h>
@ -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)
{

View File

@ -30,6 +30,12 @@ MidiStateTracker::MidiStateTracker ()
_active_notes.reset();
}
void
MidiStateTracker::reset ()
{
_active_notes.reset ();
}
void
MidiStateTracker::track_note_onoffs (const Evoral::MIDIEvent<MidiBuffer::TimeType>& 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";
}

View File

@ -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;
}

View File

@ -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

View File

@ -342,6 +342,7 @@ Playlist::notify_region_removed (boost::shared_ptr<Region> r)
pending_length = false;
LengthChanged (); /* EMIT SIGNAL */
pending_modified = false;
RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
Modified (); /* EMIT SIGNAL */
}
}
@ -360,7 +361,6 @@ Playlist::notify_region_moved (boost::shared_ptr<Region> r)
list< Evoral::RangeMove<nframes_t> > m;
m.push_back (move);
RangesMoved (m);
}
}
@ -380,6 +380,7 @@ Playlist::notify_region_added (boost::shared_ptr<Region> r)
pending_length = false;
LengthChanged (); /* EMIT SIGNAL */
pending_modified = false;
RegionAdded (boost::weak_ptr<Region> (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<Region> (*s)); /* EMIT SIGNAL */
n++;
}
for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
RegionAdded (boost::weak_ptr<Region> (*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> 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> 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<sigc::connection>::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 ();
}

View File

@ -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()) {

View File

@ -127,7 +127,6 @@ PluginManager::PluginManager ()
}
#ifdef HAVE_SLV2
cerr << "LV2: Creating world" << endl;
_lv2_world = new LV2World();
#endif

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -20,6 +20,7 @@
#include <cmath>
#include <fstream>
#include <cassert>
#include <algorithm>
#include <sigc++/bind.h>
#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<void,const char*> 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<ControlOutputs> co = _control_outs;
boost::shared_ptr<Delivery> 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<boost::shared_ptr<Processor> >& p
cerr << "}" << endl;
}
struct ProcessorSortByKey {
bool operator() (boost::shared_ptr<Processor> a, boost::shared_ptr<Processor> 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> processor, ProcessorStreams* err, ProcessorList::iterator* iter, Placement placement)
Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, ProcessorList::iterator* iter)
{
ChanCount old_pms = processor_max_streams;
@ -657,6 +630,10 @@ Route::add_processor (boost::shared_ptr<Processor> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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<const Processor> a, boost::shared_ptr<const Processor> 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<ControlOutputs> (
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<Processor> 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<PluginInsert> pi;
if (!_active && (pi = boost::dynamic_pointer_cast<PluginInsert> (*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<string>& ports)
boost::shared_ptr<Delivery>
Route::add_listener (boost::shared_ptr<IO> io, const string& listen_name)
{
vector<string>::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<ControlOutputs> out_proc(new ControlOutputs (_session, out_io));
boost::shared_ptr<Delivery> 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<Delivery>();
}
listener->set_sort_key (_meter->sort_key() + 1);
add_processor (listener, NULL);
return listener;
}
int
Route::listen_via (boost::shared_ptr<IO> io, const string& listen_name)
{
vector<string> ports;
vector<string>::const_iterator i;
{
Glib::RWLock::ReaderLock rm (_processor_lock);
for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
boost::shared_ptr<const Delivery> d = boost::dynamic_pointer_cast<const Delivery>(*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<Delivery> 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> 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<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*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<Route> other)
for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) {
boost::shared_ptr<IOProcessor> redirect = boost::dynamic_pointer_cast<IOProcessor>(*r);
if ( ! redirect)
boost::shared_ptr<IOProcessor> proc = boost::dynamic_pointer_cast<IOProcessor>(*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<Delivery> dp = boost::dynamic_pointer_cast<Delivery> (*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;
}

View File

@ -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
{

View File

@ -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<Route> 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 */
/* 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);
if (_master_out) {
/* force the master to ignore any later call to this */
if (_master_out->pending_state_node) {
_master_out->ports_became_legal();
/* 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();
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;
}
}
}
/* no panner resets till we are through */
_master_out->defer_pan_reset ();
/* 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);
_master_out->allow_pan_reset ();
}
}
@ -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 ();
/* Connect track to listen/solo etc. busses XXX generalize this beyond control_out */
if (_control_out) {
vector<string> cports;
_control_out->ensure_io(
_control_out->input_minimum(), _control_out->output_minimum(),
false, this);
uint32_t ni = _control_out->n_inputs().get (DataType::AUDIO);
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<RouteList> r = routes.reader ();
for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
(*x)->set_control_outs (cports);
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*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<string> 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> route)
}
if (route == _control_out) {
_control_out = shared_ptr<Route> ();
/* cancel control outs for all routes */
vector<string> 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<Route> ();
}
update_route_solo_state ();

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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)
{

View File

@ -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 {