protected:
friend class AudioTrack;
- int process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input);
+ int process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler);
bool commit (nframes_t nframes);
private:
int set_mode (TrackMode m);
bool can_use_mode (TrackMode m, bool& bounce_required);
- int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
- int declick, bool can_record, bool rec_monitors_input);
+ int roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame,
+ int declick, bool can_record, bool rec_monitors_input, bool& need_butler);
boost::shared_ptr<AudioDiskstream> audio_diskstream() const;
protected:
friend class Track;
- virtual void prepare ();
- virtual int process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input) = 0;
+ virtual int process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler) = 0;
virtual bool commit (nframes_t nframes) = 0;
- virtual void recover (); /* called if commit will not be called, but process was */
//private:
AlignStyle _alignment_style;
bool _scrubbing;
bool _slaved;
- bool _processed;
Location* loop_location;
nframes_t overwrite_frame;
off_t overwrite_offset;
nframes_t file_frame;
nframes_t playback_sample;
nframes_t playback_distance;
- bool commit_should_unlock;
uint32_t _read_data_count;
uint32_t _write_data_count;
protected:
friend class MidiTrack;
- int process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input);
+ int process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler);
bool commit (nframes_t nframes);
static nframes_t midi_readahead;
MidiTrack (Session&, string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal);
~MidiTrack ();
- int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
- int declick, bool can_record, bool rec_monitors_input);
+ int roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame,
+ int declick, bool can_record, bool rec_monitors_input, bool& need_butler);
void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
/* these are the core of the API of a Route. see the protected sections as well */
virtual int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
- int declick, bool can_record, bool rec_monitors_input);
+ int declick, bool can_record, bool rec_monitors_input, bool& need_butler);
virtual int no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
bool state_changing, bool can_record, bool rec_monitors_input);
virtual int silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
- bool can_record, bool rec_monitors_input);
+ bool can_record, bool rec_monitors_input, bool& need_butler);
virtual void toggle_monitor_input ();
virtual bool can_record() { return false; }
PBD::ScopedConnection export_freewheel_connection;
- void prepare_diskstreams ();
- void commit_diskstreams (nframes_t, bool& session_requires_butler);
- int process_routes (nframes_t);
- int silent_process_routes (nframes_t);
+ void get_diskstream_statistics ();
+ int process_routes (nframes_t, bool& need_butler);
+ int silent_process_routes (nframes_t, bool& need_butler);
bool get_rec_monitors_input () {
if (actively_recording()) {
virtual bool can_use_mode (TrackMode /*m*/, bool& /*bounce_required*/) { return false; }
PBD::Signal0<void> TrackModeChanged;
- virtual int no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
+ virtual int no_roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame,
bool state_changing, bool can_record, bool rec_monitors_input);
- int silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
- bool can_record, bool rec_monitors_input);
+ int silent_roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame,
+ bool can_record, bool rec_monitors_input, bool& need_butler);
- virtual int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
- int declick, bool can_record, bool rec_monitors_input) = 0;
+ virtual int roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame,
+ int declick, bool can_record, bool rec_monitors_input, bool& need_butler) = 0;
+ bool needs_butler() const { return _needs_butler; }
void toggle_monitor_input ();
bool can_record();
boost::shared_ptr<Diskstream> _diskstream;
MeterPoint _saved_meter_point;
TrackMode _mode;
+ bool _needs_butler;
ChanCount input_streams () const;
}
int
-AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input)
+AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler)
{
uint32_t n;
boost::shared_ptr<ChannelList> c = channels.reader();
bool re = record_enabled ();
bool collect_playback = false;
- /* if we've already processed the frames corresponding to this call,
- just return. this allows multiple routes that are taking input
- from this diskstream to call our ::process() method, but have
- this stuff only happen once. more commonly, it allows both
- the AudioTrack that is using this AudioDiskstream *and* the Session
- to call process() without problems.
- */
-
- if (_processed) {
- return 0;
- }
-
- commit_should_unlock = false;
+ playback_distance = 0;
if (!_io || !_io->active()) {
- _processed = true;
return 0;
}
nominally_recording = (can_record && re);
if (nframes == 0) {
- _processed = true;
return 0;
}
- /* This lock is held until the end of AudioDiskstream::commit, so these two functions
- must always be called as a pair. The only exception is if this function
- returns a non-zero value, in which case, ::commit should not be called.
- */
+ Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK);
- // If we can't take the state lock return.
- if (!state_lock.trylock()) {
+ if (!sm.locked()) {
return 1;
}
- commit_should_unlock = true;
+
adjust_capture_position = 0;
for (chan = c->begin(); chan != c->end(); ++chan) {
ret = 0;
- out:
- _processed = true;
-
- if (ret) {
-
- /* we're exiting with failure, so ::commit will not
- be called. unlock the state lock.
- */
-
- commit_should_unlock = false;
- state_lock.unlock();
- }
+ if (commit (nframes)) {
+ need_butler = true;
+ }
+ out:
return ret;
}
}
bool
-AudioDiskstream::commit (nframes_t /*nframes*/)
+AudioDiskstream::commit (nframes_t /* nframes */)
{
bool need_butler = false;
}
}
- if (commit_should_unlock) {
- state_lock.unlock();
- }
-
- _processed = false;
-
return need_butler;
}
int
AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick,
- bool can_record, bool rec_monitors_input)
+ bool can_record, bool rec_monitors_input, bool& need_butler)
{
int dret;
Sample* b;
Sample* tmpb;
nframes_t transport_frame;
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
-
+
{
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
if (lm.locked()) {
playback distance to zero, thus causing diskstream::commit
to do nothing.
*/
- return diskstream->process (transport_frame, 0, can_record, rec_monitors_input);
+ return diskstream->process (transport_frame, 0, can_record, rec_monitors_input, need_butler);
}
_silent = false;
_amp->apply_gain_automation(false);
- if ((dret = diskstream->process (transport_frame, nframes, can_record, rec_monitors_input)) != 0) {
+ if ((dret = diskstream->process (transport_frame, nframes, can_record, rec_monitors_input, need_butler)) != 0) {
silence (nframes);
return dret;
}
int
Auditioner::play_audition (nframes_t nframes)
{
- bool need_butler;
+ bool need_butler = false;
nframes_t this_nframes;
int ret;
this_nframes = min (nframes, length - current_frame);
- _diskstream->prepare ();
-
- if ((ret = roll (this_nframes, current_frame, current_frame + nframes, false, false, false)) != 0) {
+ if ((ret = roll (this_nframes, current_frame, current_frame + nframes, false, false, false, need_butler)) != 0) {
silence (nframes);
return ret;
}
- need_butler = _diskstream->commit (this_nframes);
current_frame += this_nframes;
if (current_frame >= length) {
last_recordable_frame = max_frames;
_roll_delay = 0;
_capture_offset = 0;
- _processed = false;
_slaved = false;
adjust_capture_position = 0;
last_possibly_recording = 0;
playback_distance = 0;
_read_data_count = 0;
_write_data_count = 0;
- commit_should_unlock = false;
pending_overwrite = false;
overwrite_frame = 0;
return _buffer_reallocation_required || _seek_required;
}
-void
-Diskstream::prepare ()
-{
- _processed = false;
- playback_distance = 0;
-}
-
-void
-Diskstream::recover ()
-{
- if (commit_should_unlock) {
- state_lock.unlock();
- }
- _processed = false;
-}
-
void
Diskstream::set_capture_offset ()
{
#endif
int
-MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input)
+MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler)
{
int ret = -1;
nframes_t rec_offset = 0;
bool nominally_recording;
bool re = record_enabled ();
- /* if we've already processed the frames corresponding to this call,
- just return. this allows multiple routes that are taking input
- from this diskstream to call our ::process() method, but have
- this stuff only happen once. more commonly, it allows both
- the AudioTrack that is using this AudioDiskstream *and* the Session
- to call process() without problems.
- */
-
- if (_processed) {
- return 0;
- }
-
- commit_should_unlock = false;
+ playback_distance = 0;
check_record_status (transport_frame, nframes, can_record);
nominally_recording = (can_record && re);
if (nframes == 0) {
- _processed = true;
return 0;
}
- /* This lock is held until the end of ::commit, so these two functions
- must always be called as a pair. The only exception is if this function
- returns a non-zero value, in which case, ::commit should not be called.
- */
+ Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK);
- // If we can't take the state lock return.
- if (!state_lock.trylock()) {
+ if (!sm.locked()) {
return 1;
}
- commit_should_unlock = true;
+
adjust_capture_position = 0;
if (nominally_recording || (_session.get_record_enabled() && _session.config.get_punch_in())) {
ret = 0;
- _processed = true;
-
- if (ret) {
-
- /* we're exiting with failure, so ::commit will not
- be called. unlock the state lock.
- */
-
- commit_should_unlock = false;
- state_lock.unlock();
- }
+ if (commit (nframes)) {
+ need_butler = true;
+ }
return ret;
}
" = " << frames_written - frames_read
<< " + " << nframes << " < " << midi_readahead << " = " << need_butler << ")" << endl;*/
- if (commit_should_unlock) {
- state_lock.unlock();
- }
-
- _processed = false;
-
return need_butler;
}
}
int
-MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick,
- bool can_record, bool rec_monitors_input)
+MidiTrack::roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick,
+ bool can_record, bool rec_monitors_input, bool& needs_butler)
{
int dret;
boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
playback distance to zero, thus causing diskstream::commit
to do nothing.
*/
- return diskstream->process (transport_frame, 0, can_record, rec_monitors_input);
+ return diskstream->process (transport_frame, 0, can_record, rec_monitors_input, needs_butler);
}
_silent = false;
- if ((dret = diskstream->process (transport_frame, nframes, can_record, rec_monitors_input)) != 0) {
+ if ((dret = diskstream->process (transport_frame, nframes, can_record, rec_monitors_input, needs_butler)) != 0) {
silence (nframes);
return dret;
}
int
Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick,
- bool /*can_record*/, bool /*rec_monitors_input*/)
+ bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
{
{
// automation snapshot can also be called from the non-rt context
int
Route::silent_roll (nframes_t nframes, sframes_t /*start_frame*/, sframes_t /*end_frame*/,
- bool /*can_record*/, bool /*rec_monitors_input*/)
+ bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
{
silence (nframes);
return 0;
diskstream_playlist_changed (boost::weak_ptr<Diskstream> (dstream));
dstream->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_have_rec_enabled_diskstream, this));
-
- dstream->prepare ();
-
}
void
MIDI::Manager::instance()->cycle_end();
}
-void
-Session::prepare_diskstreams ()
-{
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- (*i)->prepare ();
- }
-}
-
int
Session::fail_roll (nframes_t nframes)
{
}
int
-Session::process_routes (nframes_t nframes)
+Session::process_routes (nframes_t nframes, bool& need_butler)
{
bool record_active;
int declick = get_transport_declick_required();
(*i)->set_pending_declick (declick);
- 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
- call path, so make sure we release any outstanding locks here before we return failure.
- */
-
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator ids = dsl->begin(); ids != dsl->end(); ++ids) {
- (*ids)->recover ();
- }
-
+ if ((ret = (*i)->roll (nframes, start_frame, end_frame, declick, record_active, rec_monitors, need_butler)) < 0) {
stop_transport ();
return -1;
}
}
int
-Session::silent_process_routes (nframes_t nframes)
+Session::silent_process_routes (nframes_t nframes, bool& need_butler)
{
bool record_active = actively_recording();
int declick = get_transport_declick_required();
continue;
}
- 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
- call path, so make sure we release any outstanding locks here before we return failure.
- */
-
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator ids = dsl->begin(); ids != dsl->end(); ++ids) {
- (*ids)->recover ();
- }
-
+ if ((ret = (*i)->silent_roll (nframes, start_frame, end_frame, record_active, rec_monitors, need_butler)) < 0) {
stop_transport ();
return -1;
}
}
void
-Session::commit_diskstreams (nframes_t nframes, bool &needs_butler)
+Session::get_diskstream_statistics ()
{
int dret;
float pworst = 1.0f;
continue;
}
- /* 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, actively_recording(), get_rec_monitors_input())) == 0) {
- if ((*i)->commit (nframes)) {
- needs_butler = true;
- }
-
- } else if (dret < 0) {
- (*i)->recover();
- }
-
pworst = min (pworst, (*i)->playback_buffer_load());
cworst = min (cworst, (*i)->capture_buffer_load());
}
click (_transport_frame, this_nframes);
- /* now process frames between now and the first event in this block */
- prepare_diskstreams ();
-
- if (process_routes (this_nframes)) {
+ if (process_routes (this_nframes, session_needs_butler)) {
fail_roll (nframes);
return;
}
- commit_diskstreams (this_nframes, session_needs_butler);
-
nframes -= this_nframes;
if (frames_moved < 0) {
bool need_butler;
- prepare_diskstreams ();
- silent_process_routes (nframes);
- commit_diskstreams (nframes, need_butler);
+ silent_process_routes (nframes, need_butler);
if (need_butler) {
_butler->summon ();
click (_transport_frame, nframes);
- prepare_diskstreams ();
-
if (_transport_speed == 1.0) {
frames_moved = (long) nframes;
} else {
frames_moved = (long) interpolation.interpolate (0, nframes, 0, 0);
}
- if (process_routes (nframes)) {
+ if (process_routes (nframes, session_needs_butler)) {
fail_roll (nframes);
return;
}
- commit_diskstreams (nframes, session_needs_butler);
-
if (frames_moved < 0) {
decrement_transport_position (-frames_moved);
} else {
}
int
-Track::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
+Track::no_roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame,
bool session_state_changing, bool can_record, bool /*rec_monitors_input*/)
{
if (n_outputs().n_total() == 0) {
}
int
-Track::silent_roll (nframes_t nframes, sframes_t /*start_frame*/, sframes_t /*end_frame*/,
- bool can_record, bool rec_monitors_input)
+Track::silent_roll (nframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
+ bool can_record, bool rec_monitors_input, bool& need_butler)
{
if (n_outputs().n_total() == 0 && _processors.empty()) {
return 0;
silence (nframes);
- return diskstream()->process (_session.transport_frame(), nframes, can_record, rec_monitors_input);
+ return diskstream()->process (_session.transport_frame(), nframes, can_record, rec_monitors_input, need_butler);
}
ChanCount
return cc;
}
+