#include <algorithm>
#include <unistd.h>
-#include <pbd/error.h>
+#include "pbd/error.h"
#include <glibmm/thread.h>
-#include <ardour/ardour.h>
-#include <ardour/session.h>
-#include <ardour/timestamps.h>
-#include <ardour/audio_diskstream.h>
-#include <ardour/audioengine.h>
-#include <ardour/slave.h>
-#include <ardour/auditioner.h>
-#include <ardour/cycles.h>
-#include <ardour/cycle_timer.h>
+#include "ardour/ardour.h"
+#include "ardour/session.h"
+#include "ardour/timestamps.h"
+#include "ardour/audio_diskstream.h"
+#include "ardour/audioengine.h"
+#include "ardour/slave.h"
+#include "ardour/auditioner.h"
+#include "ardour/cycles.h"
+#include "ardour/cycle_timer.h"
-#include <midi++/manager.h>
+#include "midi++/manager.h"
#include "i18n.h"
void
Session::process (nframes_t nframes)
{
+ // This is no more the appropriate place to call cycle
+ // start. cycle_start needs to be called at the Route::roll()
+ // where the signals which we want to mixdown have been calculated.
+ //
MIDI::Manager::instance()->cycle_start(nframes);
_silent = false;
+ if (processing_blocked()) {
+ _silent = true;
+ return;
+ }
+
if (non_realtime_work_pending()) {
if (!transport_work_requested ()) {
post_transport ();
}
}
-
+
(this->*process_function) (nframes);
- MIDI::Manager::instance()->cycle_end();
-
+ // the ticker is for sending time information like MidiClock
+ nframes_t transport_frames = transport_frame();
+ BBT_Time transport_bbt;
+ bbt_time(transport_frames, transport_bbt);
+ SMPTE::Time transport_smpte;
+ smpte_time(transport_frames, transport_smpte);
+ tick (transport_frames, transport_bbt, transport_smpte); /* EMIT SIGNAL */
+
SendFeedback (); /* EMIT SIGNAL */
+
+ MIDI::Manager::instance()->cycle_end();
}
void
}
int
-Session::no_roll (nframes_t nframes, nframes_t offset)
+Session::fail_roll (nframes_t nframes)
+{
+ return no_roll (nframes);
+}
+
+int
+Session::no_roll (nframes_t nframes)
{
nframes_t end_frame = _transport_frame + nframes; // FIXME: varispeed + no_roll ??
int ret = 0;
boost::shared_ptr<RouteList> r = routes.reader ();
if (_click_io) {
- _click_io->silence (nframes, offset);
- }
-
- if (g_atomic_int_get (&processing_prohibited)) {
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- (*i)->silence (nframes, offset);
- }
- return 0;
+ _click_io->silence (nframes);
}
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->set_pending_declick (declick);
- if ((*i)->no_roll (nframes, _transport_frame, end_frame, offset, non_realtime_work_pending(),
+ if ((*i)->no_roll (nframes, _transport_frame, end_frame, non_realtime_work_pending(),
actively_recording(), declick)) {
error << string_compose(_("Session: error in no roll for %1"), (*i)->name()) << endmsg;
ret = -1;
}
int
-Session::process_routes (nframes_t nframes, nframes_t offset)
+Session::process_routes (nframes_t nframes)
{
bool record_active;
int declick = get_transport_declick_required();
(*i)->set_pending_declick (declick);
- if ((ret = (*i)->roll (nframes, start_frame, end_frame, offset, declick, record_active, rec_monitors)) < 0) {
+ if ((ret = (*i)->roll (nframes, start_frame, end_frame, declick, record_active, rec_monitors)) < 0) {
/* we have to do this here. Route::roll() for an AudioTrack will have called AudioDiskstream::process(),
and the DS will expect AudioDiskstream::commit() to be called. but we're aborting from that
}
int
-Session::silent_process_routes (nframes_t nframes, nframes_t offset)
+Session::silent_process_routes (nframes_t nframes)
{
bool record_active = actively_recording();
int declick = get_transport_declick_required();
continue;
}
- if ((ret = (*i)->silent_roll (nframes, start_frame, end_frame, offset, record_active, rec_monitors)) < 0) {
+ if ((ret = (*i)->silent_roll (nframes, start_frame, end_frame, record_active, rec_monitors)) < 0) {
/* we have to do this here. Route::roll() for an AudioTrack will have called AudioDiskstream::process(),
and the DS will expect AudioDiskstream::commit() to be called. but we're aborting from that
also runs commit() for every diskstream.
*/
- if ((dret = (*i)->process (_transport_frame, nframes, 0, actively_recording(), get_rec_monitors_input())) == 0) {
+ if ((dret = (*i)->process (_transport_frame, nframes, actively_recording(), get_rec_monitors_input())) == 0) {
if ((*i)->commit (nframes)) {
needs_butler = true;
}
Session::process_with_events (nframes_t nframes)
{
Event* ev;
- nframes_t this_nframes;
- nframes_t end_frame;
- nframes_t offset;
- bool session_needs_butler = false;
- nframes_t stop_limit;
+ nframes_t this_nframes;
+ nframes_t end_frame;
+ bool session_needs_butler = false;
+ nframes_t stop_limit;
long frames_moved;
/* make sure the auditioner is silent */
if (auditioner) {
- auditioner->silence (nframes, 0);
+ auditioner->silence (nframes);
}
/* handle any pending events */
return;
}
- end_frame = _transport_frame + (nframes_t)abs(floor(nframes * _transport_speed));
+ if (_transport_speed == 1.0) {
+ frames_moved = (long) nframes;
+ } else {
+ interpolation.set_target_speed (fabs(_target_transport_speed));
+ interpolation.set_speed (fabs(_transport_speed));
+ frames_moved = (long) interpolation.interpolate (0, nframes, 0, 0);
+ }
+
+ end_frame = _transport_frame + (nframes_t)frames_moved;
{
Event* this_event;
}
if (!_exporting && _slave) {
- if (!follow_slave (nframes, 0)) {
+ if (!follow_slave (nframes)) {
return;
}
}
if (_transport_speed == 0) {
- no_roll (nframes, 0);
+ no_roll (nframes);
return;
}
}
if (maybe_stop (stop_limit)) {
- no_roll (nframes, 0);
+ no_roll (nframes);
return;
}
the_next_one = next_event;
++the_next_one;
- offset = 0;
-
/* yes folks, here it is, the actual loop where we really truly
- process some audio */
+ process some audio
+ */
+
while (nframes) {
this_nframes = nframes; /* real (jack) time relative */
if (this_nframes) {
- click (_transport_frame, nframes, offset);
+ click (_transport_frame, this_nframes);
/* now process frames between now and the first event in this block */
prepare_diskstreams ();
- if (process_routes (this_nframes, offset)) {
- no_roll (nframes, 0);
+ if (process_routes (this_nframes)) {
+ fail_roll (nframes);
return;
}
commit_diskstreams (this_nframes, session_needs_butler);
nframes -= this_nframes;
- offset += this_nframes;
if (frames_moved < 0) {
decrement_transport_position (-frames_moved);
check_declick_out ();
}
+ _engine.split_cycle (this_nframes);
+
/* now handle this event and all others scheduled for the same time */
while (this_event && this_event->action_frame == _transport_frame) {
/* if an event left our state changing, do the right thing */
- if (non_realtime_work_pending()) {
- no_roll (nframes, offset);
+ if (nframes && non_realtime_work_pending()) {
+ no_roll (nframes);
break;
}
}
bool
-Session::follow_slave (nframes_t nframes, nframes_t offset)
+Session::follow_slave (nframes_t nframes)
{
- float slave_speed;
+ double slave_speed;
nframes_t slave_transport_frame;
nframes_t this_delta;
int dir;
slave_speed = 0.0f;
}
-#if 0
- cerr << "delta = " << (int) (dir * this_delta)
- << " speed = " << slave_speed
- << " ts = " << _transport_speed
- << " M@ "<< slave_transport_frame << " S@ " << _transport_frame
- << " avgdelta = " << average_slave_delta
- << endl;
-#endif
-
- if (_slave->is_always_synced() || Config->get_timecode_source_is_synced()) {
+ if (_slave->is_always_synced() || config.get_timecode_source_is_synced()) {
/* if the TC source is synced, then we assume that its
speed is binary: 0.0 or 1.0
our speed to remain locked.
*/
- if (delta_accumulator_cnt >= delta_accumulator_size) {
- have_first_delta_accumulator = true;
- delta_accumulator_cnt = 0;
- }
+ calculate_moving_average_of_slave_delta(dir, this_delta);
+ }
+
+ track_slave_state(slave_speed, slave_transport_frame, this_delta, starting);
- if (delta_accumulator_cnt != 0 || this_delta < _current_frame_rate) {
- delta_accumulator[delta_accumulator_cnt++] = dir*this_delta;
- }
-
- if (have_first_delta_accumulator) {
- average_slave_delta = 0;
- for (int i = 0; i < delta_accumulator_size; ++i) {
- average_slave_delta += delta_accumulator[i];
- }
- average_slave_delta /= delta_accumulator_size;
- if (average_slave_delta < 0) {
- average_dir = -1;
- average_slave_delta = -average_slave_delta;
+ if (slave_state == Running && !_slave->is_always_synced() && !config.get_timecode_source_is_synced()) {
+
+ if (_transport_speed != 0.0f) {
+
+ /*
+ note that average_dir is +1 or -1
+ */
+
+ float delta;
+
+ #ifdef USE_MOVING_AVERAGE_OF_SLAVE
+ if (average_slave_delta == 0) {
+ delta = this_delta;
+ delta *= dir;
+ } else {
+ delta = average_slave_delta;
+ delta *= average_dir;
+ }
+ #else
+ delta = this_delta;
+ delta *= dir;
+ #endif
+
+ float adjusted_speed = slave_speed + (delta / float(_current_frame_rate));
+
+ if (_slave->give_slave_full_control_over_transport_speed()) {
+ request_transport_speed(slave_speed);
} else {
- average_dir = 1;
+ request_transport_speed(adjusted_speed);
+ #ifdef DEBUG_SLAVES
+ cerr << "adjust using " << delta
+ << " towards " << adjusted_speed
+ << " ratio = " << adjusted_speed / slave_speed
+ << " current = " << _transport_speed
+ << " slave @ " << slave_speed
+ << endl;
+ #endif
+ }
+
+ if (abs(average_slave_delta) > (long) _slave->resolution()) {
+ cerr << "average slave delta greater than slave resolution, going to silent motion\n";
+ goto silent_motion;
}
- // cerr << "avgdelta = " << average_slave_delta*average_dir << endl;
}
+ }
+
+ #ifdef DEBUG_SLAVES
+ if (slave_speed != 0.0)
+ cerr << "delta = " << (int) (dir * this_delta)
+ << " speed = " << slave_speed
+ << " ts = " << _transport_speed
+ << " M@ "<< slave_transport_frame << " S@ " << _transport_frame
+ << " avgdelta = " << average_slave_delta
+ << endl;
+ #endif
+
+ if (!starting && !non_realtime_work_pending()) {
+ /* speed is set, we're locked, and good to go */
+ return true;
}
+ silent_motion:
+ #ifdef DEBUG_SLAVES
+ cerr << "reached silent_motion:" <<endl;
+ #endif
+
+ follow_slave_silently (nframes, slave_speed);
+
+ noroll:
+ /* don't move at all */
+ #ifdef DEBUG_SLAVES
+ cerr << "reached no_roll:" <<endl;
+ #endif
+ no_roll (nframes);
+ return false;
+}
+
+void
+Session::calculate_moving_average_of_slave_delta(int dir, nframes_t this_delta)
+{
+ if (delta_accumulator_cnt >= delta_accumulator_size) {
+ have_first_delta_accumulator = true;
+ delta_accumulator_cnt = 0;
+ }
+
+ if (delta_accumulator_cnt != 0 || this_delta < _current_frame_rate) {
+ delta_accumulator[delta_accumulator_cnt++] = long(dir) * long(this_delta);
+ }
+
+ if (have_first_delta_accumulator) {
+ average_slave_delta = 0L;
+ for (int i = 0; i < delta_accumulator_size; ++i) {
+ average_slave_delta += delta_accumulator[i];
+ }
+ average_slave_delta /= long(delta_accumulator_size);
+ if (average_slave_delta < 0L) {
+ average_dir = -1;
+ average_slave_delta = abs(average_slave_delta);
+ } else {
+ average_dir = 1;
+ }
+ }
+}
+
+void
+Session::track_slave_state(
+ float slave_speed,
+ nframes_t slave_transport_frame,
+ nframes_t this_delta,
+ bool starting)
+{
if (slave_speed != 0.0f) {
/* slave is running */
if (slave_state == Waiting) {
- // cerr << "waiting at " << slave_transport_frame << endl;
+ #ifdef DEBUG_SLAVES
+ cerr << "waiting at " << slave_transport_frame << endl;
+ #endif
if (slave_transport_frame >= slave_wait_end) {
- // cerr << "\tstart at " << _transport_frame << endl;
-
+#ifdef DEBUG_SLAVES
+ cerr << "\tstart at " << _transport_frame << endl;
+#endif
slave_state = Running;
bool ok = true;
_transport_frame += frame_delta;
} else {
- // cerr << "cannot micro-seek\n";
+ cerr << "cannot micro-seek\n";
/* XXX what? */
}
- memset (delta_accumulator, 0, sizeof (nframes_t) * delta_accumulator_size);
- average_slave_delta = 0;
+ memset (delta_accumulator, 0, sizeof (long) * delta_accumulator_size);
+ average_slave_delta = 0L;
this_delta = 0;
}
}
if (slave_state == Running && _transport_speed == 0.0f) {
- // cerr << "slave starts transport\n";
-
+ #ifdef DEBUG_SLAVES
+ cerr << "slave starts transport\n";
+ #endif
start_transport ();
}
- } else {
+ } else { // slave_speed is 0
/* slave has stopped */
if (_transport_speed != 0.0f) {
- // cerr << "slave stops transport: " << slave_speed << " frame: " << slave_transport_frame
- // << " tf = " << _transport_frame
- // << endl;
+ #ifdef DEBUG_SLAVES
+ cerr << "slave stops transport: " << slave_speed << " frame: " << slave_transport_frame
+ << " tf = " << _transport_frame << endl;
+ #endif
- if (Config->get_slave_source() == JACK) {
- last_stop_frame = _transport_frame;
- }
-
stop_transport();
}
if (slave_transport_frame != _transport_frame) {
- // cerr << "slave stopped, move to " << slave_transport_frame << endl;
+ #ifdef DEBUG_SLAVES
+ cerr << "slave stopped, move to " << slave_transport_frame << endl;
+ #endif
force_locate (slave_transport_frame, false);
}
slave_state = Stopped;
}
+}
- if (slave_state == Running && !_slave->is_always_synced() && !Config->get_timecode_source_is_synced()) {
-
-
- if (_transport_speed != 0.0f) {
-
- /*
- note that average_dir is +1 or -1
- */
-
- const float adjust_seconds = 1.0f;
- float delta;
-
- //if (average_slave_delta == 0) {
- delta = this_delta;
- delta *= dir;
-// } else {
-// delta = average_slave_delta;
-// delta *= average_dir;
-// }
-
- float adjusted_speed = slave_speed +
- (delta / (adjust_seconds * _current_frame_rate));
-
- // cerr << "adjust using " << delta
- // << " towards " << adjusted_speed
- // << " ratio = " << adjusted_speed / slave_speed
- // << " current = " << _transport_speed
- // << " slave @ " << slave_speed
- // << endl;
-
- request_transport_speed (adjusted_speed);
-
-#if 1
- if ((nframes_t) average_slave_delta > _slave->resolution()) {
- // cerr << "not locked\n";
- goto silent_motion;
- }
-#endif
- }
- }
-
- if (!starting && !non_realtime_work_pending()) {
- /* speed is set, we're locked, and good to go */
- return true;
- }
-
- silent_motion:
-
+void
+Session::follow_slave_silently (nframes_t nframes, float slave_speed)
+{
if (slave_speed && _transport_speed) {
/* something isn't right, but we should move with the master
bool need_butler;
prepare_diskstreams ();
- silent_process_routes (nframes, offset);
+ silent_process_routes (nframes);
commit_diskstreams (nframes, need_butler);
if (need_butler) {
maybe_stop (stop_limit);
}
-
- noroll:
- /* don't move at all */
- no_roll (nframes, 0);
- return false;
}
void
bool session_needs_butler = false;
nframes_t stop_limit;
long frames_moved;
- nframes_t offset = 0;
if (!process_can_proceed()) {
_silent = true;
}
if (!_exporting && _slave) {
- if (!follow_slave (nframes, 0)) {
+ if (!follow_slave (nframes)) {
return;
}
}
if (_transport_speed == 0) {
- no_roll (nframes, 0);
+ fail_roll (nframes);
return;
}
}
if (maybe_stop (stop_limit)) {
- no_roll (nframes, 0);
+ fail_roll (nframes);
return;
}
- if (maybe_sync_start (nframes, offset)) {
+ if (maybe_sync_start (nframes)) {
return;
}
- click (_transport_frame, nframes, offset);
+ click (_transport_frame, nframes);
prepare_diskstreams ();
- frames_moved = (long) floor (_transport_speed * nframes);
+ if (_transport_speed == 1.0) {
+ frames_moved = (long) nframes;
+ } else {
+ interpolation.set_target_speed (fabs(_target_transport_speed));
+ interpolation.set_speed (fabs(_transport_speed));
+ frames_moved = (long) interpolation.interpolate (0, nframes, 0, 0);
+ }
- if (process_routes (nframes, offset)) {
- no_roll (nframes, offset);
+ if (process_routes (nframes)) {
+ fail_roll (nframes);
return;
}
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->is_hidden()) {
- (*i)->silence (nframes, 0);
+ (*i)->silence (nframes);
}
}
}
bool
-Session::maybe_sync_start (nframes_t& nframes, nframes_t& offset)
+Session::maybe_sync_start (nframes_t& nframes)
{
nframes_t sync_offset;
is left to do.
*/
- no_roll (sync_offset, 0);
+ no_roll (sync_offset);
nframes -= sync_offset;
- offset += sync_offset;
+ Port::increment_port_offset (sync_offset);
waiting_for_sync_offset = false;
if (nframes == 0) {
with any fancy stuff here, just the minimal silence.
*/
- g_atomic_int_inc (&processing_prohibited);
- no_roll (nframes, 0);
- g_atomic_int_dec_and_test (&processing_prohibited);
+ _silent = true;
if (Config->get_locate_while_waiting_for_sync()) {
if (micro_locate (nframes)) {