From 90220998af4f9683d696b511a09b34034e799093 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 16 Jun 2015 08:44:03 -0400 Subject: add Record-Safe feature to libardour (from Nikolay Polyanovskii) --- libs/ardour/ardour/audio_diskstream.h | 1 + libs/ardour/ardour/diskstream.h | 8 ++++++- libs/ardour/ardour/midi_diskstream.h | 1 + libs/ardour/ardour/midi_track.h | 1 + libs/ardour/ardour/route.h | 2 ++ libs/ardour/ardour/session.h | 2 ++ libs/ardour/ardour/track.h | 4 ++++ libs/ardour/audio_diskstream.cc | 33 +++++++++++++++++++++++++++-- libs/ardour/diskstream.cc | 21 +++++++++++++++++- libs/ardour/midi_diskstream.cc | 26 +++++++++++++++++++++-- libs/ardour/midi_track.cc | 10 +++++++++ libs/ardour/session_rtevents.cc | 30 ++++++++++++++++++++++++-- libs/ardour/track.cc | 40 +++++++++++++++++++++++++++++++++++ 13 files changed, 171 insertions(+), 8 deletions(-) (limited to 'libs') diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index f93c949a38..f48204d7ab 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -73,6 +73,7 @@ class LIBARDOUR_API AudioDiskstream : public Diskstream } void set_record_enabled (bool yn); + void set_record_safe (bool yn); int set_destructive (bool yn); int set_non_layered (bool yn); bool can_become_destructive (bool& requires_bounce) const; diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index cde21b209f..fc41d10160 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -104,7 +104,9 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream void set_roll_delay (framecnt_t); bool record_enabled() const { return g_atomic_int_get (&_record_enabled); } + bool record_safe () const { return g_atomic_int_get (&_record_safe); } virtual void set_record_enabled (bool yn) = 0; + virtual void set_record_safe (bool yn) = 0; bool destructive() const { return _flags & Destructive; } virtual int set_destructive (bool /*yn*/) { return -1; } @@ -176,6 +178,7 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream } PBD::Signal0 RecordEnableChanged; + PBD::Signal0 RecordSafeChanged; PBD::Signal0 SpeedChanged; PBD::Signal0 ReverseChanged; /* Emitted when this diskstream is set to use a different playlist */ @@ -263,6 +266,8 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream void engage_record_enable (); void disengage_record_enable (); + void engage_record_safe (); + void disengage_record_safe (); virtual bool prep_record_enable () = 0; virtual bool prep_record_disable () = 0; @@ -286,7 +291,8 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream boost::shared_ptr _playlist; - mutable gint _record_enabled; + gint _record_enabled; + gint _record_safe; double _visible_speed; double _actual_speed; /* items needed for speed change logic */ diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index 58b74bd54f..6610708581 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -70,6 +70,7 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream void flush_playback (framepos_t, framepos_t); void set_record_enabled (bool yn); + void set_record_safe (bool yn); void reset_tracker (); void resolve_tracker (Evoral::EventSink& buffer, framepos_t time); diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index f2542f0f6b..2ba57e4e01 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -51,6 +51,7 @@ public: boost::shared_ptr create_diskstream (); void set_diskstream (boost::shared_ptr); void set_record_enabled (bool yn, void *src); + void set_record_safe (bool yn, void *src); DataType data_type () const { return DataType::MIDI; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 8237219020..cce1e152a2 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -129,6 +129,8 @@ class LIBARDOUR_API Route : public SessionObject, public Automatable, public Rou virtual void set_record_enabled (bool /*yn*/, void * /*src*/) {} virtual bool record_enabled() const { return false; } + virtual void set_record_safe (bool yn, void *src) {} + virtual bool record_safe () const {return false; } virtual void nonrealtime_handle_transport_stopped (bool abort, bool did_locate, bool flush_processors); virtual void realtime_handle_transport_stopped () {} virtual void realtime_locate () {} diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 8379ed7ae5..bbc82939c7 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -700,6 +700,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop void set_mute (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_listen (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_record_enabled (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); + void set_record_safe (boost::shared_ptr, bool yn, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_solo_isolated (boost::shared_ptr, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_monitoring (boost::shared_ptr, MonitorChoice, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false); void set_exclusive_input_active (boost::shared_ptr rt, bool onoff, bool flip_others=false); @@ -1699,6 +1700,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop void rt_set_listen (boost::shared_ptr, bool yn, bool group_override); void rt_set_solo_isolated (boost::shared_ptr, bool yn, bool group_override); void rt_set_record_enabled (boost::shared_ptr, bool yn, bool group_override); + void rt_set_record_safe (boost::shared_ptr, bool yn, bool group_override); void rt_set_monitoring (boost::shared_ptr, MonitorChoice, bool group_override); /** temporary list of Diskstreams used only during load of 2.X sessions */ diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index 5e05ec373c..f699b5d5d3 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -107,7 +107,9 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream boost::shared_ptr rec_enable_control() { return _rec_enable_control; } bool record_enabled() const; + bool record_safe () const; void set_record_enabled (bool yn, void *src); + void set_record_safe (bool yn, void *src); void prep_record_enabled (bool yn, void *src); bool using_diskstream_id (PBD::ID) const; @@ -165,6 +167,7 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream /* Emitted when our diskstream is set to use a different playlist */ PBD::Signal0 PlaylistChanged; PBD::Signal0 RecordEnableChanged; + PBD::Signal0 RecordSafeChanged; PBD::Signal0 SpeedChanged; PBD::Signal0 AlignmentStyleChanged; @@ -227,6 +230,7 @@ private: void diskstream_playlist_changed (); void diskstream_record_enable_changed (); + void diskstream_record_safe_changed (); void diskstream_speed_changed (); void diskstream_alignment_style_changed (); void parameter_changed (std::string const & p); diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 7e673c99d1..00e1f9298f 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -1736,7 +1736,7 @@ AudioDiskstream::finish_capture (boost::shared_ptr c) void AudioDiskstream::set_record_enabled (bool yn) { - if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) { + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0 || record_safe ()) { return; } @@ -1761,10 +1761,39 @@ AudioDiskstream::set_record_enabled (bool yn) } } +void +AudioDiskstream::set_record_safe (bool yn) +{ + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) { + return; + } + + /* can't rec-safe in destructive mode if transport is before start ???? + REQUIRES REVIEW */ + + if (destructive() && yn && _session.transport_frame() < _session.current_start_frame()) { + return; + } + + /* yes, i know that this not proof against race conditions, but its + good enough. i think. + */ + + if (record_safe () != yn) { + if (yn) { + engage_record_safe (); + } else { + disengage_record_safe (); + } + + RecordSafeChanged (); /* EMIT SIGNAL */ + } +} + bool AudioDiskstream::prep_record_enable () { - if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) { + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0 || record_safe ()) { // REQUIRES REVIEW "|| record_safe ()" return false; } diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index 49d9d62ec4..9f3322dade 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -64,6 +64,7 @@ Diskstream::Diskstream (Session &sess, const string &name, Flag flag) , i_am_the_modifier (0) , _track (0) , _record_enabled (0) + , _record_safe (0) , _visible_speed (1.0f) , _actual_speed (1.0f) , _buffer_reallocation_required (false) @@ -102,6 +103,7 @@ Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/) , i_am_the_modifier (0) , _track (0) , _record_enabled (0) + , _record_safe (0) , _visible_speed (1.0f) , _actual_speed (1.0f) , _buffer_reallocation_required (false) @@ -468,6 +470,7 @@ Diskstream::get_state () snprintf (buf, sizeof(buf), "%f", _visible_speed); node->add_property ("speed", buf); node->add_property ("capture-alignment", enum_2_string (_alignment_choice)); + node->add_property ("record-safe", _record_safe ? "yes" : "no"); if (_extra_xml) { node->add_child_copy (*_extra_xml); @@ -516,8 +519,12 @@ Diskstream::set_state (const XMLNode& node, int /*version*/) non_realtime_set_speed (); } } + + if ((prop = node.property ("record-safe")) != 0) { + _record_safe = PBD::string_is_affirmative (prop->value()) ? 1 : 0; + } - return 0; + return 0; } void @@ -769,6 +776,18 @@ Diskstream::disengage_record_enable () g_atomic_int_set (&_record_enabled, 0); } +void +Diskstream::engage_record_safe () +{ + g_atomic_int_set (&_record_safe, 1); +} + +void +Diskstream::disengage_record_safe () +{ + g_atomic_int_set (&_record_safe, 0); +} + framecnt_t Diskstream::default_disk_read_chunk_frames() { diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index f17b38d7ea..a2a80f780b 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -1143,7 +1143,7 @@ MidiDiskstream::finish_capture () void MidiDiskstream::set_record_enabled (bool yn) { - if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) { + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0 || record_safe ()) { return; } @@ -1162,10 +1162,32 @@ MidiDiskstream::set_record_enabled (bool yn) } } +void +MidiDiskstream::set_record_safe (bool yn) +{ + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) { // REQUIRES REVIEW + return; + } + + /* yes, i know that this not proof against race conditions, but its + good enough. i think. + */ + + if (record_safe () != yn) { + if (yn) { + engage_record_safe (); + } else { + disengage_record_safe (); + } + + RecordSafeChanged (); /* EMIT SIGNAL */ + } +} + bool MidiDiskstream::prep_record_enable () { - if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) { + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0 || record_safe ()) { // REQUIRES REVIEW "|| record_safe ()" return false; } diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 3f15464481..487eb2025c 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -111,6 +111,16 @@ MidiTrack::set_record_enabled (bool yn, void *src) Track::set_record_enabled (yn, src); } +void +MidiTrack::set_record_safe (bool yn, void *src) +{ + if (_step_editing) { /* REQUIRES REVIEW */ + return; + } + + Track::set_record_safe (yn, src); +} + void MidiTrack::set_diskstream (boost::shared_ptr ds) { diff --git a/libs/ardour/session_rtevents.cc b/libs/ardour/session_rtevents.cc index 4bd7c2da9a..11d8319c0d 100644 --- a/libs/ardour/session_rtevents.cc +++ b/libs/ardour/session_rtevents.cc @@ -197,7 +197,7 @@ Session::set_record_enabled (boost::shared_ptr rl, bool yn, SessionEv */ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { - if ((*i)->is_auditioner()) { + if ((*i)->is_auditioner() || (*i)->record_safe ()) { continue; } @@ -215,7 +215,7 @@ void Session::rt_set_record_enabled (boost::shared_ptr rl, bool yn, bool group_override) { for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { - if ((*i)->is_auditioner()) { + if ((*i)->is_auditioner() || (*i)->record_safe ()) { continue; } @@ -229,6 +229,32 @@ Session::rt_set_record_enabled (boost::shared_ptr rl, bool yn, bool g set_dirty (); } + +void +Session::set_record_safe (boost::shared_ptr rl, bool yn, SessionEvent::RTeventCallback after, bool group_override) +{ + set_record_enabled (rl, false, after, group_override); + queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_safe)); +} + +void +Session::rt_set_record_safe (boost::shared_ptr rl, bool yn, bool group_override) +{ + for (RouteList::iterator i = rl->begin (); i != rl->end (); ++i) { + if ((*i)->is_auditioner ()) { // REQUIRES REVIEW Can audiotioner be in Record Safe mode? + continue; + } + + boost::shared_ptr t; + + if ((t = boost::dynamic_pointer_cast(*i)) != 0) { + t->set_record_safe (yn, (group_override ? (void*) t->route_group () : (void *) this)); + } + } + + set_dirty (); +} + void Session::process_rtop (SessionEvent* ev) { diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 1426c3926c..92ea993470 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -232,6 +232,10 @@ Track::can_record() void Track::prep_record_enabled (bool yn, void *src) { + if (yn && record_safe ()) { + return; + } + if (!_session.writable()) { return; } @@ -272,6 +276,10 @@ Track::prep_record_enabled (bool yn, void *src) void Track::set_record_enabled (bool yn, void *src) { + if (_diskstream->record_safe ()) { + return; + } + if (!_session.writable()) { return; } @@ -290,6 +298,31 @@ Track::set_record_enabled (bool yn, void *src) _rec_enable_control->Changed (); } +bool +Track::record_safe () const +{ + return _diskstream && _diskstream->record_safe (); +} + +void +Track::set_record_safe (bool yn, void *src) +{ + if (!_session.writable()) { /* REQUIRES REVIEW */ + return; + } + + if (_freeze_record.state == Frozen) { /* REQUIRES REVIEW */ + return; + } + + if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_recenable()) { + _route_group->apply (&Track::set_record_safe, yn, _route_group); + return; + } + + _diskstream->set_record_safe (yn); +} + void Track::parameter_changed (string const & p) { @@ -558,6 +591,7 @@ Track::set_diskstream (boost::shared_ptr ds) ds->PlaylistChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_playlist_changed, this)); diskstream_playlist_changed (); ds->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_record_enable_changed, this)); + ds->RecordSafeChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_record_safe_changed, this)); ds->SpeedChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_speed_changed, this)); ds->AlignmentStyleChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_alignment_style_changed, this)); } @@ -574,6 +608,12 @@ Track::diskstream_record_enable_changed () RecordEnableChanged (); /* EMIT SIGNAL */ } +void +Track::diskstream_record_safe_changed () +{ + RecordSafeChanged (); /* EMIT SIGNAL */ +} + void Track::diskstream_speed_changed () { -- cgit v1.2.3