/*
- Copyright (C) 1999 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.
-
-*/
+ * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
+ * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
+ * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
+ * Copyright (C) 2007 Doug McLain <doug@nostar.net>
+ * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
+ * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2013-2017 John Emmas <john@creativepost.co.uk>
+ * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
+ * Copyright (C) 2015 Ben Loftis <ben@harrisonconsoles.com>
+ * Copyright (C) 2015 Colin Fletcher <colin.m.fletcher@googlemail.com>
+ * Copyright (C) 2016-2017 Nick Mainsbridge <mainsbridge@gmail.com>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
#include <cstdio> // for sprintf
#include <cmath>
#include "ardour/profile.h"
#include "ardour/lmath.h"
#include "ardour/session.h"
-#include "ardour/slave.h"
+#include "ardour/transport_master.h"
#include "ardour/tempo.h"
+#include "ardour/transport_master_manager.h"
#include "ardour/types.h"
#include "ardour_ui.h"
_mode = BBT; /* lie to force mode switch */
set_mode (Timecode);
- set (last_when, true);
+ AudioClock::set (last_when, true);
if (!is_transient) {
clocks.push_back (this);
}
+ _left_btn.set_name ("transport option button");
+ _right_btn.set_name ("transport option button");
+
_left_btn.set_sizing_text (_("0000000000000"));
// NB right_btn is in a size-group
AudioClock::~AudioClock ()
{
+ delete ops_menu;
delete foreground_attr;
delete editing_attr;
}
tmp->get_pixel_size (em_width, ignore_height);
/* force redraw of markup with new font-size */
- set (last_when, true);
+ AudioClock::set (last_when, true);
}
void
case Ticks:
return edit_string.substr (8, 4);
break;
+ case SS_Seconds:
+ return edit_string.substr (0, 8);
+ case SS_Deciseconds:
+ return edit_string.substr (9, 1);
case S_Samples:
return edit_string;
break;
ok = minsec_validate_edit (edit_string);
break;
+ case Seconds:
+ /* fallthrough */
case Samples:
if (edit_string.length() < 1) {
edit_string = pre_edit_string;
pos = samples_from_minsec_string (edit_string);
break;
+ case Seconds:
+ pos = samples_from_seconds_string (edit_string);
+ break;
+
case Samples:
- pos = samples_from_audioframes_string (edit_string);
+ pos = samples_from_audiosamples_string (edit_string);
break;
}
- set (pos, true);
+ AudioClock::set (pos, true);
_layout->set_attributes (normal_attributes);
ValueChanged(); /* EMIT_SIGNAL */
}
}
}
+samplecnt_t
+AudioClock::parse_as_seconds_distance (const std::string& str)
+{
+ float f;
+
+ if (sscanf (str.c_str(), "%f", &f) == 1) {
+ return f * _session->sample_rate();
+ }
+
+ return 0;
+}
+
samplecnt_t
AudioClock::parse_as_samples_distance (const std::string& str)
{
case MinSec:
return parse_as_minsec_distance (instr);
break;
+ case Seconds:
+ return parse_as_seconds_distance (instr);
+ break;
}
return 0;
}
ok = minsec_validate_edit (edit_string);
break;
+ case Seconds:
+ break;
+
case Samples:
break;
}
if (samples != 0) {
if (add) {
- set (current_time() + samples, true);
+ AudioClock::set (current_time() + samples, true);
} else {
samplepos_t c = current_time();
if (c > samples || _negative_allowed) {
- set (c - samples, true);
+ AudioClock::set (c - samples, true);
} else {
- set (0, true);
+ AudioClock::set (0, true);
}
}
ValueChanged (); /* EMIT SIGNAL */
void
AudioClock::session_property_changed (const PropertyChange&)
{
- set (last_when, true);
+ AudioClock::set (last_when, true);
}
void
}
if (p == "sync-source" || p == "external-sync") {
- set (current_time(), true);
+ AudioClock::set (current_time(), true);
return;
}
} else {
current = current_time ();
}
- set (current, true);
+ AudioClock::set (current, true);
break;
default:
break;
return;
}
+ _offset = offset;
if (is_duration) {
when = when - offset;
}
set_minsec (when, force);
break;
+ case Seconds:
+ set_seconds (when, force);
+ break;
+
case Samples:
set_samples (when, force);
break;
return;
}
- SyncSource sync_src = Config->get_sync_source();
+ boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
- if (_session->config.get_external_sync()) {
- Slave* slave = _session->slave();
+ if (_session->transport_master_is_external()) {
- switch (sync_src) {
+ switch (tm->type()) {
case Engine:
- _left_btn.set_text (sync_source_to_string (sync_src, true), true);
+ _left_btn.set_text (tm->name(), true);
_right_btn.set_text ("", true);
break;
case MIDIClock:
- if (slave) {
- _left_btn.set_text (sync_source_to_string (sync_src, true), true);
- _right_btn.set_text (slave->approximate_current_delta (), true);
+ if (tm) {
+ _left_btn.set_text (tm->display_name(), true);
+ _right_btn.set_text (tm->delta_string (), true);
} else {
_left_btn.set_text (_("--pending--"), true);
_right_btn.set_text ("", true);
break;
case LTC:
case MTC:
- if (slave) {
+ if (tm) {
bool matching;
- TimecodeSlave* tcslave;
- if ((tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
- matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
+ boost::shared_ptr<TimecodeTransportMaster> tcmaster;
+ if ((tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
+ matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
_left_btn.set_text (string_compose ("%1<span face=\"monospace\" foreground=\"%3\">%2</span>",
- sync_source_to_string(sync_src, true)[0],
- dynamic_cast<TimecodeSlave*>(slave)->approximate_current_position (),
- matching ? "#66ff66" : "#ff3333"
+ tm->display_name()[0],
+ tcmaster->position_string (),
+ matching ? "#66ff66" : "#ff3333"
), true);
- _right_btn.set_text (slave->approximate_current_delta (), true);
+ _right_btn.set_text (tm->delta_string (), true);
}
} else {
_left_btn.set_text (_("--pending--"), true);
break;
}
} else {
- _left_btn.set_text (string_compose ("%1/%2",
- _("INT"), sync_source_to_string(sync_src, true)), true);
+ _left_btn.set_text (string_compose ("%1/%2", _("INT"), tm->display_name()), true);
_right_btn.set_text ("", true);
}
}
}
}
+void
+AudioClock::set_seconds (samplepos_t when, bool /*force*/)
+{
+ char buf[32];
+
+ if (_off) {
+ _layout->set_text (" ----------");
+ _left_btn.set_text ("", true);
+ _right_btn.set_text ("", true);
+ return;
+ }
+
+ if (when >= _limit_pos || when <= -_limit_pos) {
+ set_out_of_bounds (when < 0);
+ } else {
+ if (when < 0) {
+ snprintf (buf, sizeof (buf), "%12.1f", when / (float)_session->sample_rate());
+ } else {
+ snprintf (buf, sizeof (buf), " %11.1f", when / (float)_session->sample_rate());
+ }
+ _layout->set_text (buf);
+ }
+
+ set_slave_info();
+}
+
void
AudioClock::print_minsec (samplepos_t when, char* buf, size_t bufsize, float sample_rate)
{
}
}
- set (last_when, true);
+ AudioClock::set (last_when, true);
}
}
return MS_Milliseconds;
}
break;
+ case Seconds:
+ if (index < 10) {
+ return SS_Seconds;
+ } else {
+ return SS_Deciseconds;
+ }
+ break;
case Samples:
return S_Samples;
break;
case Timecode_frames:
case MS_Milliseconds:
case Ticks:
+ case SS_Deciseconds:
f = Field (0);
break;
default:
if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
samples *= 10;
}
- set (current_time() + samples, true);
+ AudioClock::set (current_time() + samples, true);
ValueChanged (); /* EMIT_SIGNAL */
}
break;
}
if (!_negative_allowed && (double)current_time() - (double)samples < 0.0) {
- set (0, true);
+ AudioClock::set (0, true);
} else {
- set (current_time() - samples, true);
+ AudioClock::set (current_time() - samples, true);
}
ValueChanged (); /* EMIT_SIGNAL */
samples = get_sample_step (drag_field, pos, dir);
if (samples != 0 && samples * drag_accum < current_time()) {
- set ((samplepos_t) floor (pos - drag_accum * samples), false); // minus because up is negative in GTK
+ AudioClock::set ((samplepos_t) floor (pos - drag_accum * samples), false); // minus because up is negative in GTK
} else {
- set (0 , false);
+ AudioClock::set (0 , false);
}
drag_accum= 0;
f = 1;
break;
+ case SS_Seconds:
+ f = (samplecnt_t) _session->sample_rate();
+ break;
+ case SS_Deciseconds:
+ f = (samplecnt_t) _session->sample_rate() / 10.f;
+ break;
+
case MS_Hours:
f = (samplecnt_t) floor (3600.0 * _session->sample_rate());
break;
samplepos_t ret = 0;
switch (_mode) {
- case Timecode:
- ret = last_when;
- break;
case BBT:
ret = sample_duration_from_bbt_string (pos, _layout->get_text());
break;
+ case Timecode:
case MinSec:
- ret = last_when;
- break;
-
+ case Seconds:
case Samples:
ret = last_when;
break;
}
bool
-AudioClock::bbt_validate_edit (const string& str)
+AudioClock::bbt_validate_edit (string & str)
{
AnyTime any;
}
if (!is_duration && any.bbt.beats == 0) {
- return false;
+ /* user could not have mean zero beats because for a
+ * non-duration clock that's impossible. Assume that they
+ * mis-entered things and meant Bar|1|ticks
+ */
+
+ char buf[128];
+ snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, any.bbt.bars, 1, any.bbt.ticks);
+ str = buf;
}
return true;
}
samplepos_t
-AudioClock::samples_from_audioframes_string (const string& str) const
+AudioClock::samples_from_seconds_string (const string& str) const
+{
+ float f;
+ sscanf (str.c_str(), "%f", &f);
+ return f * _session->sample_rate();
+}
+
+samplepos_t
+AudioClock::samples_from_audiosamples_string (const string& str) const
{
samplepos_t f;
sscanf (str.c_str(), "%" PRId64, &f);
ops_items.push_back (MenuElem (_("Timecode"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Timecode, false)));
ops_items.push_back (MenuElem (_("Bars:Beats"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), BBT, false)));
ops_items.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), MinSec, false)));
+ ops_items.push_back (MenuElem (_("Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Seconds, false)));
ops_items.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Samples, false)));
if (editable && !_off && !is_duration && !_follows_playhead) {
return;
}
- set (_session->transport_sample());
+ AudioClock::set (_session->transport_sample());
ValueChanged ();
}
insert_map.push_back (1);
break;
+ case Seconds:
+ insert_map.push_back (11);
+ insert_map.push_back (9);
+ insert_map.push_back (8);
+ insert_map.push_back (7);
+ insert_map.push_back (6);
+ insert_map.push_back (5);
+ insert_map.push_back (4);
+ insert_map.push_back (3);
+ insert_map.push_back (2);
+ insert_map.push_back (1);
+ break;
+
case Samples:
break;
}
- set (last_when, true);
+ AudioClock::set (last_when, true);
if (!is_transient && !noemit) {
ModeChanged (); /* EMIT SIGNAL (the static one)*/
}
is_duration = yn;
- set (last_when, true);
+ AudioClock::set (last_when, true);
}
void
* change
*/
- set (last_when, true);
+ AudioClock::set (last_when, true);
}
void