add new concept for managing alignment style (AlignChoice); switch to using worst_pla...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 9 Mar 2011 05:19:44 +0000 (05:19 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 9 Mar 2011 05:19:44 +0000 (05:19 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@9112 d708f5d6-7413-0410-9779-e7cbd77b26cf

15 files changed:
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_time_axis.h
libs/ardour/ardour/diskstream.h
libs/ardour/ardour/session.h
libs/ardour/ardour/track.h
libs/ardour/ardour/types.h
libs/ardour/audio_diskstream.cc
libs/ardour/diskstream.cc
libs/ardour/enums.cc
libs/ardour/midi_diskstream.cc
libs/ardour/mtc_slave.cc
libs/ardour/session.cc
libs/ardour/session_midi.cc
libs/ardour/session_transport.cc
libs/ardour/track.cc

index cde6d552b4678b8cd4483fbe20ebd8370598051e..94e4601db1d4831d535a24592284f4b396b9a04c 100644 (file)
@@ -506,36 +506,96 @@ RouteTimeAxisView::build_display_menu ()
 
                        int existing = 0;
                        int capture = 0;
+                        int automatic = 0;
+                        int styles = 0;
+                        boost::shared_ptr<Track> first_track;
+
                        TrackSelection const & s = _editor.get_selection().tracks;
                        for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
                                RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
                                if (!r || !r->is_track ()) {
                                        continue;
                                }
-                               
-                               switch (r->track()->alignment_style()) {
-                               case ExistingMaterial:
-                                       ++existing;
-                                       break;
-                               case CaptureTime:
-                                       ++capture;
-                                       break;
-                               }
+
+                                if (!first_track) {
+                                        first_track = r->track();
+                                }
+
+                                switch (r->track()->alignment_choice()) {
+                                case Automatic:
+                                        ++automatic;
+                                        styles |= 0x1;
+                                        switch (r->track()->alignment_style()) {
+                                        case ExistingMaterial:
+                                                ++existing;
+                                                break;
+                                        case CaptureTime:
+                                                ++capture;
+                                                break;
+                                        }
+                                        break;
+                                case UseExistingMaterial:
+                                        ++existing;
+                                        styles |= 0x2;
+                                        break;
+                                case UseCaptureTime:
+                                        ++capture;
+                                        styles |= 0x4;
+                                        break;
+                                }
                        }
-                       
-                       alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
-                       RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
-                       i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial, true));
-                       i->set_active (existing != 0 && capture == 0);
-                       i->set_inconsistent (existing != 0 && capture != 0);
-                       
-                       alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
-                       i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
-                       i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime, true));
-                       i->set_active (existing == 0 && capture != 0);
-                       i->set_inconsistent (existing != 0 && capture != 0);
-                       
-                       items.push_back (MenuElem (_("Alignment"), *alignment_menu));
+
+                        bool inconsistent;
+                        switch (styles) {
+                        case 1:
+                        case 2:
+                        case 4:
+                                inconsistent = false;
+                                break;
+                        default:
+                                inconsistent = true;
+                                break;
+                        }
+
+                        RadioMenuItem* i;
+
+                        if (!inconsistent && first_track) {
+
+                                alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
+                                i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
+                                i->set_active (automatic != 0 && existing == 0 && capture == 0); 
+                                i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
+
+                                switch (first_track->alignment_choice()) {
+                                case Automatic:
+                                        switch (first_track->alignment_style()) { 
+                                        case ExistingMaterial:
+                                                alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
+                                                break;
+                                        case CaptureTime:
+                                                alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
+                                                break;
+                                        }
+                                        break;
+                                default:
+                                        break;
+                                }
+                                
+                                alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
+                                i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
+                                i->set_active (existing != 0 && capture == 0 && automatic == 0);
+                                i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
+                                
+                                alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
+                                i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
+                                i->set_active (existing == 0 && capture != 0 && automatic == 0);
+                                i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
+
+                                items.push_back (MenuElem (_("Alignment"), *alignment_menu));
+
+                        } else {
+                                /* show nothing */
+                        }
 
                        Menu* mode_menu = manage (new Menu);
                        MenuList& mode_items = mode_menu->items ();
@@ -922,13 +982,21 @@ RouteTimeAxisView::set_samples_per_unit (double spu)
 }
 
 void
