get diskreader working, and remove per-track varispeed API and mechanism

This commit is contained in:
Paul Davis 2017-04-17 11:12:38 +01:00
parent fe8c70e6fc
commit 2a1dccabc9
12 changed files with 182 additions and 177 deletions

View file

@ -78,7 +78,6 @@ class LIBARDOUR_API DiskIOProcessor : public Processor
bool recordable() const { return _flags & Recordable; }
bool non_layered() const { return _flags & NonLayered; }
bool reversed() const { return _actual_speed < 0.0f; }
double speed() const { return _visible_speed; }
virtual void non_realtime_locate (framepos_t);
@ -122,9 +121,7 @@ class LIBARDOUR_API DiskIOProcessor : public Processor
protected:
Flag _flags;
uint32_t i_am_the_modifier;
double _visible_speed;
double _actual_speed;
double _speed;
double _target_speed;
/* items needed for speed change logic */
bool _buffer_reallocation_required;

View file

@ -48,6 +48,7 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor
void run (BufferSet& /*bufs*/, framepos_t /*start_frame*/, framepos_t /*end_frame*/, double speed, pframes_t /*nframes*/, bool /*result_required*/);
void non_realtime_locate (framepos_t);
void realtime_handle_transport_stopped ();
virtual XMLNode& state (bool full);
int set_state (const XMLNode&, int version);

View file

@ -44,7 +44,6 @@ public:
int roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& need_butler);
void realtime_handle_transport_stopped ();
void realtime_locate ();
void non_realtime_locate (framepos_t);

View file

@ -388,7 +388,8 @@ public:
virtual XMLNode& get_template();
XMLNode& get_processor_state ();
virtual void set_processor_state (const XMLNode&);
void set_processor_state (const XMLNode&);
virtual bool set_processor_state (XMLNode const & node, XMLProperty const* prop, ProcessorList& new_order, bool& must_configure);
boost::weak_ptr<Route> weakroute ();

View file

@ -67,6 +67,8 @@ class LIBARDOUR_API Track : public Route, public Recordable
MonitorState monitoring_state () const;
MeterState metering_state () const;
bool set_processor_state (XMLNode const & node, XMLProperty const* prop, ProcessorList& new_order, bool& must_configure);
virtual int no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
bool state_changing);
@ -155,6 +157,7 @@ class LIBARDOUR_API Track : public Route, public Recordable
int can_internal_playback_seek (framecnt_t);
int internal_playback_seek (framecnt_t);
void non_realtime_locate (framepos_t);
void realtime_handle_transport_stopped ();
void non_realtime_set_speed ();
int overwrite_existing_buffers ();
framecnt_t get_captured_frames (uint32_t n = 0) const;
@ -163,7 +166,6 @@ class LIBARDOUR_API Track : public Route, public Recordable
bool realtime_set_speed (double, bool);
void transport_stopped_wallclock (struct tm &, time_t, bool);
bool pending_overwrite () const;
double speed () const;
void prepare_to_stop (framepos_t, framepos_t);
void set_slaved (bool);
ChanCount n_channels ();

View file

