diff --git a/manual/documentation.tsc b/manual/documentation.tsc index 7747d5f0..8b56ba92 100644 --- a/manual/documentation.tsc +++ b/manual/documentation.tsc @@ -148,6 +148,7 @@ + diff --git a/manual/modltcgen.tex b/manual/modltcgen.tex index a0b052fc..bb3d10af 100644 --- a/manual/modltcgen.tex +++ b/manual/modltcgen.tex @@ -1,9 +1,27 @@ -LTC generator module. +A Linear Time Code (LTC) generator module encodes either session time or wall clock time into LTC code, such as for synchronizing cameras. A jack port is provided through which the signal is transmitted. -\begin{tscattributes} -\indattr{fpsnum} & Frames per second, numerator (default: 25)\\ -\indattr{fpsden} & Frames per second, denominator (default: 1)\\ -\indattr{volume} & Signal volume in dB FS (default: -18)\\ -\indattr{connect} & Space-separated list of output port connections\\ -\end{tscattributes} +\definecolor{shadecolor}{RGB}{255,230,204}\begin{snugshade} +{\footnotesize +\label{attrtab:ltcgen} +Attributes of element {\bf ltcgen}\nopagebreak +\begin{tabularx}{\textwidth}{lXl} +\hline +name & description (type, unit) & def.\\ +\hline +\hline +\indattr{addtime} & Add time, e.g., for time zone compensation (double, s) & 0\\ +\hline +\indattr{connect} & Space-separated list of output port connections (string array) & \\ +\hline +\indattr{fpsden} & Frames per second, denominator (double) & 1\\ +\hline +\indattr{fpsnum} & Frames per second, numerator (double) & 25\\ +\hline +\indattr{usewallclock} & Use wallclock time instead of session time (bool) & false\\ +\hline +\indattr{volume} & Signal volume (double, dB re FS) & -18\\ +\hline +\end{tabularx} +} +\end{snugshade} diff --git a/plugins/src/tascarmod_ltcgen.cc b/plugins/src/tascarmod_ltcgen.cc index 1a07aae1..ed41daa3 100644 --- a/plugins/src/tascarmod_ltcgen.cc +++ b/plugins/src/tascarmod_ltcgen.cc @@ -22,91 +22,117 @@ #include "session.h" #include #include +#include class ltcgen_t : public TASCAR::module_base_t, public jackc_transport_t { public: - ltcgen_t( const TASCAR::module_cfg_t& cfg ); + ltcgen_t(const TASCAR::module_cfg_t& cfg); virtual ~ltcgen_t(); - virtual int process(jack_nframes_t, const std::vector&, const std::vector&,uint32_t tp_frame, bool tp_rolling); + virtual int process(jack_nframes_t, const std::vector&, + const std::vector&, uint32_t tp_frame, + bool tp_rolling); + private: - double fpsnum; - double fpsden; - double volume; + double fpsnum = 25; + double fpsden = 1; + double volume = -18; + double addtime = 0.0; + bool usewallclock = false; std::vector connect; - LTCEncoder* encoder; - ltcsnd_sample_t* enc_buf; + LTCEncoder* encoder = NULL; + ltcsnd_sample_t* enc_buf = NULL; // - uint32_t encoded_data; - uint32_t byteCnt; + uint32_t encoded_data = 0; + uint32_t byteCnt = 0; ltcsnd_sample_t* enc_buf_; - uint32_t lastframe; + uint32_t lastframe = -1; +#ifndef _WIN32 + struct timeval tv; + struct timezone tz; +#endif }; -ltcgen_t::ltcgen_t( const TASCAR::module_cfg_t& cfg ) - : module_base_t( cfg ), - jackc_transport_t("ltc."+session->name), - fpsnum(25), - fpsden(1), - volume(-18), - encoder(NULL), - enc_buf(NULL), - encoded_data(0), - byteCnt(0), - enc_buf_(enc_buf), - lastframe(-1) +ltcgen_t::ltcgen_t(const TASCAR::module_cfg_t& cfg) + : module_base_t(cfg), jackc_transport_t("ltc." + session->name), + enc_buf_(enc_buf) { - GET_ATTRIBUTE_(fpsnum); - GET_ATTRIBUTE_(fpsden); - GET_ATTRIBUTE_(volume); - GET_ATTRIBUTE_(connect); - encoder = ltc_encoder_create(get_srate(), - fpsnum/fpsden, LTC_TV_625_50, 0); + GET_ATTRIBUTE(fpsnum, "", "Frames per second, numerator"); + GET_ATTRIBUTE(fpsden, "", "Frames per second, denominator"); + GET_ATTRIBUTE(volume, "dB re FS", "Signal volume"); + GET_ATTRIBUTE(connect, "", "Space-separated list of output port connections"); + GET_ATTRIBUTE(addtime, "s", "Add time, e.g., for time zone compensation"); + GET_ATTRIBUTE_BOOL(usewallclock, + "Use wallclock time instead of session time"); + encoder = ltc_encoder_create(get_srate(), fpsnum / fpsden, LTC_TV_625_50, 0); enc_buf = new ltcsnd_sample_t[ltc_encoder_get_buffersize(encoder)]; - memset(enc_buf,0,ltc_encoder_get_buffersize(encoder)*sizeof(ltcsnd_sample_t)); + memset(enc_buf, 0, + ltc_encoder_get_buffersize(encoder) * sizeof(ltcsnd_sample_t)); add_output_port("ltc"); activate(); - for(std::vector::const_iterator it=connect.begin();it!=connect.end();++it) - jackc_transport_t::connect(get_client_name()+":ltc",*it,true); + for(std::vector::const_iterator it = connect.begin(); + it != connect.end(); ++it) + jackc_transport_t::connect(get_client_name() + ":ltc", *it, true); } ltcgen_t::~ltcgen_t() { deactivate(); - ltc_encoder_free( encoder ); + ltc_encoder_free(encoder); } -int ltcgen_t::process(jack_nframes_t n, const std::vector& , const std::vector& sOut,uint32_t tp_frame, bool tp_rolling) +int ltcgen_t::process(jack_nframes_t n, const std::vector&, + const std::vector& sOut, uint32_t tp_frame, + bool tp_rolling) { - float smult = pow(10, volume/20.0)/(90.0); - if( tp_frame != lastframe + n){ - double sec(tp_frame*t_sample); + float smult = pow(10, volume / 20.0) / (90.0); + if(tp_frame != lastframe + n) { + double sec(tp_frame * t_sample); + if(usewallclock) { +#ifndef _WIN32 + gettimeofday(&tv, &tz); + struct tm* caltime = localtime(&(tv.tv_sec)); + double p_hour = caltime->tm_hour; + double p_min = caltime->tm_min; + double p_sec = caltime->tm_sec; + p_sec += 0.000001 * tv.tv_usec; +#else + SYSTEMTIME caltime; + GetLocalTime(&caltime); + double p_hour = caltime.wHour; + double p_min = caltime.wMinute; + double p_sec = caltime.wSecond; + p_sec += 0.001 * caltime.wMilliseconds; +#endif + sec = p_sec + 60 * p_min + 3600 * p_hour; + } + sec += addtime; SMPTETimecode st; - memset(st.timezone,0,6); + memset(st.timezone, 0, 6); st.years = 0; st.months = 0; st.days = 0; - st.hours = (int)floor(sec/3600.0); - st.mins = (int)floor((sec-3600.0*floor(sec/3600.0))/60.0); - st.secs = (int)floor(sec)%60; - st.frame = (int)floor((sec-floor(sec))*(double)fpsnum/(double)fpsden); + st.hours = (int)floor(sec / 3600.0); + st.mins = (int)floor((sec - 3600.0 * floor(sec / 3600.0)) / 60.0); + st.secs = (int)floor(sec) % 60; + st.frame = (int)floor((sec - floor(sec)) * (double)fpsnum / (double)fpsden); ltc_encoder_set_timecode(encoder, &st); } lastframe = tp_frame; - if( sOut.size() ){ - for( uint32_t k=0;k= 10 ){ + if(sOut.size()) { + for(uint32_t k = 0; k < n; ++k) { + if(!encoded_data) { + if(byteCnt >= 10) { byteCnt = 0; - if( tp_rolling ) + if(tp_rolling) ltc_encoder_inc_timecode(encoder); } - ltc_encoder_encode_byte(encoder, byteCnt, 1.0); + ltc_encoder_encode_byte(encoder, byteCnt, 1.0); byteCnt++; encoded_data = ltc_encoder_get_buffer(encoder, enc_buf); enc_buf_ = enc_buf; } - if( encoded_data ){ - sOut[0][k] = smult*((float)(*enc_buf_) - 128.0f); + if(encoded_data) { + sOut[0][k] = smult * ((float)(*enc_buf_) - 128.0f); ++enc_buf_; --encoded_data; } @@ -115,10 +141,8 @@ int ltcgen_t::process(jack_nframes_t n, const std::vector& , const std:: return 0; } - REGISTER_MODULE(ltcgen_t); - /* * Local Variables: * mode: c++ @@ -127,4 +151,3 @@ REGISTER_MODULE(ltcgen_t); * compile-command: "make -C .." * End: */ -