#include <ardour/audio_track.h>
#include <ardour/audio_diskstream.h>
#include <ardour/session.h>
-#include <ardour/redirect.h>
+#include <ardour/io_processor.h>
#include <ardour/audioregion.h>
#include <ardour/audiosource.h>
#include <ardour/region_factory.h>
#include <ardour/route_group_specialized.h>
-#include <ardour/insert.h>
+#include <ardour/processor.h>
+#include <ardour/plugin_insert.h>
#include <ardour/audioplaylist.h>
#include <ardour/playlist_factory.h>
#include <ardour/panner.h>
}
if ((prop = node.property ("input-connection")) != 0) {
- Connection* c = _session.connection_by_name (prop->value());
+ boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
if (c == 0) {
- error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
+ error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
- if ((c = _session.connection_by_name (_("in 1"))) == 0) {
- error << _("No input connections available as a replacement")
+ if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
+ error << _("No input bundles available as a replacement")
<< endmsg;
return -1;
} else {
- info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
+ info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
<< endmsg;
}
}
- use_input_connection (*c, this);
+ connect_input_ports_to_bundle (c, this);
} else if ((prop = node.property ("inputs")) != 0) {
if (set_inputs (prop->value())) {
child = *niter;
if (child->name() == X_("recenable")) {
- _rec_enable_control.set_state (*child);
- _session.add_controllable (&_rec_enable_control);
+ _rec_enable_control->set_state (*child);
+ _session.add_controllable (_rec_enable_control);
}
}
freeze_node->add_property ("playlist", _freeze_record.playlist->name());
freeze_node->add_property ("state", enum_2_string (_freeze_record.state));
- for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
- inode = new XMLNode (X_("insert"));
+ for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
+ inode = new XMLNode (X_("processor"));
(*i)->id.print (buf, sizeof (buf));
inode->add_property (X_("id"), buf);
inode->add_child_copy ((*i)->state);
_diskstream->id().print (buf, sizeof (buf));
root.add_property ("diskstream-id", buf);
- root.add_child_nocopy (_rec_enable_control.get_state());
+ root.add_child_nocopy (_rec_enable_control->get_state());
return root;
}
_freeze_record.have_mementos = false;
_freeze_record.state = Frozen;
- for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
+ for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
delete *i;
}
- _freeze_record.insert_info.clear ();
+ _freeze_record.processor_info.clear ();
if ((prop = fnode->property (X_("playlist"))) != 0) {
boost::shared_ptr<Playlist> pl = _session.playlist_by_name (prop->value());
XMLNodeList clist = fnode->children();
for (citer = clist.begin(); citer != clist.end(); ++citer) {
- if ((*citer)->name() != X_("insert")) {
+ if ((*citer)->name() != X_("processor")) {
continue;
}
continue;
}
- FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo (*((*citer)->children().front()),
- boost::shared_ptr<Insert>());
+ FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo (*((*citer)->children().front()),
+ boost::shared_ptr<Processor>());
frii->id = prop->value ();
- _freeze_record.insert_info.push_back (frii);
+ _freeze_record.processor_info.push_back (frii);
}
}
AudioTrack::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset,
bool session_state_changing, bool can_record, bool rec_monitors_input)
{
- if (n_outputs().get_total() == 0) {
+ if (n_outputs().n_total() == 0) {
return 0;
}
send_silence = true;
} else {
- if (Config->get_auto_input()) {
- if (Config->get_monitoring_model() == SoftwareMonitoring) {
+ if (!Config->get_tape_machine_mode()) {
+ /*
+ ADATs work in a strange way..
+ they monitor input always when stopped.and auto-input is engaged.
+ */
+ if ((Config->get_monitoring_model() == SoftwareMonitoring) && (Config->get_auto_input () || _diskstream->record_enabled())) {
send_silence = false;
} else {
send_silence = true;
}
} else {
- if (_diskstream->record_enabled()) {
- if (Config->get_monitoring_model() == SoftwareMonitoring) {
- send_silence = false;
- } else {
- send_silence = true;
- }
+ /*
+ Other machines switch to input on stop if the track is record enabled,
+ regardless of the auto input setting (auto input only changes the
+ monitoring state when the transport is rolling)
+ */
+ if ((Config->get_monitoring_model() == SoftwareMonitoring) && _diskstream->record_enabled()) {
+ send_silence = false;
} else {
send_silence = true;
}
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
{
- Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK);
+ Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
if (lm.locked()) {
// automation snapshot can also be called from the non-rt context
// and it uses the redirect list, so we take the lock out here
- automation_snapshot (start_frame);
+ automation_snapshot (start_frame, false);
}
}
- if (n_outputs().get_total() == 0 && _redirects.empty()) {
+ if (n_outputs().n_total() == 0 && _processors.empty()) {
return 0;
}
transport_frame = _session.transport_frame();
+ prepare_inputs( nframes, offset );
+
if ((nframes = check_initial_delay (nframes, offset, transport_frame)) == 0) {
/* need to do this so that the diskstream sets its
playback distance to zero, thus causing diskstream::commit
/* copy the diskstream data to all output buffers */
-
- const size_t limit = n_process_buffers().get(DataType::AUDIO);
- BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
-
+
+ size_t limit = n_process_buffers().n_audio();
+ BufferSet& bufs = _session.get_scratch_buffers ();
+ const size_t blimit = bufs.count().n_audio();
+
uint32_t n;
uint32_t i;
- for (i = 0, n = 1; i < limit; ++i, ++n) {
- memcpy (bufs.get_audio(i).data(), b, sizeof (Sample) * nframes);
- if (n < diskstream->n_channels().get(DataType::AUDIO)) {
- tmpb = diskstream->playback_buffer(n);
- if (tmpb!=0) {
- b = tmpb;
+ if (limit > blimit) {
+
+ /* example case: auditioner configured for stereo output,
+ but loaded with an 8 channel file. there are only
+ 2 passthrough buffers, but n_process_buffers() will
+ return 8.
+
+ arbitrary decision: map all channels in the diskstream
+ to the outputs available.
+ */
+
+ float scaling = limit/blimit;
+
+ for (i = 0, n = 1; i < blimit; ++i, ++n) {
+
+ /* first time through just copy a channel into
+ the output buffer.
+ */
+
+ Sample* bb = bufs.get_audio (i).data();
+
+ for (nframes_t xx = 0; xx < nframes; ++xx) {
+ bb[xx] = b[xx] * scaling;
+ }
+
+ if (n < diskstream->n_channels().n_audio()) {
+ tmpb = diskstream->playback_buffer(n);
+ if (tmpb!=0) {
+ b = tmpb;
+ }
+ }
+ }
+
+ for (;i < limit; ++i, ++n) {
+
+ /* for all remaining channels, sum with existing
+ data in the output buffers
+ */
+
+ bufs.get_audio (i%blimit).accumulate_with_gain_from (b, nframes, 0, scaling);
+
+ if (n < diskstream->n_channels().n_audio()) {
+ tmpb = diskstream->playback_buffer(n);
+ if (tmpb!=0) {
+ b = tmpb;
+ }
+ }
+
+ }
+
+ limit = blimit;
+
+ } else {
+ for (i = 0, n = 1; i < limit; ++i, ++n) {
+ memcpy (bufs.get_audio (i).data(), b, sizeof (Sample) * nframes);
+ if (n < diskstream->n_channels().n_audio()) {
+ tmpb = diskstream->playback_buffer(n);
+ if (tmpb!=0) {
+ b = tmpb;
+ }
}
}
}
/* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
if (!diskstream->record_enabled() && _session.transport_rolling()) {
- Glib::Mutex::Lock am (automation_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
- if (am.locked() && gain_automation_playback()) {
- apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+ if (am.locked() && gain_control()->automation_playback()) {
+ apply_gain_automation = gain_control()->list()->curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
}
}
AudioTrack::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset,
bool can_record, bool rec_monitors_input)
{
- if (n_outputs().get_total() == 0 && _redirects.empty()) {
+ if (n_outputs().n_total() == 0 && _processors.empty()) {
return 0;
}
gain_t gain_automation[nframes];
gain_t gain_buffer[nframes];
float mix_buffer[nframes];
- RedirectList::iterator i;
+ ProcessorList::iterator i;
bool post_fader_work = false;
gain_t this_gain = _gain;
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
- Glib::RWLock::ReaderLock rlock (redirect_lock);
+ Glib::RWLock::ReaderLock rlock (_processor_lock);
boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist());
assert(apl);
- if (apl->read (buffers.get_audio(nframes).data(),
- mix_buffer, gain_buffer, start, nframes) != nframes) {
+ assert(buffers.get_audio(0).capacity() >= nframes);
+
+ if (apl->read (buffers.get_audio(0).data(), mix_buffer, gain_buffer, start, nframes) != nframes) {
return -1;
}
- assert(buffers.count().get(DataType::AUDIO) >= 1);
+ assert(buffers.count().n_audio() >= 1);
uint32_t n=1;
Sample* b = buffers.get_audio(0).data();
BufferSet::audio_iterator bi = buffers.audio_begin();
++bi;
for ( ; bi != buffers.audio_end(); ++bi, ++n) {
- if (n < diskstream->n_channels().get(DataType::AUDIO)) {
+ if (n < diskstream->n_channels().n_audio()) {
if (apl->read (bi->data(), mix_buffer, gain_buffer, start, nframes, n) != nframes) {
return -1;
}
}
- /* note: only run inserts during export. other layers in the machinery
- will already have checked that there are no external port inserts.
+ /* note: only run processors during export. other layers in the machinery
+ will already have checked that there are no external port processors.
*/
- for (i = _redirects.begin(); i != _redirects.end(); ++i) {
- boost::shared_ptr<Insert> insert;
+ for (i = _processors.begin(); i != _processors.end(); ++i) {
+ boost::shared_ptr<Processor> processor;
- if ((insert = boost::dynamic_pointer_cast<Insert>(*i)) != 0) {
- switch (insert->placement()) {
+ if ((processor = boost::dynamic_pointer_cast<Processor>(*i)) != 0) {
+ switch (processor->placement()) {
case PreFader:
- insert->run (buffers, start, start+nframes, nframes, 0);
+ processor->run_in_place (buffers, start, start+nframes, nframes, 0);
break;
case PostFader:
post_fader_work = true;
}
}
- if (_gain_automation_curve.automation_state() == Play) {
+ if (gain_control()->automation_state() == Play) {
- _gain_automation_curve.get_vector (start, start + nframes, gain_automation, nframes);
+ gain_control()->list()->curve().get_vector (start, start + nframes, gain_automation, nframes);
for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) {
Sample *b = bi->data();
if (post_fader_work) {
- for (i = _redirects.begin(); i != _redirects.end(); ++i) {
- boost::shared_ptr<PluginInsert> insert;
+ for (i = _processors.begin(); i != _processors.end(); ++i) {
+ boost::shared_ptr<PluginInsert> processor;
- if ((insert = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
+ if ((processor = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
switch ((*i)->placement()) {
case PreFader:
break;
case PostFader:
- insert->run (buffers, start, start+nframes, nframes, 0);
+ processor->run_in_place (buffers, start, start+nframes, nframes, 0);
break;
}
}
return 0;
}
-void
+boost::shared_ptr<Region>
AudioTrack::bounce (InterThreadInfo& itt)
{
vector<boost::shared_ptr<Source> > srcs;
- _session.write_one_audio_track (*this, 0, _session.current_end_frame(), false, srcs, itt);
+ return _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), false, srcs, itt);
}
-
-void
+boost::shared_ptr<Region>
AudioTrack::bounce_range (nframes_t start, nframes_t end, InterThreadInfo& itt)
{
vector<boost::shared_ptr<Source> > srcs;
- _session.write_one_audio_track (*this, start, end, false, srcs, itt);
+ return _session.write_one_track (*this, start, end, false, srcs, itt);
}
void
return;
}
- if (_session.write_one_audio_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt)) {
+ boost::shared_ptr<Region> res;
+
+ if ((res = _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt)) == 0) {
return;
}
- _freeze_record.insert_info.clear ();
+ _freeze_record.processor_info.clear ();
_freeze_record.have_mementos = true;
{
- Glib::RWLock::ReaderLock lm (redirect_lock);
+ Glib::RWLock::ReaderLock lm (_processor_lock);
- for (RedirectList::iterator r = _redirects.begin(); r != _redirects.end(); ++r) {
+ for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
- boost::shared_ptr<Insert> insert;
+ boost::shared_ptr<Processor> processor;
- if ((insert = boost::dynamic_pointer_cast<Insert>(*r)) != 0) {
+ if ((processor = boost::dynamic_pointer_cast<Processor>(*r)) != 0) {
- FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo ((*r)->get_state(), insert);
+ FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo ((*r)->get_state(), processor);
- frii->id = insert->id();
+ frii->id = processor->id();
- _freeze_record.insert_info.push_back (frii);
+ _freeze_record.processor_info.push_back (frii);
- /* now deactivate the insert */
+ /* now deactivate the processor */
- insert->set_active (false, this);
+ processor->set_active (false);
+ _session.set_dirty ();
}
}
}
new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false);
+
+ _freeze_record.gain = _gain;
+ _freeze_record.gain_automation_state = _gain_control->automation_state();
+ _freeze_record.pan_automation_state = _panner->automation_state();
+
region_name = new_playlist_name;
/* create a new region from all filesources, keep it private */
diskstream->use_playlist (boost::dynamic_pointer_cast<AudioPlaylist>(new_playlist));
diskstream->set_record_enabled (false);
+ /* reset stuff that has already been accounted for in the freeze process */
+
+ set_gain (1.0, this);
+ _gain_control->set_automation_state (Off);
+ _panner->set_automation_state (Off);
+
_freeze_record.state = Frozen;
FreezeChange(); /* EMIT SIGNAL */
}
if (_freeze_record.have_mementos) {
- for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
+ for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
(*i)->memento ();
}
} else {
- Glib::RWLock::ReaderLock lm (redirect_lock); // should this be a write lock? jlc
- for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
- for (vector<FreezeRecordInsertInfo*>::iterator ii = _freeze_record.insert_info.begin(); ii != _freeze_record.insert_info.end(); ++ii) {
+ Glib::RWLock::ReaderLock lm (_processor_lock); // should this be a write lock? jlc
+ for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+ for (vector<FreezeRecordProcessorInfo*>::iterator ii = _freeze_record.processor_info.begin(); ii != _freeze_record.processor_info.end(); ++ii) {
if ((*ii)->id == (*i)->id()) {
(*i)->set_state (((*ii)->state));
break;
}
_freeze_record.playlist.reset ();
+ set_gain (_freeze_record.gain, this);
+ _gain_control->set_automation_state (_freeze_record.gain_automation_state);
+ _panner->set_automation_state (_freeze_record.pan_automation_state);
}
_freeze_record.state = UnFrozen;