-RouteTimeAxisView::set_align_style (AlignStyle style, bool apply_to_selection)
+RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
 {
+        /* this is one of the two calls made when these radio menu items change status. this one
+           is for the item that became inactive, and we want to ignore it.
+        */
+
+        if (!mitem->get_active()) {
+                return;
+        }
+
        if (apply_to_selection) {
-               _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_style, _1, style, false));
+               _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
        } else {
                if (track ()) {
-                       track()->set_align_style (style);
+                       track()->set_align_choice (choice);
                }
        }
 }
@@ -1524,7 +1592,6 @@ RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist>
 
                                boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
                                if (!track) {
-                                       std::cerr << "route " << (*i)->name() << " is not a Track" << std::endl;
                                        continue;
                                }
 
index 91bc1ff5c66e2bef5f99b7f4de59a055737ebff2..c68dc573ead4a052b57fea4445a51ce73d869384 100644 (file)
@@ -216,7 +216,7 @@ protected:
        virtual void append_extra_display_menu_items () {}
        void         build_display_menu ();
 
-       void set_align_style (ARDOUR::AlignStyle, bool apply_to_selection = false);
+       void set_align_choice (Gtk::RadioMenuItem*, ARDOUR::AlignChoice, bool apply_to_selection = false);
 
        void         playlist_click ();
        void         show_playlist_selector ();
index b0896349b55e646bb2c5bafdcc8c6703e353d181..c6651473e5e9b5502299f8648d650892d198016d 100644 (file)
@@ -75,9 +75,10 @@ class Diskstream : public SessionObject, public PublicDiskstream
        void set_flag (Flag f)   { _flags = Flag (_flags | f); }
        void unset_flag (Flag f) { _flags = Flag (_flags & ~f); }
 
-       AlignStyle alignment_style() const { return _alignment_style; }
+       AlignStyle  alignment_style() const { return _alignment_style; }
+       AlignChoice alignment_choice() const { return _alignment_choice; }
        void       set_align_style (AlignStyle);
-       void       set_persistent_align_style (AlignStyle a) { _persistent_alignment_style = a; }
+       void       set_align_choice (AlignChoice a);
 
        framecnt_t roll_delay() const { return _roll_delay; }
        void       set_roll_delay (framecnt_t);
@@ -272,6 +273,7 @@ class Diskstream : public SessionObject, public PublicDiskstream
        framepos_t    last_recordable_frame;
        int           last_possibly_recording;
        AlignStyle   _alignment_style;
+       AlignChoice  _alignment_choice;
        bool         _scrubbing;
        bool         _slaved;
        Location*     loop_location;
@@ -294,8 +296,6 @@ class Diskstream : public SessionObject, public PublicDiskstream
        uint32_t     _write_data_count;
 
        bool          in_set_state;
-       AlignStyle   _persistent_alignment_style;
-       bool          first_input_change;
 
        Glib::Mutex state_lock;
 
index 7d720cfa081ca8574533730d57277a411acb2f1d..47285088ff30bfe066e3eb88dd168a70b1fd2c11 100644 (file)
@@ -351,6 +351,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        framecnt_t worst_output_latency () const { return _worst_output_latency; }
        framecnt_t worst_input_latency ()  const { return _worst_input_latency; }
        framecnt_t worst_track_latency ()  const { return _worst_track_latency; }
+       framecnt_t worst_playback_latency () const { return _worst_output_latency + _worst_track_latency; }
 
 #ifdef HAVE_JACK_SESSION 
        void jack_session_event (jack_session_event_t* event);
index 8faff74bc3f2765826c735c1fa3f36bbcb69ed44..aadc2f77978520fcedffbd9620d757d8c29a4cae 100644 (file)
@@ -139,11 +139,13 @@ class Track : public Route, public PublicDiskstream
        ChanCount n_channels ();
        framepos_t get_capture_start_frame (uint32_t n = 0) const;
        AlignStyle alignment_style () const;
+       AlignChoice alignment_choice () const;
        framepos_t current_capture_start () const;
        framepos_t current_capture_end () const;
        void playlist_modified ();
        int use_playlist (boost::shared_ptr<Playlist>);
        void set_align_style (AlignStyle);
+       void set_align_choice (AlignChoice);
        int use_copy_playlist ();
        int use_new_playlist ();
         void adjust_playback_buffering ();
