summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2012-10-12 09:45:22 +0000
committerRobin Gareus <robin@gareus.org>2012-10-12 09:45:22 +0000
commitbce3184ff5383f47675a97a8184f7739552cb04e (patch)
treef74f770085dfb11a2b419cd3af197d3bc489e260 /libs/ardour
parent8f55ca6a5099f44de83330d3da267bd32fd769d9 (diff)
skeleton framework for LTC-slave
git-svn-id: svn://localhost/ardour2/branches/3.0@13256 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/audioengine.h8
-rw-r--r--libs/ardour/ardour/slave.h37
-rw-r--r--libs/ardour/ardour/types.h3
-rw-r--r--libs/ardour/audioengine.cc3
-rw-r--r--libs/ardour/enums.cc1
-rw-r--r--libs/ardour/globals.cc3
-rw-r--r--libs/ardour/ltc_slave.cc175
-rw-r--r--libs/ardour/session_transport.cc18
-rw-r--r--libs/ardour/utils.cc3
-rw-r--r--libs/ardour/wscript6
10 files changed, 256 insertions, 1 deletions
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index 1c0d0f1a55..4e55ea2140 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -260,6 +260,10 @@ _ the regular process() call to session->process() is not made.
int create_process_thread (boost::function<void()>, pthread_t*, size_t stacksize);
+#ifdef HAVE_LTC
+ Port *ltc_input_port() const { return _ltc_input; }
+#endif
+
private:
static AudioEngine* _instance;
@@ -289,6 +293,10 @@ private:
Glib::Threads::Thread* m_meter_thread;
ProcessThread* _main_thread;
+#ifdef HAVE_LTC
+ Port* _ltc_input;
+#endif
+
SerializedRCUManager<Ports> ports;
boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input);
diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h
index a8bf28b8ce..b64ba3f42e 100644
--- a/libs/ardour/ardour/slave.h
+++ b/libs/ardour/ardour/slave.h
@@ -32,6 +32,10 @@
#include "midi++/parser.h"
#include "midi++/types.h"
+#ifdef HAVE_LTC
+#include <ltc.h>
+#endif
+
namespace MIDI {
class Port;
}
@@ -293,6 +297,39 @@ class MTC_Slave : public Slave {
void init_engine_dll (framepos_t, framepos_t);
};
+#ifdef HAVE_LTC
+class LTC_Slave : public Slave {
+ public:
+ LTC_Slave (Session&);
+ ~LTC_Slave ();
+
+ bool speed_and_position (double&, framepos_t&);
+
+ bool locked() const;
+ bool ok() const;
+
+ framecnt_t resolution () const;
+ bool requires_seekahead () const { return true; }
+ framecnt_t seekahead_distance() const;
+ bool give_slave_full_control_over_transport_speed() const;
+
+ private:
+ int parse_ltc(const jack_nframes_t nframes, const jack_default_audio_sample_t * const in, const framecnt_t posinfo);
+ void process_ltc();
+
+ Session& session;
+ bool did_reset_tc_format;
+ Timecode::TimecodeFormat saved_tc_format;
+
+ LTCDecoder *decoder;
+ framecnt_t current_frames_per_ltc_frame;
+ framecnt_t monotonic_fcnt;
+
+ framepos_t ltc_transport_pos;
+ double ltc_speed;
+};
+#endif
+
class MIDIClock_Slave : public Slave {
public:
MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24);
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index b84eb8e7f6..5bd03d2788 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -462,7 +462,8 @@ namespace ARDOUR {
enum SyncSource {
JACK,
MTC,
- MIDIClock
+ MIDIClock,
+ LTC
};
enum ShuttleBehaviour {
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 450bf2a296..9fb1d1d706 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -89,6 +89,9 @@ AudioEngine::AudioEngine (string client_name, string session_uuid)
}
Port::set_engine (this);
+#ifdef HAVE_LTC
+ _ltc_input = new AudioPort ("LTC in", Port::IsInput);
+#endif
}
AudioEngine::~AudioEngine ()
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index 5776db21c7..6c82792328 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -307,6 +307,7 @@ setup_enum_writer ()
REGISTER_ENUM (MTC);
REGISTER_ENUM (JACK);
REGISTER_ENUM (MIDIClock);
+ REGISTER_ENUM (LTC);
REGISTER (_SyncSource);
REGISTER_ENUM (Sprung);
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 78ed2ff472..3895bd76a7 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -485,6 +485,9 @@ ARDOUR::get_available_sync_options ()
ret.push_back (JACK);
ret.push_back (MTC);
ret.push_back (MIDIClock);
+#ifdef HAVE_LTC
+ ret.push_back (LTC);
+#endif
return ret;
}
diff --git a/libs/ardour/ltc_slave.cc b/libs/ardour/ltc_slave.cc
new file mode 100644
index 0000000000..cc86189d8c
--- /dev/null
+++ b/libs/ardour/ltc_slave.cc
@@ -0,0 +1,175 @@
+/*
+ Copyright (C) 2012 Paul Davis
+ Witten by 2012 Robin Gareus <robin@gareus.org>
+
+ 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.
+
+*/
+#include <iostream>
+#include <errno.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "pbd/error.h"
+
+#include "ardour/debug.h"
+#include "ardour/slave.h"
+#include "ardour/session.h"
+#include "ardour/audioengine.h"
+#include "ardour/audio_port.h"
+
+#include "i18n.h"
+
+using namespace std;
+using namespace ARDOUR;
+using namespace MIDI;
+using namespace PBD;
+using namespace Timecode;
+
+LTC_Slave::LTC_Slave (Session& s)
+ : session (s)
+{
+ current_frames_per_ltc_frame = 1920; // samplerate / framerate
+ ltc_transport_pos = 0;
+ ltc_speed = 1.0;
+ monotonic_fcnt = 0;
+
+ decoder = ltc_decoder_create(current_frames_per_ltc_frame, 128 /*queue size*/);
+}
+
+LTC_Slave::~LTC_Slave()
+{
+ if (did_reset_tc_format) {
+ session.config.set_timecode_format (saved_tc_format);
+ }
+
+ ltc_decoder_free(decoder);
+}
+
+bool
+LTC_Slave::give_slave_full_control_over_transport_speed() const
+{
+ return true; // DLL align to engine transport
+ // return false; // for Session-level computed varispeed
+}
+
+ARDOUR::framecnt_t
+LTC_Slave::resolution () const
+{
+ return current_frames_per_ltc_frame;
+}
+
+ARDOUR::framecnt_t
+LTC_Slave::seekahead_distance () const
+{
+ return current_frames_per_ltc_frame * 2;
+}
+
+bool
+LTC_Slave::locked () const
+{
+ return true;
+}
+
+bool
+LTC_Slave::ok() const
+{
+ return true;
+}
+
+int
+LTC_Slave::parse_ltc(const jack_nframes_t nframes, const jack_default_audio_sample_t * const in, const framecnt_t posinfo)
+{
+ jack_nframes_t i;
+ unsigned char sound[8192];
+ if (nframes > 8192) return 1;
+
+ for (i = 0; i < nframes; i++) {
+ const int snd=(int)rint((127.0*in[i])+128.0);
+ sound[i] = (unsigned char) (snd&0xff);
+ }
+ ltc_decoder_write(decoder, sound, nframes, posinfo);
+ return 0;
+}
+
+void
+LTC_Slave::process_ltc()
+{
+ LTCFrameExt frame;
+ while (ltc_decoder_read(decoder,&frame)) {
+ SMPTETimecode stime;
+ ltc_frame_to_time(&stime, &frame.ltc, 0);
+
+ fprintf(stdout, "%02d:%02d:%02d%c%02d | %8lld %8lld%s\n",
+ stime.hours,
+ stime.mins,
+ stime.secs,
+ (frame.ltc.dfbit) ? '.' : ':',
+ stime.frame,
+ frame.off_start,
+ frame.off_end,
+ frame.reverse ? " R" : " "
+ );
+
+ /* when a full LTC frame is decoded, the timecode the LTC frame
+ * is referring has just passed.
+ * So we send the _next_ timecode which
+ * is expected to start at the end of the current frame
+ */
+
+ int detected_fps = 25; // XXX
+ if (!frame.reverse) {
+ ltc_frame_increment(&frame.ltc, detected_fps , 0);
+ ltc_frame_to_time(&stime, &frame.ltc, 0);
+ } else {
+ ltc_frame_decrement(&frame.ltc, detected_fps , 0);
+ int off = frame.off_end - frame.off_start;
+ frame.off_start += off;
+ frame.off_end += off;
+ }
+ }
+}
+
+/* main entry point from session_process.cc
+ * called from jack_process callback context
+ */
+bool
+LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
+{
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("LTC_Slave::speed_and_position - TID:%1\n", ::pthread_self()));
+ framepos_t now = session.engine().frame_time_at_cycle_start();
+ framepos_t sess_pos = session.transport_frame(); // corresponds to now
+ framecnt_t nframes = session.engine().frames_per_cycle();
+
+ jack_port_t *ltc_port = session.engine().ltc_input_port()->jack_port();
+ jack_default_audio_sample_t *in;
+ in = (jack_default_audio_sample_t*) jack_port_get_buffer (ltc_port, nframes);
+
+ //in = session.engine().ltc_input_port()->engine_get_whole_audio_buffer()
+ // TODO: get capture latency for ltc_port.
+
+ if (in) {
+ parse_ltc(nframes, in, monotonic_fcnt /* + jltc_latency*/ );
+ process_ltc();
+ }
+
+ /* fake for testing */
+ ltc_transport_pos += nframes * ltc_speed;
+ pos = ltc_transport_pos;
+ speed = ltc_speed;
+
+ monotonic_fcnt += nframes;
+}
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index b55fdfaa33..d4a0a010c9 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -1372,6 +1372,24 @@ Session::switch_to_sync_source (SyncSource src)
}
break;
+ case LTC:
+#ifdef HAVE_LTC
+ if (_slave && dynamic_cast<LTC_Slave*>(_slave)) {
+ return;
+ }
+
+ try {
+ new_slave = new LTC_Slave (*this);
+ }
+
+ catch (failed_constructor& err) {
+ return;
+ }
+#else
+ return;
+#endif
+ break;
+
case MIDIClock:
if (_slave && dynamic_cast<MIDIClock_Slave*>(_slave)) {
return;
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 7751ea20ca..904750e9d8 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -452,6 +452,9 @@ sync_source_to_string (SyncSource src, bool sh)
case MIDIClock:
return _("MIDI Clock");
+
+ case LTC:
+ return _("LTC");
}
/* GRRRR .... stupid, stupid gcc - you can't get here from there, all enum values are handled */
return _("JACK");
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 3a61df11d7..ddcb5e00e5 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -281,6 +281,8 @@ def configure(conf):
atleast_version='1.2.1')
autowaf.check_pkg(conf, 'libcurl', uselib_store='CURL',
atleast_version='7.0.0')
+ autowaf.check_pkg(conf, 'ltc', uselib_store='LTC',
+ atleast_version='0.3.2', mandatory=False)
# we don't try to detect this, since its part of our source tree
@@ -381,6 +383,10 @@ def build(bld):
#obj.uselib += ' SOUNDTOUCH '
#obj.add_objects = 'default/libs/surfaces/control_protocol/smpte_1.o'
+ if bld.is_defined('HAVE_LTC') :
+ obj.source += ['ltc_slave.cc']
+ obj.uselib += ['LTC']
+
if bld.is_defined('HAVE_LILV') :
obj.source += ['lv2_plugin.cc', 'lv2_evbuf.c', 'uri_map.cc']
obj.uselib += ['LILV']