#include "ardour/scene_changer.h"
#include "ardour/session.h"
#include "ardour/slave.h"
+#include "ardour/tempo.h"
#include "ardour/operations.h"
-#include "i18n.h"
+#include "pbd/i18n.h"
using namespace std;
using namespace ARDOUR;
queue_event (ev);
}
+void
+Session::unset_preroll_record_punch ()
+{
+ if (_preroll_record_punch_pos >= 0) {
+ remove_event (_preroll_record_punch_pos, SessionEvent::RecordStart);
+ }
+ _preroll_record_punch_pos = -1;
+}
+
+void
+Session::unset_preroll_record_trim ()
+{
+ _preroll_record_trim_len = 0;
+}
+
+void
+Session::request_preroll_record_punch (framepos_t rec_in, framecnt_t preroll)
+{
+ if (actively_recording ()) {
+ return;
+ }
+ unset_preroll_record_punch ();
+ unset_preroll_record_trim ();
+ framepos_t start = std::max ((framepos_t)0, rec_in - preroll);
+
+ _preroll_record_punch_pos = rec_in;
+ if (_preroll_record_punch_pos >= 0) {
+ replace_event (SessionEvent::RecordStart, _preroll_record_punch_pos);
+ config.set_punch_in (false);
+ config.set_punch_out (false);
+ }
+ maybe_enable_record ();
+ request_locate (start, true);
+ set_requested_return_frame (rec_in);
+}
+
+void
+Session::request_preroll_record_trim (framepos_t rec_in, framecnt_t preroll)
+{
+ if (actively_recording ()) {
+ return;
+ }
+ unset_preroll_record_punch ();
+ unset_preroll_record_trim ();
+
+ config.set_punch_in (false);
+ config.set_punch_out (false);
+
+ framepos_t pos = std::max ((framepos_t)0, rec_in - preroll);
+ _preroll_record_trim_len = preroll;
+ maybe_enable_record ();
+ request_locate (pos, true);
+ set_requested_return_frame (rec_in);
+}
+
void
Session::request_play_loop (bool yn, bool change_transport_roll)
{
+ if (_slave && yn) {
+ // don't attempt to loop when not using Internal Transport
+ // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
+ return;
+ }
+
SessionEvent* ev;
Location *location = _locations->auto_loop_location();
double target_speed;
}
if (ptw & PostTransportAdjustPlaybackBuffering) {
+ /* non_realtime_locate() calls Automatable::transport_located()
+ * for every route. This eventually calls
+ * ARDOUR::AutomationList::state () which has a LocaleGuard,
+ * and would switch locales forth/back every time.
+ */
+ LocaleGuard lg;
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
if (tr) {
/* don't seek if locate will take care of that in non_realtime_stop() */
if (!(ptw & PostTransportLocate)) {
-
+ LocaleGuard lg; // see note for non_realtime_locate() above
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->non_realtime_locate (_transport_frame);
}
- boost::shared_ptr<RouteList> rl = routes.reader();
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- (*i)->non_realtime_locate (_transport_frame);
+ {
+ LocaleGuard lg; // see note for non_realtime_locate() above
+ boost::shared_ptr<RouteList> rl = routes.reader();
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ (*i)->non_realtime_locate (_transport_frame);
+ }
}
_scene_changer->locate (_transport_frame);
flush_all_inserts ();
}
+ // rg: what is the logic behind this case?
+ // _requested_return_frame should be ignored when synced_to_engine/slaved.
+ // currently worked around in MTC_Slave by forcing _requested_return_frame to -1
+ // 2016-01-10
if ((auto_return_enabled || synced_to_engine() || _requested_return_frame >= 0) &&
!(ptw & PostTransportLocate)) {
}
clear_clicks();
+ unset_preroll_record_trim ();
/* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
*/
/* this for() block can be put inside the previous if() and has the effect of ... ??? what */
- DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
- (*i)->non_realtime_locate (_transport_frame);
+ {
+ LocaleGuard lg; // see note for non_realtime_locate() above
+ DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
+ (*i)->non_realtime_locate (_transport_frame);
- if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
- finished = false;
- /* we will be back */
- return;
+ if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
+ finished = false;
+ /* we will be back */
+ return;
+ }
}
}
}
// Update Timecode time
- // [DR] FIXME: find out exactly where this should go below
_transport_frame = target_frame;
_last_roll_or_reversal_location = target_frame;
timecode_time(_transport_frame, transmitting_timecode_time);
- outbound_mtc_timecode_frame = _transport_frame;
- next_quarter_frame_to_send = 0;
/* do "stopped" stuff if:
*
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
- if (tr && tr->record_enabled ()) {
+ if (tr && tr->rec_enable_control()->get_value()) {
// tell it we've looped, so it can deal with the record state
tr->transport_looped (_transport_frame);
}
switch (record_status()) {
case Enabled:
- if (!config.get_punch_in()) {
+ if (!config.get_punch_in() && !preroll_record_punch_enabled()) {
enable_record ();
}
break;
if (!dynamic_cast<MTC_Slave*>(_slave)) {
send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
}
+
+ if (actively_recording() && click_data && config.get_count_in ()) {
+ /* calculate count-in duration (in audio samples)
+ * - use [fixed] tempo/meter at _transport_frame
+ * - calc duration of 1 bar + time-to-beat before or at transport_frame
+ */
+ const Tempo& tempo = _tempo_map->tempo_at_frame (_transport_frame);
+ const Meter& meter = _tempo_map->meter_at_frame (_transport_frame);
+
+ double div = meter.divisions_per_bar ();
+ double pulses = _tempo_map->exact_qn_at_frame (_transport_frame, 0) * div / 4.0;
+ double beats_left = fmod (pulses, div);
+
+ _count_in_samples = meter.frames_per_bar (tempo, _current_frame_rate);
+
+ double dt = _count_in_samples / div;
+ if (beats_left == 0) {
+ /* at bar boundary, count-in 2 bars before start. */
+ _count_in_samples *= 2;
+ } else {
+ /* beats left after full bar until roll position */
+ _count_in_samples += meter.frames_per_grid (tempo, _current_frame_rate) * beats_left;
+ }
+
+ int clickbeat = 0;
+ framepos_t cf = _transport_frame - _count_in_samples;
+ while (cf < _transport_frame) {
+ add_click (cf - _worst_track_latency, clickbeat == 0);
+ cf += dt;
+ clickbeat = fmod (clickbeat + 1, div);
+ }
+ }
}
DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
void
Session::route_processors_changed (RouteProcessorChange c)
{
- if (ignore_route_processor_changes) {
+ if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
return;
}