index e0c738270e232d80cdf1cdf072c0c60a77495946..d831dfae2b247464b84780bb94801498f0a50c58 100644 (file)
@@ -168,6 +168,12 @@ namespace ARDOUR {
                ExistingMaterial
        };
 
+       enum AlignChoice {
+               UseCaptureTime,
+               UseExistingMaterial,
+                Automatic
+       };
+
        enum MeterPoint {
                MeterInput,
                MeterPreFader,
index 6da9fb6f0a24eec52e62c40a1609f4115126dcb9..dd4310294b3e494edd41034db3b95914acbc6be7 100644 (file)
@@ -177,13 +177,7 @@ AudioDiskstream::non_realtime_input_change ()
 
                get_input_sources ();
                set_capture_offset ();
-
-               if (first_input_change) {
-                       set_align_style (_persistent_alignment_style);
-                       first_input_change = false;
-               } else {
-                       set_align_style_from_io ();
-               }
+                set_align_style_from_io ();
 
                input_change_pending = IOChange::NoChange;
 
@@ -1554,7 +1548,7 @@ AudioDiskstream::transport_looped (framepos_t transport_frame)
                        capture_captured += _capture_offset;
 
                        if (_alignment_style == ExistingMaterial) {
-                               capture_captured += _session.worst_output_latency();
+                               capture_captured += _session.worst_playback_latency();
                        } else {
                                capture_captured += _roll_delay;
                        }
@@ -2006,6 +2000,10 @@ AudioDiskstream::set_align_style_from_io ()
 {
        bool have_physical = false;
 
+        if (_alignment_choice != Automatic) {
+                return;
+        }
+
        if (_io == 0) {
                return;
        }
index 97780972f8d20e3fe3a8e7fd9b5389c1ec02f240..647d62e00f3d548ffb98a82dea44e243c0ee1f2c 100644 (file)
 #include <sys/mman.h>
 
 
+#include <glibmm/thread.h>
+
 #include "pbd/error.h"
 #include "pbd/basename.h"
-#include <glibmm/thread.h>
-#include "pbd/xml++.h"
 #include "pbd/memento_command.h"
+#include "pbd/xml++.h"
 
 #include "ardour/ardour.h"
 #include "ardour/audioengine.h"
@@ -93,6 +94,7 @@ Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
         , last_recordable_frame (max_framepos)
         , last_possibly_recording (0)
         , _alignment_style (ExistingMaterial)
+        , _alignment_choice (Automatic)
         , _scrubbing (false)
         , _slaved (false)
         , loop_location (0)
@@ -110,8 +112,6 @@ Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
         , _read_data_count (0)
         , _write_data_count (0)
         , in_set_state (false)
-        , _persistent_alignment_style (ExistingMaterial)
-        , first_input_change (true)
         , _flags (flag)
         , deprecated_io_node (0)
 {
@@ -137,6 +137,7 @@ Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/)
         , last_recordable_frame (max_framepos)
         , last_possibly_recording (0)
         , _alignment_style (ExistingMaterial)
+        , _alignment_choice (Automatic)
         , _scrubbing (false)
         , _slaved (false)
         , loop_location (0)
@@ -154,8 +155,6 @@ Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/)
         , _read_data_count (0)
         , _write_data_count (0)
         , in_set_state (false)
-        , _persistent_alignment_style (ExistingMaterial)
-        , first_input_change (true)
         , _flags (Recordable)
         , deprecated_io_node (0)
 {
@@ -270,6 +269,7 @@ Diskstream::set_capture_offset ()
         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: using IO latency, capture offset set to %2\n", name(), _capture_offset));
 }
 
+
 void
 Diskstream::set_align_style (AlignStyle a)
 {
@@ -283,6 +283,30 @@ Diskstream::set_align_style (AlignStyle a)
        }
 }
 