@ -49,9 +49,7 @@ DiskIOProcessor::DiskIOProcessor (Session& s, string const & str, Flag f)
: Processor (s, str)
, _flags (f)
, i_am_the_modifier (false)
, _visible_speed (0.0)
, _actual_speed (0.0)
, _speed (0.0)
, _target_speed (0.0)
, _buffer_reallocation_required (false)
, _seek_required (false)
@ -170,11 +168,7 @@ DiskIOProcessor::configure_io (ChanCount in, ChanCount out)
midi_interpolation.add_channel_to (0,0);
}
if (speed() != 1.0f || speed() != -1.0f) {
seek ((framepos_t) (_session.transport_frame() * (double) speed()));
} else {
seek (_session.transport_frame());
}
seek (_session.transport_frame());
return Processor::configure_io (in, out);
}
@ -206,11 +200,7 @@ DiskIOProcessor::non_realtime_locate (framepos_t location)
{
/* now refill channel buffers */
if (speed() != 1.0f || speed() != -1.0f) {
seek ((framepos_t) (location * (double) speed()), true);
} else {
seek (location, true);
}
seek (location, true);
}
void
@ -221,39 +211,27 @@ DiskIOProcessor::non_realtime_set_speed ()
}
if (_seek_required) {
if (speed() != 1.0f || speed() != -1.0f) {
seek ((framepos_t) (_session.transport_frame() * (double) speed()), true);
}
else {
seek (_session.transport_frame(), true);
}
seek (_session.transport_frame(), true);
_seek_required = false;
}
}
bool
DiskIOProcessor::realtime_set_speed (double sp, bool global)
DiskIOProcessor::realtime_set_speed (double new_speed, bool global)
{
bool changed = false;
double new_speed = sp * _session.transport_speed();
if (_visible_speed != sp) {
_visible_speed = sp;
DEBUG_TRACE (DEBUG::Transport, string_compose ("%1 will run at %2\n", name(), new_speed));
if (_target_speed != new_speed) {
_target_speed = new_speed;
changed = true;
}
if (new_speed != _actual_speed) {
framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() *
fabs (new_speed)) + 2;
framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() * fabs (new_speed)) + 2;
if (required_wrap_size > wrap_buffer_size) {
_buffer_reallocation_required = true;
}
_actual_speed = new_speed;
_target_speed = fabs(_actual_speed);
}
if (changed) {

View file

@ -112,13 +112,11 @@ DiskReader::default_chunk_frames()
bool
DiskReader::set_name (string const & str)
{
if (_name != str) {
for (uint32_t n = 0; n < DataType::num_types; ++n) {
if (_playlists[n]) {
_playlists[n]->set_name (str);
}
}
SessionObject::set_name(str);
string my_name = X_("reader:");
my_name += str;
if (_name != my_name) {
SessionObject::set_name (my_name);
}
return true;
@ -151,6 +149,7 @@ DiskReader::set_state (const XMLNode& node, int version)
void
DiskReader::realtime_handle_transport_stopped ()
{
realtime_set_speed (0.0f, true);
}
void
@ -244,14 +243,7 @@ DiskReader::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
const bool need_disk_signal = result_required || _monitoring_choice == MonitorDisk || _monitoring_choice == MonitorCue;
_need_butler = false;
if (fabsf (_actual_speed) != 1.0f) {
midi_interpolation.set_speed (_target_speed);
interpolation.set_speed (_target_speed);
playback_distance = midi_interpolation.distance (nframes);
} else {
playback_distance = nframes;
}
playback_distance = calculate_playback_distance (nframes);
if (!need_disk_signal) {
@ -339,7 +331,6 @@ DiskReader::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
}
chaninfo->buf->increment_read_ptr (playback_distance);
_speed = _target_speed;
}
/* MIDI data handling */
@ -352,7 +343,7 @@ DiskReader::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
get_playback (mbuf, playback_distance);
/* vari-speed */
if (_target_speed > 0 && _actual_speed != 1.0f) {
if (_actual_speed != 0.0 && fabsf (_actual_speed) != 1.0f) {
MidiBuffer& mbuf (bufs.get_midi (0));
for (MidiBuffer::iterator i = mbuf.begin(); i != mbuf.end(); ++i) {
MidiBuffer::TimeType *tme = i.timeptr();
@ -428,6 +419,8 @@ DiskReader::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
if (frames_read <= frames_written) {
if ((frames_written - frames_read) + playback_distance < midi_readahead) {
_need_butler = true;
} else {
cerr << name() << " fr " << frames_read << " > " << frames_written << endl;
}
} else {
_need_butler = true;
@ -448,17 +441,14 @@ DiskReader::calculate_playback_distance (pframes_t nframes)
{
frameoffset_t playback_distance = nframes;
if (_actual_speed != 1.0f && _actual_speed != -1.0f) {
if (_target_speed != 1.0f && _target_speed != -1.0f) {
interpolation.set_speed (_target_speed);
boost::shared_ptr<ChannelList> c = channels.reader();
int channel = 0;
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) {
playback_distance = interpolation.interpolate (channel, nframes, NULL, NULL);
}
} else {
playback_distance = nframes;
midi_interpolation.set_speed (_target_speed);
playback_distance = midi_interpolation.distance (nframes);
}
_actual_speed = _target_speed;
if (_actual_speed < 0.0) {
return -playback_distance;
} else {
@ -496,7 +486,7 @@ DiskReader::overwrite_existing_buffers ()
/* AUDIO */
bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
bool reversed = (_target_speed * _session.transport_speed()) < 0.0f;
/* assume all are the same size */
framecnt_t size = c->front()->buf->bufsize();
@ -839,7 +829,7 @@ DiskReader::refill_audio (Sample* mixdown_buffer, float* gain_buffer, framecnt_t
int32_t ret = 0;
framecnt_t to_read;
RingBufferNPT<Sample>::rw_vector vector;
bool const reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
bool const reversed = (_target_speed * _session.transport_speed()) < 0.0f;
framecnt_t total_space;
framecnt_t zero_fill;
uint32_t chan_n;
@ -1401,10 +1391,9 @@ DiskReader::refill_midi ()
}
size_t write_space = _midi_buf->write_space();
bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
bool reversed = (_target_speed * _session.transport_speed()) < 0.0f;
DEBUG_TRACE (DEBUG::DiskIO, string_compose ("MIDI refill, write space = %1 file frame = %2\n", write_space, file_frame));
//PBD::stacktrace (cerr, 20);
/* no space to write */
if (write_space == 0) {

View file

@ -417,13 +417,13 @@ DiskWriter::set_state (const XMLNode& node, int version)
if (DiskIOProcessor::set_state (node, version)) {
return -1;
}
#if 0 // XXX DISK
if ((prop = node.property (X_("capture-alignment"))) != 0) {
set_align_choice (AlignChoice (string_2_enum (prop->value(), _alignment_choice)), true);
} else {
set_align_choice (Automatic, true);
}
#endif
if ((prop = node.property ("record-safe")) != 0) {
_record_safe = PBD::string_is_affirmative (prop->value()) ? 1 : 0;
@ -1702,3 +1702,9 @@ DiskWriter::adjust_buffering ()
(*chan)->resize (_session.butler()->audio_diskstream_capture_buffer_size());
}
}
void
DiskWriter::realtime_handle_transport_stopped ()
{
realtime_set_speed (0.0f, true);
}

View file

@ -397,20 +397,6 @@ MidiTrack::realtime_locate ()
_disk_reader->reset_tracker ();
}
void
MidiTrack::realtime_handle_transport_stopped ()
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
if (!lm.locked ()) {
return;
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->realtime_handle_transport_stopped ();
}
}
void
MidiTrack::non_realtime_locate (framepos_t pos)
{

View file

@ -457,6 +457,7 @@ Route::process_output_buffers (BufferSet& bufs,
_initial_delay + latency, longest_session_latency - latency);
}
//cerr << name() << " run " << (*i)->name() << endl;
(*i)->run (bufs, start_frame - latency, end_frame - latency, speed, nframes, *i != _processors.back());
bufs.set_count ((*i)->output_streams());
@ -2825,88 +2826,7 @@ Route::set_processor_state (const XMLNode& node)
/* CapturingProcessor should never be restored, it's always
added explicitly when needed */
} else {
ProcessorList::iterator o;
for (o = _processors.begin(); o != _processors.end(); ++o) {
XMLProperty const * id_prop = (*niter)->property(X_("id"));
if (id_prop && (*o)->id() == id_prop->value()) {
(*o)->set_state (**niter, Stateful::current_state_version);
new_order.push_back (*o);
break;
}
}
// If the processor (*niter) is not on the route then create it
if (o == _processors.end()) {
boost::shared_ptr<Processor> processor;
if (prop->value() == "intsend") {
processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), boost::shared_ptr<Route>(), Delivery::Aux, true));
} else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "windows-vst" ||
prop->value() == "mac-vst" ||
prop->value() == "lxvst" ||
prop->value() == "luaproc" ||
prop->value() == "audiounit") {
if (_session.get_disable_all_loaded_plugins ()) {
processor.reset (new UnknownProcessor (_session, **niter));
} else {
processor.reset (new PluginInsert (_session));
processor->set_owner (this);
if (_strict_io) {
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(processor);
pi->set_strict_io (true);
}
}
} else if (prop->value() == "port") {
processor.reset (new PortInsert (_session, _pannable, _mute_master));
} else if (prop->value() == "send") {
processor.reset (new Send (_session, _pannable, _mute_master, Delivery::Send, true));
boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (processor);
send->SelfDestruct.connect_same_thread (*this,
boost::bind (&Route::processor_selfdestruct, this, boost::weak_ptr<Processor> (processor)));
} else {
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
continue;
}
if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
/* This processor could not be configured. Turn it into a UnknownProcessor */
processor.reset (new UnknownProcessor (_session, **niter));
}
/* subscribe to Sidechain IO changes */
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
if (pi && pi->has_sidechain ()) {
pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2));
}
/* we have to note the monitor send here, otherwise a new one will be created
and the state of this one will be lost.
*/
boost::shared_ptr<InternalSend> isend = boost::dynamic_pointer_cast<InternalSend> (processor);
if (isend && isend->role() == Delivery::Listen) {
_monitor_send = isend;
}
/* it doesn't matter if invisible processors are added here, as they
will be sorted out by setup_invisible_processors () shortly.
*/
new_order.push_back (processor);
must_configure = true;
}
set_processor_state (**niter, prop, new_order, must_configure);
}
}
@ -2948,6 +2868,93 @@ Route::set_processor_state (const XMLNode& node)
set_processor_positions ();
}
bool
Route::set_processor_state (XMLNode const & node, XMLProperty const* prop, ProcessorList& new_order, bool& must_configure)
{
ProcessorList::iterator o;
for (o = _processors.begin(); o != _processors.end(); ++o) {
XMLProperty const * id_prop = node.property(X_("id"));
if (id_prop && (*o)->id() == id_prop->value()) {
(*o)->set_state (node, Stateful::current_state_version);
new_order.push_back (*o);
break;
}
}
// If the processor (node) is not on the route then create it
if (o == _processors.end()) {
boost::shared_ptr<Processor> processor;
if (prop->value() == "intsend") {
processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), boost::shared_ptr<Route>(), Delivery::Aux, true));
} else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "windows-vst" ||
prop->value() == "mac-vst" ||
prop->value() == "lxvst" ||
prop->value() == "luaproc" ||
prop->value() == "audiounit") {
if (_session.get_disable_all_loaded_plugins ()) {
processor.reset (new UnknownProcessor (_session, node));
} else {
processor.reset (new PluginInsert (_session));
processor->set_owner (this);
if (_strict_io) {
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(processor);
pi->set_strict_io (true);
}
}
} else if (prop->value() == "port") {
processor.reset (new PortInsert (_session, _pannable, _mute_master));
} else if (prop->value() == "send") {
processor.reset (new Send (_session, _pannable, _mute_master, Delivery::Send, true));
boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (processor);
send->SelfDestruct.connect_same_thread (*this,
boost::bind (&Route::processor_selfdestruct, this, boost::weak_ptr<Processor> (processor)));
} else {
return false;
}
if (processor->set_state (node, Stateful::current_state_version) != 0) {
/* This processor could not be configured. Turn it into a UnknownProcessor */
processor.reset (new UnknownProcessor (_session, node));
}
/* subscribe to Sidechain IO changes */
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
if (pi && pi->has_sidechain ()) {
pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2));
}
/* we have to note the monitor send here, otherwise a new one will be created
and the state of this one will be lost.
*/
boost::shared_ptr<InternalSend> isend = boost::dynamic_pointer_cast<InternalSend> (processor);
if (isend && isend->role() == Delivery::Listen) {
_monitor_send = isend;
}
/* it doesn't matter if invisible processors are added here, as they
will be sorted out by setup_invisible_processors () shortly.
*/
new_order.push_back (processor);
must_configure = true;
}
return true;
}
void
Route::curve_reallocate ()
{

View file

@ -1530,7 +1530,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
boost::shared_ptr<RouteList> rl = routes.reader();
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
if (tr && tr->realtime_set_speed (tr->speed(), true)) {
if (tr && tr->realtime_set_speed (_transport_speed, true)) {
todo = PostTransportWork (todo | PostTransportSpeed);
}
}
@ -1694,7 +1694,7 @@ Session::start_transport ()
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
if (tr) {
tr->realtime_set_speed (tr->speed(), true);
tr->realtime_set_speed (_transport_speed, true);
}
}
@ -1861,7 +1861,7 @@ Session::use_sync_source (Slave* new_slave)
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
if (tr && !tr->hidden()) {
if (tr->realtime_set_speed (tr->speed(), true)) {
if (tr->realtime_set_speed (_transport_speed, true)) {
non_rt_required = true;
}
tr->set_slaved (_slave != 0);

View file

@ -77,7 +77,6 @@ Track::init ()
}
_disk_reader.reset (new DiskReader (_session, name(), dflags));
_disk_reader->set_block_size (_session.get_block_size ());
_disk_reader->set_route (shared_from_this());
@ -342,6 +341,7 @@ Track::set_name (const string& str)
_disk_writer->set_write_source_name (diskstream_name);
boost::shared_ptr<Track> me = boost::dynamic_pointer_cast<Track> (shared_from_this ());
if (_playlists[data_type()]->all_regions_empty () && _session.playlists->playlists_for_track (me).size() == 1) {
/* Only rename the diskstream (and therefore the playlist) if
a) the playlist has never had a region added to it and
@ -358,6 +358,12 @@ Track::set_name (const string& str)
_disk_writer->set_name (str);
}
for (uint32_t n = 0; n < DataType::num_types; ++n) {
if (_playlists[n]) {
_playlists[n]->set_name (str);
}
}
/* save state so that the statefile fully reflects any filename changes */
if ((ret = Route::set_name (str)) == 0) {
@ -483,9 +489,9 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
if (no_meter) {
BufferSet& bufs (_session.get_silent_buffers (n_process_buffers()));
_meter->run (bufs, start_frame, end_frame, 1.0, nframes, true);
_input->process_input (boost::shared_ptr<Processor>(), start_frame, end_frame, speed(), nframes);
_input->process_input (boost::shared_ptr<Processor>(), start_frame, end_frame, _session.transport_speed(), nframes);
} else {
_input->process_input (_meter, start_frame, end_frame, speed(), nframes);
_input->process_input (_meter, start_frame, end_frame, _session.transport_speed(), nframes);
}
}
@ -498,7 +504,7 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
fill_buffers_with_input (bufs, _input, nframes);
if (_meter_point == MeterInput) {
_meter->run (bufs, start_frame, end_frame, 1.0 /*speed()*/, nframes, true);
_meter->run (bufs, start_frame, end_frame, _session.transport_speed(), nframes, true);
}
passthru (bufs, start_frame, end_frame, nframes, false);
@ -707,6 +713,20 @@ Track::realtime_set_speed (double s, bool g)
return _disk_writer->realtime_set_speed (s, g);
}
void
Track::realtime_handle_transport_stopped ()
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
if (!lm.locked ()) {
return;
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->realtime_handle_transport_stopped ();
}
}
void
Track::transport_stopped_wallclock (struct tm & n, time_t t, bool g)
{
@ -719,12 +739,6 @@ Track::pending_overwrite () const
return _disk_reader->pending_overwrite ();
}
double
Track::speed () const
{
return _disk_reader->speed ();
}
void
Track::prepare_to_stop (framepos_t t, framepos_t a)
{
@ -1115,3 +1129,28 @@ Track::metering_state () const
}
return rv ? MeteringInput : MeteringRoute;
}
bool
Track::set_processor_state (XMLNode const & node, XMLProperty const* prop, ProcessorList& new_order, bool& must_configure)
{
if (Route::set_processor_state (node, prop, new_order, must_configure)) {
return true;
}
if (prop->value() == "diskreader") {
if (_disk_reader) {
_disk_reader->set_state (node, Stateful::current_state_version);
new_order.push_back (_disk_reader);
return true;
}
} else if (prop->value() == "diskwriter") {
if (_disk_writer) {
_disk_writer->set_state (node, Stateful::current_state_version);
new_order.push_back (_disk_writer);
return true;
}
}
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
return false;
}