summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/slave.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/ardour/slave.h')
-rw-r--r--libs/ardour/ardour/slave.h510
1 files changed, 0 insertions, 510 deletions
diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h
deleted file mode 100644
index 2a05268c77..0000000000
--- a/libs/ardour/ardour/slave.h
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- Copyright (C) 2002 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_slave_h__
-#define __ardour_slave_h__
-
-#include <vector>
-
-#include <glibmm/threads.h>
-
-#include <ltc.h>
-
-#include "pbd/signals.h"
-
-#include "temporal/time.h"
-
-#include "ardour/libardour_visibility.h"
-#include "ardour/types.h"
-#include "midi++/parser.h"
-#include "midi++/types.h"
-
-
-/* used for delta_string(): */
-#define PLUSMINUS(A) ( ((A)<0) ? "-" : (((A)>0) ? "+" : "\u00B1") )
-#define LEADINGZERO(A) ( (A)<10 ? " " : (A)<100 ? " " : (A)<1000 ? " " : "" )
-
-namespace ARDOUR {
-
-class TempoMap;
-class Session;
-class AudioEngine;
-class MidiPort;
-
-/**
- * @class Slave
- *
- * @brief The Slave interface can be used to sync ARDOURs tempo to an external source
- * like MTC, MIDI Clock, etc.
- *
- * The name of the interface may be a bit misleading: A subclass of Slave actually
- * acts as a time master for ARDOUR, that means ARDOUR will try to follow the
- * speed and transport position of the implementation of Slave.
- * Therefore it is rather that class, that makes ARDOUR a slave by connecting it
- * to its external time master.
- */
-class LIBARDOUR_API Slave {
- public:
- Slave() { }
- virtual ~Slave() {}
-
- /**
- * This is the most important function to implement:
- * Each process cycle, Session::follow_slave will call this method.
- * and after the method call they should
- *
- * Session::follow_slave will then try to follow the given
- * <em>position</em> using a delay locked loop (DLL),
- * starting with the first given transport speed.
- * If the values of speed and position contradict each other,
- * ARDOUR will always follow the position and disregard the speed.
- * Although, a correct speed is important so that ARDOUR
- * can sync to the master time source quickly.
- *
- * For background information on delay locked loops,
- * see http://www.kokkinizita.net/papers/usingdll.pdf
- *
- * The method has the following precondition:
- * <ul>
- * <li>
- * Slave::ok() should return true, otherwise playback will stop
- * immediately and the method will not be called
- * </li>
- * <li>
- * when the references speed and position are passed into the Slave
- * they are uninitialized
- * </li>
- * </ul>
- *
- * After the method call the following postconditions should be met:
- * <ul>
- * <li>
- * The first position value on transport start should be 0,
- * otherwise ARDOUR will try to locate to the new position
- * rather than move to it
- * </li>
- * <li>
- * the references speed and position should be assigned
- * to the Slaves current requested transport speed
- * and transport position.
- * </li>
- * <li>
- * Slave::resolution() should be greater than the maximum distance of
- * ARDOURs transport position to the slaves requested transport position.
- * </li>
- * <li>Slave::locked() should return true, otherwise Session::no_roll will be called</li>
- * <li>Slave::starting() should be false, otherwise the transport will not move until it becomes true</li> *
- * </ul>
- *
- * @param speed - The transport speed requested
- * @param position - The transport position requested
- * @return - The return value is currently ignored (see Session::follow_slave)
- */
- virtual bool speed_and_position (double& speed, samplepos_t& position) = 0;
-
- /**
- * reports to ARDOUR whether the Slave is currently synced to its external
- * time source.
- *
- * @return - when returning false, the transport will stop rolling
- */
- virtual bool locked() const = 0;
-
- /**
- * reports to ARDOUR whether the slave is in a sane state
- *
- * @return - when returning false, the transport will be stopped and the slave
- * disconnected from ARDOUR.
- */
- virtual bool ok() const = 0;
-
- /**
- * reports to ARDOUR whether the slave is in the process of starting
- * to roll
- *
- * @return - when returning false, transport will not move until this method returns true
- */
- virtual bool starting() const { return false; }
-
- /**
- * @return - the timing resolution of the Slave - If the distance of ARDOURs transport
- * to the slave becomes greater than the resolution, sound will stop
- */
- virtual samplecnt_t resolution() const = 0;
-
- /**
- * @return - when returning true, ARDOUR will wait for seekahead_distance() before transport
- * starts rolling
- */
- virtual bool requires_seekahead () const = 0;
-
- /**
- * @return the number of samples that this slave wants to seek ahead. Relevant
- * only if requires_seekahead() returns true.
- */
-
- virtual samplecnt_t seekahead_distance() const { return 0; }
-
- /**
- * @return - when returning true, ARDOUR will use transport speed 1.0 no matter what
- * the slave returns
- */
- virtual bool is_always_synced() const { return false; }
-
- /**
- * @return - whether ARDOUR should use the slave speed without any adjustments
- */
- virtual bool give_slave_full_control_over_transport_speed() const { return false; }
-
- /**
- * @return - current time-delta between engine and sync-source
- */
- virtual std::string delta_string () const { return ""; }
-
-};
-
-/// We need this wrapper for testability, it's just too hard to mock up a session class
-class LIBARDOUR_API ISlaveSessionProxy {
- public:
- virtual ~ISlaveSessionProxy() {}
- virtual TempoMap& tempo_map() const { return *((TempoMap *) 0); }
- virtual samplecnt_t sample_rate() const { return 0; }
- virtual pframes_t samples_per_cycle() const { return 0; }
- virtual samplepos_t audible_sample () const { return 0; }
- virtual samplepos_t transport_sample () const { return 0; }
- virtual pframes_t samples_since_cycle_start () const { return 0; }
- virtual samplepos_t sample_time_at_cycle_start() const { return 0; }
- virtual samplepos_t sample_time () const { return 0; }
-};
-
-
-/// The Session Proxy for use in real Ardour
-class LIBARDOUR_API SlaveSessionProxy : public ISlaveSessionProxy {
- Session& session;
-
- public:
- SlaveSessionProxy(Session &s) : session(s) {}
-
- TempoMap& tempo_map() const;
- samplecnt_t sample_rate() const;
- pframes_t samples_per_cycle() const;
- samplepos_t audible_sample () const;
- samplepos_t transport_sample () const;
- pframes_t samples_since_cycle_start () const;
- samplepos_t sample_time_at_cycle_start() const;
- samplepos_t sample_time () const;
-};
-
-struct LIBARDOUR_API SafeTime {
- volatile int guard1;
- samplepos_t position;
- samplepos_t timestamp;
- double speed;
- volatile int guard2;
-
- SafeTime() {
- guard1 = 0;
- position = 0;
- timestamp = 0;
- speed = 0;
- guard2 = 0;
- }
-};
-
-class LIBARDOUR_API TimecodeSlave : public Slave {
- public:
- TimecodeSlave () {}
-
- virtual Timecode::TimecodeFormat apparent_timecode_format() const = 0;
-
- /* this is intended to be used by a UI and polled from a timeout. it should
- return a string describing the current position of the TC source. it
- should NOT do any computation, but should use a cached value
- of the TC source position.
- */
- virtual std::string position_string () const = 0;
-
- samplepos_t timecode_offset;
- bool timecode_negative_offset;
-
- PBD::Signal1<void, bool> ActiveChanged;
-};
-
-class LIBARDOUR_API MTC_Slave : public TimecodeSlave {
- public:
- MTC_Slave (Session&, MidiPort&);
- ~MTC_Slave ();
-
- void rebind (MidiPort&);
- bool speed_and_position (double&, samplepos_t&);
-
- bool locked() const;
- bool ok() const;
- void handle_locate (const MIDI::byte*);
-
- samplecnt_t resolution () const;
- bool requires_seekahead () const { return false; }
- samplecnt_t seekahead_distance() const;
- bool give_slave_full_control_over_transport_speed() const;
-
- Timecode::TimecodeFormat apparent_timecode_format() const;
- std::string position_string () const;
- std::string delta_string () const;
-
- private:
- Session& session;
- MidiPort* port;
- PBD::ScopedConnectionList port_connections;
- PBD::ScopedConnection config_connection;
- bool can_notify_on_unknown_rate;
-
- static const int sample_tolerance;
-
- SafeTime current;
- samplepos_t mtc_frame; /* current time */
- double mtc_frame_dll;
- samplepos_t last_inbound_frame; /* when we got it; audio clocked */
- MIDI::byte last_mtc_fps_byte;
- samplepos_t window_begin;
- samplepos_t window_end;
- samplepos_t first_mtc_timestamp;
- bool did_reset_tc_format;
- Timecode::TimecodeFormat saved_tc_format;
- Glib::Threads::Mutex reset_lock;
- uint32_t reset_pending;
- bool reset_position;
- int transport_direction;
- int busy_guard1;
- int busy_guard2;
-
- double speedup_due_to_tc_mismatch;
- double quarter_frame_duration;
- Timecode::TimecodeFormat mtc_timecode;
- Timecode::TimecodeFormat a3e_timecode;
- Timecode::Time timecode;
- bool printed_timecode_warning;
- sampleoffset_t current_delta;
-
- /* DLL - chase MTC */
- double t0; ///< time at the beginning of the MTC quater sample
- double t1; ///< calculated end of the MTC quater sample
- double e2; ///< second order loop error
- double b, c, omega; ///< DLL filter coefficients
-
- /* DLL - sync engine */
- int engine_dll_initstate;
- double te0; ///< time at the beginning of the engine process
- double te1; ///< calculated sync time
- double ee2; ///< second order loop error
- double be, ce, oe; ///< DLL filter coefficients
-
- void reset (bool with_pos);
- void queue_reset (bool with_pos);
- void maybe_reset ();
-
- void update_mtc_qtr (MIDI::Parser&, int, samplepos_t);
- void update_mtc_time (const MIDI::byte *, bool, samplepos_t);
- void update_mtc_status (MIDI::MTC_Status);
- void read_current (SafeTime *) const;
- void reset_window (samplepos_t);
- bool outside_window (samplepos_t) const;
- void init_mtc_dll(samplepos_t, double);
- void init_engine_dll (samplepos_t, samplepos_t);
- void parse_timecode_offset();
- void parameter_changed(std::string const & p);
-};
-
-class LIBARDOUR_API LTC_Slave : public TimecodeSlave {
-public:
- LTC_Slave (Session&);
- ~LTC_Slave ();
-
- bool speed_and_position (double&, samplepos_t&);
-
- bool locked() const;
- bool ok() const;
-
- samplecnt_t resolution () const;
- bool requires_seekahead () const { return false; }
- samplecnt_t seekahead_distance () const { return 0; }
- bool give_slave_full_control_over_transport_speed() const { return true; }
-
- Timecode::TimecodeFormat apparent_timecode_format() const;
- std::string position_string() const;
- std::string delta_string() const;
-
- private:
- void parse_ltc(const pframes_t, const Sample* const, const samplecnt_t);
- void process_ltc(samplepos_t const);
- void init_engine_dll (samplepos_t, int32_t);
- bool detect_discontinuity(LTCFrameExt *, int, bool);
- bool detect_ltc_fps(int, bool);
- bool equal_ltc_sample_time(LTCFrame *a, LTCFrame *b);
- void reset (bool with_ts = true);
- void resync_xrun();
- void resync_latency();
- void parse_timecode_offset();
- void parameter_changed(std::string const & p);
-
- Session& session;
- bool did_reset_tc_format;
- Timecode::TimecodeFormat saved_tc_format;
-
- LTCDecoder * decoder;
- double samples_per_ltc_frame;
- Timecode::Time timecode;
- LTCFrameExt prev_sample;
- bool fps_detected;
-
- samplecnt_t monotonic_cnt;
- samplecnt_t last_timestamp;
- samplecnt_t last_ltc_sample;
- double ltc_speed;
- sampleoffset_t current_delta;
- int delayedlocked;
-
- int ltc_detect_fps_cnt;
- int ltc_detect_fps_max;
- bool printed_timecode_warning;
- bool sync_lock_broken;
- Timecode::TimecodeFormat ltc_timecode;
- Timecode::TimecodeFormat a3e_timecode;
-
- PBD::ScopedConnectionList port_connections;
- PBD::ScopedConnection config_connection;
- LatencyRange ltc_slave_latency;
-
- /* DLL - chase LTC */
- int transport_direction;
- int engine_dll_initstate;
- double t0; ///< time at the beginning of the MTC quater sample
- double t1; ///< calculated end of the MTC quater sample
- double e2; ///< second order loop error
- double b, c; ///< DLL filter coefficients
-};
-
-class LIBARDOUR_API MIDIClock_Slave : public Slave {
- public:
- MIDIClock_Slave (Session&, MidiPort&, int ppqn = 24);
-
- /// Constructor for unit tests
- MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24);
- ~MIDIClock_Slave ();
-
- void rebind (MidiPort&);
- bool speed_and_position (double&, samplepos_t&);
-
- bool locked() const;
- bool ok() const;
- bool starting() const;
-
- samplecnt_t resolution () const;
- bool requires_seekahead () const { return false; }
- bool give_slave_full_control_over_transport_speed() const { return true; }
-
- void set_bandwidth (double a_bandwith) { bandwidth = a_bandwith; }
- std::string delta_string () const;
-
- protected:
- ISlaveSessionProxy* session;
- PBD::ScopedConnectionList port_connections;
-
- /// pulses per quarter note for one MIDI clock sample (default 24)
- int ppqn;
-
- /// the duration of one ppqn in sample time
- double one_ppqn_in_samples;
-
- /// the timestamp of the first MIDI clock message
- samplepos_t first_timestamp;
-
- /// the time stamp and should-be transport position of the last inbound MIDI clock message
- samplepos_t last_timestamp;
- double should_be_position;
-
- /// the number of midi clock messages received (zero-based)
- /// since start
- long midi_clock_count;
-
- //the delay locked loop (DLL), see www.kokkinizita.net/papers/usingdll.pdf
-
- /// time at the beginning of the MIDI clock sample
- double t0;
-
- /// calculated end of the MIDI clock sample
- double t1;
-
- /// loop error = real value - expected value
- double e;
-
- /// second order loop error
- double e2;
-
- /// DLL filter bandwidth
- double bandwidth;
-
- /// DLL filter coefficients
- double b, c, omega;
-
- sampleoffset_t current_delta;
-
- void reset ();
- void start (MIDI::Parser& parser, samplepos_t timestamp);
- void contineu (MIDI::Parser& parser, samplepos_t timestamp);
- void stop (MIDI::Parser& parser, samplepos_t timestamp);
- void position (MIDI::Parser& parser, MIDI::byte* message, size_t size);
- // we can't use continue because it is a C++ keyword
- void calculate_one_ppqn_in_samples_at(samplepos_t time);
- samplepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
- void calculate_filter_coefficients();
- void update_midi_clock (MIDI::Parser& parser, samplepos_t timestamp);
- void read_current (SafeTime *) const;
- bool stop_if_no_more_clock_events(samplepos_t& pos, samplepos_t now);
-
- /// whether transport should be rolling
- bool _started;
-
- /// is true if the MIDI Start message has just been received until
- /// the first MIDI Clock Event
- bool _starting;
-};
-
-class LIBARDOUR_API Engine_Slave : public Slave
-{
- public:
- Engine_Slave (AudioEngine&);
- ~Engine_Slave ();
-
- bool speed_and_position (double& speed, samplepos_t& pos);
-
- bool starting() const { return _starting; }
- bool locked() const;
- bool ok() const;
- samplecnt_t resolution () const { return 1; }
- bool requires_seekahead () const { return false; }
- bool is_always_synced() const { return true; }
-
- private:
- AudioEngine& engine;
- bool _starting;
-};
-
-} /* namespace */
-
-#endif /* __ardour_slave_h__ */