+void
+Diskstream::set_align_choice (AlignChoice a)
+{
+       if (record_enabled() && _session.actively_recording()) {
+               return;
+       }
+
+       if (a != _alignment_choice) {
+               _alignment_choice = a;
+
+                switch (_alignment_choice) {
+                case Automatic:
+                        set_align_style_from_io ();
+                        break;
+                case UseExistingMaterial:
+                        set_align_style (ExistingMaterial);
+                        break;
+                case UseCaptureTime:
+                        set_align_style (CaptureTime);
+                        break;
+                }
+       }
+}
+
 int
 Diskstream::set_loop (Location *location)
 {
@@ -452,6 +476,7 @@ Diskstream::get_state ()
        node->add_property("id", buf);
        snprintf (buf, sizeof(buf), "%f", _visible_speed);
        node->add_property ("speed", buf);
+        node->add_property ("capture-alignment", enum_2_string (_alignment_choice));
 
        if (_extra_xml) {
                node->add_child_copy (*_extra_xml);
@@ -483,6 +508,12 @@ Diskstream::set_state (const XMLNode& node, int /*version*/)
                _flags = Flag (string_2_enum (prop->value(), _flags));
        }
 
+        if ((prop = node.property (X_("capture-alignment"))) != 0) {
+                _alignment_choice = AlignChoice (string_2_enum (prop->value(), _alignment_choice));
+        } else {
+                _alignment_choice = Automatic;
+        }
+
        if ((prop = node.property ("playlist")) == 0) {
                return -1;
        }
@@ -621,10 +652,10 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
                last_recordable_frame = max_framepos;
                capture_start_frame = transport_frame;
 
-                DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 basic FRF = %2 LRF = %3 CSF = %4 CO = %5, WLO = %6\n",
+                DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 basic FRF = %2 LRF = %3 CSF = %4 CO = %5, WPL = %6\n",
                                                                       name(), first_recordable_frame, last_recordable_frame, capture_start_frame,
                                                                       _capture_offset,
-                                                                      _session.worst_output_latency(),
+                                                                      _session.worst_playback_latency(),
                                                                       transport_frame));
 
                 
