along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cmath>
#include <unistd.h>
#include <pbd/error.h>
-
+
#include <glibmm/thread.h>
#include <ardour/ardour.h>
#include <ardour/cycles.h>
#include <ardour/cycle_timer.h>
+#include <midi++/manager.h>
+
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
using namespace std;
+/** Called by the audio engine when there is work to be done with JACK.
+ * @param nframes Number of frames to process.
+ */
void
Session::process (nframes_t nframes)
{
+ MIDI::Manager::instance()->cycle_start(nframes);
+
if (synced_to_jack() && waiting_to_start) {
if ( _engine.transport_state() == AudioEngine::TransportRolling) {
actually_start_transport ();
}
(this->*process_function) (nframes);
+
+ MIDI::Manager::instance()->cycle_end();
SendFeedback (); /* EMIT SIGNAL */
}
int
Session::no_roll (nframes_t nframes, nframes_t offset)
{
- nframes_t end_frame = _transport_frame + nframes;
+ nframes_t end_frame = _transport_frame + nframes; // FIXME: varispeed + no_roll ??
int ret = 0;
bool declick = get_transport_declick_required();
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if ((*i)->hidden()) {
+ if ((*i)->is_hidden()) {
continue;
}
record_active = actively_recording(); // || (get_record_enabled() && get_punch_in());
+ const nframes_t start_frame = _transport_frame;
+ const nframes_t end_frame = _transport_frame + (nframes_t)floor(nframes * _transport_speed);
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
int ret;
- if ((*i)->hidden()) {
+ if ((*i)->is_hidden()) {
continue;
}
(*i)->set_pending_declick (declick);
- if ((ret = (*i)->roll (nframes, _transport_frame, _transport_frame + nframes, offset, declick, record_active, rec_monitors)) < 0) {
+ if ((ret = (*i)->roll (nframes, start_frame, end_frame, offset, 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
/* force a declick out */
declick = -1;
}
+
+ const nframes_t start_frame = _transport_frame;
+ const nframes_t end_frame = _transport_frame + lrintf(nframes * _transport_speed);
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
int ret;
- if ((*i)->hidden()) {
+ if ((*i)->is_hidden()) {
continue;
}
- if ((ret = (*i)->silent_roll (nframes, _transport_frame, _transport_frame + nframes, offset, record_active, rec_monitors)) < 0) {
+ if ((ret = (*i)->silent_roll (nframes, start_frame, end_frame, offset, 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
}
/* force all diskstreams not handled by a Route to call do their stuff.
+ Note: the diskstreams that were handled by a route will just return zero
+ from this call, because they know they were processed. So in fact, this
+ also runs commit() for every diskstream.
*/
if ((dret = (*i)->process (_transport_frame, nframes, 0, actively_recording(), get_rec_monitors_input())) == 0) {
}
}
+/** Process callback used when the auditioner is not active */
void
Session::process_with_events (nframes_t nframes)
{
- Event* ev;
+ Event* ev;
nframes_t this_nframes;
nframes_t end_frame;
nframes_t offset;
- bool session_needs_butler = false;
nframes_t stop_limit;
long frames_moved;
+ bool session_needs_butler = false;
/* make sure the auditioner is silent */
process_event (ev);
}
+ /* Events caused a transport change, send an MTC Full Frame (SMPTE) message.
+ * This is sent whether rolling or not, to give slaves an idea of ardour time
+ * on locates (and allow slow slaves to position and prepare for rolling)
+ */
+ if (_send_smpte_update) {
+ send_full_time_code(nframes);
+ }
+
if (!process_can_proceed()) {
no_roll (nframes, 0);
return;
}
-
+
if (events.empty() || next_event == events.end()) {
process_without_events (nframes);
return;
}
- end_frame = _transport_frame + nframes;
+ end_frame = _transport_frame + (nframes_t)abs(floor(nframes * _transport_speed));
{
Event* this_event;
no_roll (nframes, 0);
return;
}
+
+ send_midi_time_code_for_cycle(nframes);
if (actively_recording()) {
stop_limit = max_frames;
offset = 0;
+ /* yes folks, here it is, the actual loop where we really truly
+ process some audio */
while (nframes) {
- if (this_event == 0 || this_event->action_frame > end_frame || this_event->action_frame < _transport_frame) {
-
- this_nframes = nframes;
-
- } else {
-
- /* compute nframes to next event */
+ this_nframes = nframes; /* real (jack) time relative */
+ frames_moved = (long) floor (_transport_speed * nframes); /* transport relative */
- if (this_event->action_frame < end_frame) {
- this_nframes = nframes - (end_frame - this_event->action_frame);
- } else {
- this_nframes = nframes;
- }
- }
+ /* running an event, position transport precisely to its time */
+ if (this_event && this_event->action_frame <= end_frame && this_event->action_frame >= _transport_frame) {
+ /* this isn't quite right for reverse play */
+ frames_moved = (long) (this_event->action_frame - _transport_frame);
+ this_nframes = (nframes_t) abs( floor(frames_moved / _transport_speed) );
+ }
if (this_nframes) {
nframes -= this_nframes;
offset += this_nframes;
- frames_moved = (nframes_t) floor (_transport_speed * this_nframes);
-
if (frames_moved < 0) {
decrement_transport_position (-frames_moved);
} else {
}
/* this is necessary to handle the case of seamless looping */
- /* not sure if it will work in conjuction with varispeed */
- end_frame = _transport_frame + nframes;
+ end_frame = _transport_frame + (nframes_t) floor (nframes * _transport_speed);
}
} /* implicit release of route lock */
-
- if (session_needs_butler) {
+ if (session_needs_butler)
summon_butler ();
- }
-
- if (!_engine.freewheeling() && session_send_mtc) {
- send_midi_time_code_in_another_thread ();
- }
-
- return;
-}
+}
void
Session::reset_slave_state ()
cerr << "delta = " << (int) (dir * this_delta)
<< " speed = " << slave_speed
<< " ts = " << _transport_speed
- << " M@"<< slave_transport_frame << " S@" << _transport_frame
+ << " M@ "<< slave_transport_frame << " S@ " << _transport_frame
<< " avgdelta = " << average_slave_delta
<< endl;
#endif
if (slave_state == Waiting) {
// cerr << "waiting at " << slave_transport_frame << endl;
-
if (slave_transport_frame >= slave_wait_end) {
// cerr << "\tstart at " << _transport_frame << endl;
no_roll (nframes, 0);
return;
}
+
+ send_midi_time_code_for_cycle(nframes);
if (actively_recording()) {
stop_limit = max_frames;
} /* implicit release of route lock */
- if (session_needs_butler) {
+ if (session_needs_butler)
summon_butler ();
- }
-
- if (!_engine.freewheeling() && session_send_mtc) {
- send_midi_time_code_in_another_thread ();
- }
-
- return;
-}
+}
+/** Process callback used when the auditioner is active.
+ * @param nframes number of frames to process.
+ */
void
Session::process_audition (nframes_t nframes)
{
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if (!(*i)->hidden()) {
+ if (!(*i)->is_hidden()) {
(*i)->silence (nframes, 0);
}
}
}
if (!auditioner->active()) {
+ /* auditioner no longer active, so go back to the normal process callback */
process_function = &Session::process_with_events;
}
}
Session::maybe_sync_start (nframes_t& nframes, nframes_t& offset)
{
nframes_t sync_offset;
-
+
if (!waiting_for_sync_offset) {
return false;
}