@@ -635,13 +666,13 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
                         
                        if (_alignment_style == ExistingMaterial) {
                                 
-                                /* audio played by ardour will take (up to) _session.worst_output_latency() ("WOL") to
+                                /* audio played by ardour will take (up to) _session.worst_playback_latency() ("WOL") to
                                    appear at the speakers; audio played at the time when it does appear at
                                    the speakers will take _capture_offset to arrive back here. we've
                                    already added _capture_offset, so now add WOL.
                                 */
                                 
-                                first_recordable_frame += _session.worst_output_latency();
+                                first_recordable_frame += _session.worst_playback_latency();
                                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tROLL: shift FRF by delta between WOL %1\n",
                                                                                       first_recordable_frame));
                         } else {
@@ -657,7 +688,7 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
                        if (_alignment_style == ExistingMaterial) {
 
                                 /* see comment in ExistingMaterial block above */
-                                first_recordable_frame += _session.worst_output_latency();
+                                first_recordable_frame += _session.worst_playback_latency();
                                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tMANUAL PUNCH: shift FRF by delta between WOL and CO to %1\n",
                                                                                       first_recordable_frame));
                        } else {
index a524db3d23b0c68e61a070da908ef614014babe7..878da1e381bf14345b38f4bbadf99c1671089b57 100644 (file)
@@ -54,6 +54,7 @@ setup_enum_writer ()
 
        OverlapType _OverlapType;
        AlignStyle _AlignStyle;
+       AlignChoice _AlignChoice;
        MeterPoint _MeterPoint;
        TrackMode _TrackMode;
        NoteMode _NoteMode;
@@ -162,6 +163,11 @@ setup_enum_writer ()
        REGISTER_ENUM (ExistingMaterial);
        REGISTER (_AlignStyle);
 
+       REGISTER_ENUM (UseCaptureTime);
+       REGISTER_ENUM (UseExistingMaterial);
+       REGISTER_ENUM (Automatic);
+       REGISTER (_AlignChoice);
+
        REGISTER_ENUM (MeterInput);
        REGISTER_ENUM (MeterPreFader);
        REGISTER_ENUM (MeterPostFader);
index 0a9b361f351b3dbfc619d10ffe2c69e723d400ee..e2233fa418398ba4cfe8ea70981a8bf0b574f39c 100644 (file)
@@ -171,13 +171,7 @@ MidiDiskstream::non_realtime_input_change ()
 
                get_input_sources ();
                set_capture_offset ();
-
-               if (first_input_change) {
-                       set_align_style (_persistent_alignment_style);
-                       first_input_change = false;
-               } else {
-                       set_align_style_from_io ();
-               }
+                set_align_style_from_io ();
 
                input_change_pending.type = IOChange::NoChange;
 
@@ -1110,7 +1104,7 @@ MidiDiskstream::transport_looped (framepos_t transport_frame)
                        capture_captured += _capture_offset;
 
                        if (_alignment_style == ExistingMaterial) {
-                               capture_captured += _session.worst_output_latency();
+                               capture_captured += _session.worst_playback_latency();
                        } else {
                                capture_captured += _roll_delay;
                        }
@@ -1389,6 +1383,10 @@ MidiDiskstream::set_align_style_from_io ()
 {
        bool have_physical = false;
 
+        if (_alignment_choice != Automatic) {
+                return;
+        }
+
        if (_io == 0) {
                return;
        }
index 9564770f7f95ba7bdfc0431cf95fad198fb1782f..ee9bef05702eb844e68a54043151eb379f696c4f 100644 (file)
@@ -212,7 +212,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
                   frames. Also compensate for audio latency.
                */
                
-               mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
+               mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_playback_latency();
 
 
                if (now) {
index 759495351a8fbc9cf40743b574b5ee29f86b3584..787de5993cb119ea14d375ad56703b85631d8c5d 100644 (file)
@@ -1106,7 +1106,7 @@ Session::audible_frame () const
           in the absence of any plugin latency compensation
        */
 
-       offset = _worst_output_latency;
+       offset = worst_playback_latency ();
 
        if (offset > current_block_size) {
                offset -= current_block_size;
index ae6d3830929633a01d1e5842e5627eb816c4f0d1..df1abba5ddbd1f70d9d4ecd384ba57240b341cb5 100644 (file)
@@ -379,7 +379,7 @@ Session::send_full_time_code (framepos_t const t)
        }
 
        // Compensate for audio latency
-       outbound_mtc_timecode_frame += _worst_output_latency;
+       outbound_mtc_timecode_frame += worst_playback_latency();
        next_quarter_frame_to_send = 0;
 
        // Sync slave to the same Timecode time as we are on
index dcbf25777a7b11574ebca27d1a627fb44a6c9bcd..f06e34849b8ad7974e4a6ec721926dc6908ca1c7 100644 (file)
@@ -222,11 +222,11 @@ Session::realtime_stop (bool abort, bool clear_state)
                   past that point to pick up delayed input (and/or to delick)
                */
 
-                if (_worst_output_latency > current_block_size) {
+                if (worst_playback_latency() > current_block_size) {
                         /* we rolled past the stop point to pick up data that had
                            not yet arrived. move back to where the stop occured.
                         */
-                        decrement_transport_position (current_block_size + (_worst_output_latency - current_block_size));
+                        decrement_transport_position (current_block_size + (worst_playback_latency() - current_block_size));
                 } else {
                         decrement_transport_position (current_block_size);
                 }
@@ -1041,7 +1041,7 @@ Session::stop_transport (bool abort, bool clear_state)
                return;
        }
 
-       if (actively_recording() && !(transport_sub_state & StopPendingCapture) && _worst_output_latency > current_block_size) {
+       if (actively_recording() && !(transport_sub_state & StopPendingCapture) && worst_playback_latency() > current_block_size) {
 
                boost::shared_ptr<RouteList> rl = routes.reader();
                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
@@ -1060,8 +1060,8 @@ Session::stop_transport (bool abort, bool clear_state)
                */
 
                SessionEvent *ev = new SessionEvent (SessionEvent::StopOnce, SessionEvent::Replace,
-                                      _transport_frame + _worst_output_latency - current_block_size,
-                                      0, 0, abort);
+                                                     _transport_frame + _worst_input_latency - current_block_size,
+                                                     0, 0, abort);
 
                merge_event (ev);
                transport_sub_state |= StopPendingCapture;
index be992eaa61b20cb45558874ab57da94d3392756c..d51344eb0d45572180fd04ac51a34ca718a82fca 100644 (file)
@@ -563,6 +563,12 @@ Track::alignment_style () const
        return _diskstream->alignment_style ();
 }
 
+AlignChoice
+Track::alignment_choice () const
+{
+       return _diskstream->alignment_choice ();
+}
+
 framepos_t
 Track::current_capture_start () const
 {
@@ -611,6 +617,12 @@ Track::set_align_style (AlignStyle s)
        _diskstream->set_align_style (s);
 }
 
+void
+Track::set_align_choice (AlignChoice s)
+{
+       _diskstream->set_align_choice (s);
+}
+
 uint32_t
 Track::write_data_count () const
 {