diff options
author | David Robillard <d@drobilla.net> | 2009-10-24 00:39:28 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2009-10-24 00:39:28 +0000 |
commit | a532e7247cfccaf35edbb9b76868ead3cc9b1342 (patch) | |
tree | 3bd051d42f95dccf78d70ed0d389ab6c98c42ff9 /libs/ardour | |
parent | d56817e7856040adf3db6bda812dfaef7d493c80 (diff) |
Move butler methods from Session to Butler.
Slay the dragon. A lil' bit.
git-svn-id: svn://localhost/ardour2/branches/3.0@5901 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r-- | libs/ardour/ardour/butler.h | 33 | ||||
-rw-r--r-- | libs/ardour/ardour/diskstream.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_diskstream.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 37 | ||||
-rw-r--r-- | libs/ardour/audio_diskstream.cc | 30 | ||||
-rw-r--r-- | libs/ardour/butler.cc | 365 | ||||
-rw-r--r-- | libs/ardour/midi_diskstream.cc | 3 | ||||
-rw-r--r-- | libs/ardour/session.cc | 8 | ||||
-rw-r--r-- | libs/ardour/session_butler.cc | 343 | ||||
-rw-r--r-- | libs/ardour/session_events.cc | 5 | ||||
-rw-r--r-- | libs/ardour/session_export.cc | 8 | ||||
-rw-r--r-- | libs/ardour/session_process.cc | 25 | ||||
-rw-r--r-- | libs/ardour/session_state.cc | 5 | ||||
-rw-r--r-- | libs/ardour/session_transport.cc | 32 |
14 files changed, 466 insertions, 430 deletions
diff --git a/libs/ardour/ardour/butler.h b/libs/ardour/ardour/butler.h index 524651ba28..b88b820736 100644 --- a/libs/ardour/ardour/butler.h +++ b/libs/ardour/ardour/butler.h @@ -25,17 +25,48 @@ namespace ARDOUR { +class Session; + class Butler { public: - Butler(); + Butler(Session* session); ~Butler(); + int start_thread(); + void terminate_thread(); + void schedule_transport_work(); + void summon(); + void stop(); + void wait_until_finished(); + bool transport_work_requested() const; + + float read_data_rate() const; ///< in usec + float write_data_rate() const; + + uint32_t audio_diskstream_buffer_size() const { return audio_dstream_buffer_size; } + uint32_t midi_diskstream_buffer_size() const { return midi_dstream_buffer_size; } + + static void* _thread_work(void *arg); + void* thread_work(); + + struct Request { + enum Type { + Wake, + Run, + Pause, + Quit + }; + }; + + Session* session; pthread_t thread; Glib::Mutex request_lock; Glib::Cond paused; bool should_run; mutable gint should_do_transport_work; int request_pipe[2]; + uint32_t audio_dstream_buffer_size; + uint32_t midi_dstream_buffer_size; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index e135d1319b..8ae9dff6e3 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -163,6 +163,7 @@ class Diskstream : public SessionObject, public boost::noncopyable protected: friend class Session; + friend class Butler; /* the Session is the only point of access for these because they require * that the Session is "inactive" while they are called. diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index 4dbabcc802..930d37330a 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -112,6 +112,7 @@ class MidiDiskstream : public Diskstream protected: friend class Session; + friend class Butler; /* the Session is the only point of access for these because they require that the Session is "inactive" diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index aa15f07e8d..baf7343496 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -298,14 +298,18 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable bool have_captured() const { return _have_captured; } void refill_all_diskstream_buffers (); - uint32_t audio_diskstream_buffer_size() const { return audio_dstream_buffer_size; } - uint32_t midi_diskstream_buffer_size() const { return midi_dstream_buffer_size; } + Butler* butler() { return _butler; } + void butler_transport_work (); uint32_t get_next_diskstream_id() const { return n_diskstreams(); } uint32_t n_diskstreams() const; + void refresh_disk_space (); + typedef std::list<boost::shared_ptr<Diskstream> > DiskstreamList; + SerializedRCUManager<DiskstreamList>& diskstream_list() { return diskstreams; } + int load_routes (const XMLNode&, int); boost::shared_ptr<RouteList> get_routes() const { return routes.reader (); @@ -924,9 +928,6 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable void reset_playback_load_min (); void reset_capture_load_min (); - float read_data_rate () const; // in usec - float write_data_rate () const; - /* ranges */ void set_audio_range (std::list<AudioRange>&); @@ -975,8 +976,6 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable protected: friend class Diskstream; - void stop_butler (); - void wait_till_butler_finished(); protected: friend class Route; @@ -1188,18 +1187,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable bool pending_abort; bool pending_auto_loop; - Butler* butler; - - bool transport_work_requested() const; - - struct ButlerRequest { - enum Type { - Wake, - Run, - Pause, - Quit - }; - }; + Butler* _butler; enum PostTransportWork { PostTransportStop = 0x1, @@ -1232,13 +1220,6 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable PostTransportWork post_transport_work; - void summon_butler (); - void schedule_butler_transport_work (); - int start_butler_thread (); - void terminate_butler_thread (); - static void *_butler_thread_work (void *arg); - void* butler_thread_work (); - uint32_t cumulative_rf_motion; uint32_t rf_scale; @@ -1421,7 +1402,6 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable void non_realtime_locate (); void non_realtime_stop (bool abort, int entry_request_count, bool& finished); void non_realtime_overwrite (int entry_request_count, bool& finished); - void butler_transport_work (); void post_transport (); void engine_halted (); void xrun_recovery (); @@ -1439,8 +1419,6 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable SerializedRCUManager<DiskstreamList> diskstreams; - uint32_t audio_dstream_buffer_size; - uint32_t midi_dstream_buffer_size; int load_diskstreams (const XMLNode&); /* routes stuff */ @@ -1581,7 +1559,6 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable Glib::Mutex space_lock; std::string get_best_session_directory_for_new_source (); - void refresh_disk_space (); mutable gint _playback_load; mutable gint _capture_load; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index aa002130f8..661ddf139e 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -37,24 +37,25 @@ #include "pbd/enumwriter.h" #include "pbd/stacktrace.h" -#include "ardour/ardour.h" -#include "ardour/audioengine.h" #include "ardour/analyser.h" +#include "ardour/ardour.h" +#include "ardour/audio_buffer.h" #include "ardour/audio_diskstream.h" -#include "ardour/utils.h" -#include "ardour/configuration.h" +#include "ardour/audio_port.h" +#include "ardour/audioengine.h" #include "ardour/audiofilesource.h" -#include "ardour/send.h" -#include "ardour/region_factory.h" #include "ardour/audioplaylist.h" -#include "ardour/playlist_factory.h" -#include "ardour/cycle_timer.h" #include "ardour/audioregion.h" -#include "ardour/audio_port.h" -#include "ardour/source_factory.h" -#include "ardour/audio_buffer.h" -#include "ardour/session.h" +#include "ardour/butler.h" +#include "ardour/configuration.h" +#include "ardour/cycle_timer.h" #include "ardour/io.h" +#include "ardour/playlist_factory.h" +#include "ardour/region_factory.h" +#include "ardour/send.h" +#include "ardour/session.h" +#include "ardour/source_factory.h" +#include "ardour/utils.h" #include "i18n.h" #include <locale.h> @@ -2065,10 +2066,9 @@ AudioDiskstream::set_align_style_from_io () int AudioDiskstream::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many) { - while (how_many--) { - c->push_back (new ChannelInfo(_session.audio_diskstream_buffer_size(), speed_buffer_size, wrap_buffer_size)); - interpolation.add_channel_to (_session.audio_diskstream_buffer_size(), speed_buffer_size); + c->push_back (new ChannelInfo(_session.butler()->audio_diskstream_buffer_size(), speed_buffer_size, wrap_buffer_size)); + interpolation.add_channel_to (_session.butler()->audio_diskstream_buffer_size(), speed_buffer_size); } _n_channels.set(DataType::AUDIO, c->size()); diff --git a/libs/ardour/butler.cc b/libs/ardour/butler.cc index 33811ca387..3d43c11e38 100644 --- a/libs/ardour/butler.cc +++ b/libs/ardour/butler.cc @@ -17,12 +17,32 @@ */ +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <poll.h> +#include "pbd/error.h" +#include "pbd/pthread_utils.h" #include "ardour/butler.h" +#include "ardour/crossfade.h" +#include "ardour/io.h" +#include "ardour/midi_diskstream.h" +#include "ardour/session.h" + +#include "i18n.h" + +using namespace PBD; + +static float _read_data_rate; +static float _write_data_rate; namespace ARDOUR { -Butler::Butler() - : thread(0) +Butler::Butler(Session* s) + : session(s) + , thread(0) + , audio_dstream_buffer_size(0) + , midi_dstream_buffer_size(0) { g_atomic_int_set(&should_do_transport_work, 0); } @@ -31,4 +51,345 @@ Butler::~Butler() { } +int +Butler::start_thread() +{ + const float rate = (float)session->frame_rate(); + + /* size is in Samples, not bytes */ + audio_dstream_buffer_size = (uint32_t) floor (Config->get_audio_track_buffer_seconds() * rate); + + /* size is in bytes + * XXX: Jack needs to tell us the MIDI buffer size + * (i.e. how many MIDI bytes we might see in a cycle) + */ + midi_dstream_buffer_size = (uint32_t) floor (Config->get_midi_track_buffer_seconds() * rate); + + MidiDiskstream::set_readahead_frames ((nframes_t)(Config->get_midi_readahead() * rate)); + + Crossfade::set_buffer_size (audio_dstream_buffer_size); + + should_run = false; + + if (pipe (request_pipe)) { + error << string_compose(_("Cannot create transport request signal pipe (%1)"), + strerror (errno)) << endmsg; + return -1; + } + + if (fcntl (request_pipe[0], F_SETFL, O_NONBLOCK)) { + error << string_compose(_("UI: cannot set O_NONBLOCK on butler request pipe (%1)"), + strerror (errno)) << endmsg; + return -1; + } + + if (fcntl (request_pipe[1], F_SETFL, O_NONBLOCK)) { + error << string_compose(_("UI: cannot set O_NONBLOCK on butler request pipe (%1)"), + strerror (errno)) << endmsg; + return -1; + } + + if (pthread_create_and_store ("disk butler", &thread, 0, _thread_work, this)) { + error << _("Session: could not create butler thread") << endmsg; + return -1; + } + + //pthread_detach (thread); + + return 0; +} + +void +Butler::terminate_thread () +{ + if (thread) { + void* status; + const char c = Request::Quit; + ::write (request_pipe[1], &c, 1); + pthread_join (thread, &status); + } +} + +void * +Butler::_thread_work (void* arg) +{ + PBD::notify_gui_about_thread_creation (pthread_self(), X_("Butler")); + return ((Butler *) arg)->thread_work (); +} + +void * +Butler::thread_work () +{ + uint32_t err = 0; + int32_t bytes; + bool compute_io; + microseconds_t begin, end; + + struct pollfd pfd[1]; + bool disk_work_outstanding = false; + Session::DiskstreamList::iterator i; + + while (true) { + pfd[0].fd = request_pipe[0]; + pfd[0].events = POLLIN|POLLERR|POLLHUP; + + if (poll (pfd, 1, (disk_work_outstanding ? 0 : -1)) < 0) { + + if (errno == EINTR) { + continue; + } + + error << string_compose (_("poll on butler request pipe failed (%1)"), + strerror (errno)) + << endmsg; + break; + } + + if (pfd[0].revents & ~POLLIN) { + error << string_compose (_("Error on butler thread request pipe: fd=%1 err=%2"), pfd[0].fd, pfd[0].revents) << endmsg; + break; + } + + if (pfd[0].revents & POLLIN) { + + char req; + + /* empty the pipe of all current requests */ + + while (1) { + size_t nread = ::read (request_pipe[0], &req, sizeof (req)); + if (nread == 1) { + + switch ((Request::Type) req) { + + case Request::Wake: + break; + + case Request::Run: + should_run = true; + break; + + case Request::Pause: + should_run = false; + break; + + case Request::Quit: + pthread_exit_pbd (0); + /*NOTREACHED*/ + break; + + default: + break; + } + + } else if (nread == 0) { + break; + } else if (errno == EAGAIN) { + break; + } else { + fatal << _("Error reading from butler request pipe") << endmsg; + /*NOTREACHED*/ + } + } + } + + if (transport_work_requested()) { + session->butler_transport_work (); + } + + disk_work_outstanding = false; + bytes = 0; + compute_io = true; + + begin = get_microseconds(); + + boost::shared_ptr<Session::DiskstreamList> dsl = session->diskstream_list().reader (); + +// for (i = dsl->begin(); i != dsl->end(); ++i) { +// cerr << "BEFORE " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; +// } + + for (i = dsl->begin(); !transport_work_requested() && should_run && i != dsl->end(); ++i) { + + boost::shared_ptr<Diskstream> ds = *i; + + /* don't read inactive tracks */ + + boost::shared_ptr<IO> io = ds->io(); + + if (io && !io->active()) { + continue; + } + + switch (ds->do_refill ()) { + case 0: + bytes += ds->read_data_count(); + break; + case 1: + bytes += ds->read_data_count(); + disk_work_outstanding = true; + break; + + default: + compute_io = false; + error << string_compose(_("Butler read ahead failure on dstream %1"), (*i)->name()) << endmsg; + break; + } + + } + + if (i != dsl->end()) { + /* we didn't get to all the streams */ + disk_work_outstanding = true; + } + + if (!err && transport_work_requested()) { + continue; + } + + if (compute_io) { + end = get_microseconds(); + if (end - begin > 0) { + _read_data_rate = (float) bytes / (float) (end - begin); + } else { + _read_data_rate = 0; // infinity better + } + } + + bytes = 0; + compute_io = true; + begin = get_microseconds(); + + for (i = dsl->begin(); !transport_work_requested() && should_run && i != dsl->end(); ++i) { + // cerr << "write behind for " << (*i)->name () << endl; + + /* note that we still try to flush diskstreams attached to inactive routes + */ + + switch ((*i)->do_flush (ButlerContext)) { + case 0: + bytes += (*i)->write_data_count(); + break; + case 1: + bytes += (*i)->write_data_count(); + disk_work_outstanding = true; + break; + + default: + err++; + compute_io = false; + error << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << endmsg; + /* don't break - try to flush all streams in case they + are split across disks. + */ + } + } + + if (err && session->actively_recording()) { + /* stop the transport and try to catch as much possible + captured state as we can. + */ + session->request_stop (); + } + + if (i != dsl->end()) { + /* we didn't get to all the streams */ + disk_work_outstanding = true; + } + + if (!err && transport_work_requested()) { + continue; + } + + if (compute_io) { + // there are no apparent users for this calculation? + end = get_microseconds(); + if(end-begin > 0) { + _write_data_rate = (float) bytes / (float) (end - begin); + } else { + _write_data_rate = 0; // Well, infinity would be better + } + } + + if (!disk_work_outstanding) { + session->refresh_disk_space (); + } + + + { + Glib::Mutex::Lock lm (request_lock); + + if (should_run && (disk_work_outstanding || transport_work_requested())) { +// for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { +// cerr << "AFTER " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; +// } + + continue; + } + + paused.signal(); + } + } + + pthread_exit_pbd (0); + /*NOTREACHED*/ + return (0); +} + +void +Butler::schedule_transport_work () +{ + g_atomic_int_inc (&should_do_transport_work); + summon (); +} + +void +Butler::summon () +{ + char c = Request::Run; + ::write (request_pipe[1], &c, 1); +} + +void +Butler::stop () +{ + Glib::Mutex::Lock lm (request_lock); + char c = Request::Pause; + ::write (request_pipe[1], &c, 1); + paused.wait(request_lock); +} + +void +Butler::wait_until_finished () +{ + Glib::Mutex::Lock lm (request_lock); + char c = Request::Wake; + ::write (request_pipe[1], &c, 1); + paused.wait(request_lock); +} + +bool +Butler::transport_work_requested () const +{ + return g_atomic_int_get(&should_do_transport_work); +} + +float +Butler::read_data_rate () const +{ + /* disk i/o in excess of 10000MB/sec indicate the buffer cache + in action. ignore it. + */ + return _read_data_rate > 10485.7600000f ? 0.0f : _read_data_rate; +} + +float +Butler::write_data_rate () const +{ + /* disk i/o in excess of 10000MB/sec indicate the buffer cache + in action. ignore it. + */ + return _write_data_rate > 10485.7600000f ? 0.0f : _write_data_rate; +} + } // namespace ARDOUR diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 262a29d1df..1840b950fd 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -38,6 +38,7 @@ #include "ardour/ardour.h" #include "ardour/audioengine.h" +#include "ardour/butler.h" #include "ardour/configuration.h" #include "ardour/cycle_timer.h" #include "ardour/io.h" @@ -123,7 +124,7 @@ MidiDiskstream::init (Diskstream::Flag f) set_block_size (_session.get_block_size()); allocate_temporary_buffers (); - const size_t size = _session.midi_diskstream_buffer_size(); + const size_t size = _session.butler()->midi_diskstream_buffer_size(); _playback_buf = new MidiRingBuffer<nframes_t>(size); _capture_buf = new MidiRingBuffer<nframes_t>(size); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index a42d764c9e..aef643efea 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -130,7 +130,7 @@ Session::Session (AudioEngine &eng, _session_dir (new SessionDirectory(fullpath)), pending_events (2048), state_tree (0), - butler (new Butler ()), + _butler (new Butler (this)), post_transport_work((PostTransportWork)0), _send_smpte_update (false), midi_thread (pthread_t (0)), @@ -216,7 +216,7 @@ Session::Session (AudioEngine &eng, _session_dir ( new SessionDirectory(fullpath)), pending_events (2048), state_tree (0), - butler (new Butler ()), + _butler (new Butler (this)), post_transport_work((PostTransportWork)0), _send_smpte_update (false), midi_thread (pthread_t (0)), @@ -356,7 +356,7 @@ Session::destroy () Stateful::loading_state_version = 0; - terminate_butler_thread (); + _butler->terminate_thread (); //terminate_midi_thread (); if (click_data != default_click) { @@ -3499,7 +3499,7 @@ Session::set_audition (boost::shared_ptr<Region> r) { pending_audition_region = r; post_transport_work = PostTransportWork (post_transport_work | PostTransportAudition); - schedule_butler_transport_work (); + _butler->schedule_transport_work (); } void diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc index 2a217e5630..41b4851ce5 100644 --- a/libs/ardour/session_butler.cc +++ b/libs/ardour/session_butler.cc @@ -47,9 +47,6 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -static float _read_data_rate; -static float _write_data_rate; - /* XXX put this in the right place */ static inline uint32_t next_power_of_two (uint32_t n) @@ -68,326 +65,13 @@ static inline uint32_t next_power_of_two (uint32_t n) BUTLER THREAD ---------------------------------------------------------------------------*/ -int -Session::start_butler_thread () -{ - /* size is in Samples, not bytes */ - audio_dstream_buffer_size = (uint32_t) floor (Config->get_audio_track_buffer_seconds() * (float) frame_rate()); - - /* size is in bytes - * XXX: Jack needs to tell us the MIDI buffer size - * (i.e. how many MIDI bytes we might see in a cycle) - */ - midi_dstream_buffer_size = (uint32_t) floor (Config->get_midi_track_buffer_seconds() * (float)frame_rate()); - MidiDiskstream::set_readahead_frames ((nframes_t) (Config->get_midi_readahead() * (float) frame_rate())); - - Crossfade::set_buffer_size (audio_dstream_buffer_size); - - butler->should_run = false; - - if (pipe (butler->request_pipe)) { - error << string_compose(_("Cannot create transport request signal pipe (%1)"), strerror (errno)) << endmsg; - return -1; - } - - if (fcntl (butler->request_pipe[0], F_SETFL, O_NONBLOCK)) { - error << string_compose(_("UI: cannot set O_NONBLOCK on butler request pipe (%1)"), strerror (errno)) << endmsg; - return -1; - } - - if (fcntl (butler->request_pipe[1], F_SETFL, O_NONBLOCK)) { - error << string_compose(_("UI: cannot set O_NONBLOCK on butler request pipe (%1)"), strerror (errno)) << endmsg; - return -1; - } - - if (pthread_create_and_store ("disk butler", &butler->thread, 0, _butler_thread_work, this)) { - error << _("Session: could not create butler thread") << endmsg; - return -1; - } - - // pthread_detach (butler->thread); - - return 0; -} - -void -Session::terminate_butler_thread () -{ - if (butler->thread) { - void* status; - char c = ButlerRequest::Quit; - ::write (butler->request_pipe[1], &c, 1); - pthread_join (butler->thread, &status); - } -} - -void -Session::schedule_butler_transport_work () -{ - g_atomic_int_inc (&butler->should_do_transport_work); - summon_butler (); -} - void Session::schedule_curve_reallocation () { post_transport_work = PostTransportWork (post_transport_work | PostTransportCurveRealloc); - schedule_butler_transport_work (); -} - -void -Session::summon_butler () -{ - char c = ButlerRequest::Run; - ::write (butler->request_pipe[1], &c, 1); - // PBD::stacktrace (cerr); -} - -void -Session::stop_butler () -{ - Glib::Mutex::Lock lm (butler->request_lock); - char c = ButlerRequest::Pause; - ::write (butler->request_pipe[1], &c, 1); - butler->paused.wait(butler->request_lock); -} - -void -Session::wait_till_butler_finished () -{ - Glib::Mutex::Lock lm (butler->request_lock); - char c = ButlerRequest::Wake; - ::write (butler->request_pipe[1], &c, 1); - butler->paused.wait(butler->request_lock); -} - -void * -Session::_butler_thread_work (void* arg) -{ - PBD::notify_gui_about_thread_creation (pthread_self(), X_("Butler")); - return ((Session *) arg)->butler_thread_work (); - return 0; -} - -void * -Session::butler_thread_work () -{ - uint32_t err = 0; - int32_t bytes; - bool compute_io; - microseconds_t begin, end; - - struct pollfd pfd[1]; - bool disk_work_outstanding = false; - DiskstreamList::iterator i; - - while (true) { - pfd[0].fd = butler->request_pipe[0]; - pfd[0].events = POLLIN|POLLERR|POLLHUP; - - if (poll (pfd, 1, (disk_work_outstanding ? 0 : -1)) < 0) { - - if (errno == EINTR) { - continue; - } - - error << string_compose (_("poll on butler request pipe failed (%1)"), - strerror (errno)) - << endmsg; - break; - } - - if (pfd[0].revents & ~POLLIN) { - error << string_compose (_("Error on butler thread request pipe: fd=%1 err=%2"), pfd[0].fd, pfd[0].revents) << endmsg; - break; - } - - if (pfd[0].revents & POLLIN) { - - char req; - - /* empty the pipe of all current requests */ - - while (1) { - size_t nread = ::read (butler->request_pipe[0], &req, sizeof (req)); - if (nread == 1) { - - switch ((ButlerRequest::Type) req) { - - case ButlerRequest::Wake: - break; - - case ButlerRequest::Run: - butler->should_run = true; - break; - - case ButlerRequest::Pause: - butler->should_run = false; - break; - - case ButlerRequest::Quit: - pthread_exit_pbd (0); - /*NOTREACHED*/ - break; - - default: - break; - } - - } else if (nread == 0) { - break; - } else if (errno == EAGAIN) { - break; - } else { - fatal << _("Error reading from butler request pipe") << endmsg; - /*NOTREACHED*/ - } - } - } - - if (transport_work_requested()) { - butler_transport_work (); - } - - disk_work_outstanding = false; - bytes = 0; - compute_io = true; - - begin = get_microseconds(); - - boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader (); - -// for (i = dsl->begin(); i != dsl->end(); ++i) { -// cerr << "BEFORE " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; -// } - - for (i = dsl->begin(); !transport_work_requested() && butler->should_run && i != dsl->end(); ++i) { - - boost::shared_ptr<Diskstream> ds = *i; - - /* don't read inactive tracks */ - - boost::shared_ptr<IO> io = ds->io(); - - if (io && !io->active()) { - continue; - } - - switch (ds->do_refill ()) { - case 0: - bytes += ds->read_data_count(); - break; - case 1: - bytes += ds->read_data_count(); - disk_work_outstanding = true; - break; - - default: - compute_io = false; - error << string_compose(_("Butler read ahead failure on dstream %1"), (*i)->name()) << endmsg; - break; - } - - } - - if (i != dsl->end()) { - /* we didn't get to all the streams */ - disk_work_outstanding = true; - } - - if (!err && transport_work_requested()) { - continue; - } - - if (compute_io) { - end = get_microseconds(); - if(end-begin > 0) { - _read_data_rate = (float) bytes / (float) (end - begin); - } else { _read_data_rate = 0; // infinity better - } - } - - bytes = 0; - compute_io = true; - begin = get_microseconds(); - - for (i = dsl->begin(); !transport_work_requested() && butler->should_run && i != dsl->end(); ++i) { - // cerr << "write behind for " << (*i)->name () << endl; - - /* note that we still try to flush diskstreams attached to inactive routes - */ - - switch ((*i)->do_flush (ButlerContext)) { - case 0: - bytes += (*i)->write_data_count(); - break; - case 1: - bytes += (*i)->write_data_count(); - disk_work_outstanding = true; - break; - - default: - err++; - compute_io = false; - error << string_compose(_("Butler write-behind failure on dstream %1"), (*i)->name()) << endmsg; - /* don't break - try to flush all streams in case they - are split across disks. - */ - } - } - - if (err && actively_recording()) { - /* stop the transport and try to catch as much possible - captured state as we can. - */ - request_stop (); - } - - if (i != dsl->end()) { - /* we didn't get to all the streams */ - disk_work_outstanding = true; - } - - if (!err && transport_work_requested()) { - continue; - } - - if (compute_io) { - // there are no apparent users for this calculation? - end = get_microseconds(); - if(end-begin > 0) { - _write_data_rate = (float) bytes / (float) (end - begin); - } else { - _write_data_rate = 0; // Well, infinity would be better - } - } - - if (!disk_work_outstanding) { - refresh_disk_space (); - } - - - { - Glib::Mutex::Lock lm (butler->request_lock); - - if (butler->should_run && (disk_work_outstanding || transport_work_requested())) { -// for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { -// cerr << "AFTER " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; -// } - - continue; - } - - butler->paused.signal(); - } - } - - pthread_exit_pbd (0); - /*NOTREACHED*/ - return (0); + _butler->schedule_transport_work (); } - void Session::request_overwrite_buffer (Diskstream* stream) { @@ -417,25 +101,7 @@ Session::overwrite_some_buffers (Diskstream* ds) } post_transport_work = PostTransportWork (post_transport_work | PostTransportOverWrite); - schedule_butler_transport_work (); -} - -float -Session::read_data_rate () const -{ - /* disk i/o in excess of 10000MB/sec indicate the buffer cache - in action. ignore it. - */ - return _read_data_rate > 10485.7600000f ? 0.0f : _read_data_rate; -} - -float -Session::write_data_rate () const -{ - /* disk i/o in excess of 10000MB/sec indicate the buffer cache - in action. ignore it. - */ - return _write_data_rate > 10485.7600000f ? 0.0f : _write_data_rate; + _butler->schedule_transport_work (); } uint32_t @@ -474,8 +140,3 @@ Session::reset_playback_load_min () g_atomic_int_set (&_playback_load_min, 100); } -bool -Session::transport_work_requested () const -{ - return g_atomic_int_get(&butler->should_do_transport_work); -} diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc index cf6e9f9c51..716ade0075 100644 --- a/libs/ardour/session_events.cc +++ b/libs/ardour/session_events.cc @@ -26,8 +26,9 @@ #include <glibmm/thread.h> #include "ardour/ardour.h" -#include "ardour/session.h" #include "ardour/audio_diskstream.h" +#include "ardour/butler.h" +#include "ardour/session.h" #include "i18n.h" @@ -425,7 +426,7 @@ Session::process_event (Event* ev) case Event::InputConfigurationChange: post_transport_work = PostTransportWork (post_transport_work | PostTransportInputChange); - schedule_butler_transport_work (); + _butler->schedule_transport_work (); break; case Event::SetAudioRange: diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 764898875b..3eda11bab7 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -65,7 +65,7 @@ Session::pre_export () { get_export_status (); // Init export_status - wait_till_butler_finished (); + _butler->wait_until_finished (); /* take everyone out of awrite to avoid disasters */ @@ -138,7 +138,7 @@ Session::start_audio_export (nframes_t position, bool realtime) set_transport_speed (1.0, false); butler_transport_work (); - g_atomic_int_set (&butler->should_do_transport_work, 0); + g_atomic_int_set (&_butler->should_do_transport_work, 0); post_transport (); /* we are ready to go ... */ @@ -173,7 +173,7 @@ Session::process_export (nframes_t nframes) we're running faster than realtime c/o JACK. */ - wait_till_butler_finished (); + _butler->wait_until_finished (); } /* do the usual stuff */ @@ -211,7 +211,7 @@ Session::stop_audio_export () */ realtime_stop (true); - schedule_butler_transport_work (); + _butler->schedule_transport_work (); if (!export_status->aborted()) { ExportReadFinished (); diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 41f3a52d7d..8b4d88b704 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -27,14 +27,15 @@ #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/butler.h" #include "ardour/cycle_timer.h" +#include "ardour/cycles.h" +#include "ardour/session.h" +#include "ardour/slave.h" +#include "ardour/timestamps.h" #include "midi++/manager.h" @@ -64,7 +65,7 @@ Session::process (nframes_t nframes) } if (non_realtime_work_pending()) { - if (!transport_work_requested ()) { + if (!_butler->transport_work_requested ()) { post_transport (); } } @@ -449,8 +450,9 @@ Session::process_with_events (nframes_t nframes) } /* implicit release of route lock */ - if (session_needs_butler) - summon_butler (); + if (session_needs_butler) { + _butler->summon (); + } } void @@ -766,7 +768,7 @@ Session::follow_slave_silently (nframes_t nframes, float slave_speed) commit_diskstreams (nframes, need_butler); if (need_butler) { - summon_butler (); + _butler->summon (); } int32_t frames_moved = (int32_t) floor (_transport_speed * nframes); @@ -867,8 +869,9 @@ Session::process_without_events (nframes_t nframes) maybe_stop (stop_limit); check_declick_out (); - if (session_needs_butler) - summon_butler (); + if (session_needs_butler) { + _butler->summon (); + } } /** Process callback used when the auditioner is active. @@ -889,7 +892,7 @@ Session::process_audition (nframes_t nframes) /* run the auditioner, and if it says we need butler service, ask for it */ if (auditioner->play_audition (nframes) > 0) { - summon_butler (); + _butler->summon (); } /* handle pending events */ diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 4fc35fc964..4a5d974563 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -71,6 +71,7 @@ #include "ardour/audioregion.h" #include "ardour/auditioner.h" #include "ardour/buffer.h" +#include "ardour/butler.h" #include "ardour/configuration.h" #include "ardour/control_protocol_manager.h" #include "ardour/crossfade.h" @@ -184,8 +185,6 @@ Session::first_stage_init (string fullpath, string snapshot_name) pending_locate_frame = 0; pending_locate_roll = false; pending_locate_flush = false; - audio_dstream_buffer_size = 0; - midi_dstream_buffer_size = 0; state_was_pending = false; set_next_event (); outbound_mtc_smpte_frame = 0; @@ -297,7 +296,7 @@ Session::second_stage_init (bool new_session) remove_empty_sounds (); } - if (start_butler_thread()) { + if (_butler->start_thread()) { return -1; } diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 755202718b..a4e4a81c95 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -194,7 +194,7 @@ Session::butler_transport_work () boost::shared_ptr<RouteList> r = routes.reader (); boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); - int on_entry = g_atomic_int_get (&butler->should_do_transport_work); + int on_entry = g_atomic_int_get (&_butler->should_do_transport_work); finished = true; if (post_transport_work & PostTransportCurveRealloc) { @@ -227,9 +227,9 @@ Session::butler_transport_work () if (!(*i)->hidden()) { (*i)->non_realtime_locate (_transport_frame); } - if (on_entry != g_atomic_int_get (&butler->should_do_transport_work)) { + if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) { /* new request, stop seeking, and start again */ - g_atomic_int_dec_and_test (&butler->should_do_transport_work); + g_atomic_int_dec_and_test (&_butler->should_do_transport_work); goto restart; } } @@ -243,7 +243,7 @@ Session::butler_transport_work () if (post_transport_work & PostTransportStop) { non_realtime_stop (post_transport_work & PostTransportAbort, on_entry, finished); if (!finished) { - g_atomic_int_dec_and_test (&butler->should_do_transport_work); + g_atomic_int_dec_and_test (&_butler->should_do_transport_work); goto restart; } } @@ -251,7 +251,7 @@ Session::butler_transport_work () if (post_transport_work & PostTransportOverWrite) { non_realtime_overwrite (on_entry, finished); if (!finished) { - g_atomic_int_dec_and_test (&butler->should_do_transport_work); + g_atomic_int_dec_and_test (&_butler->should_do_transport_work); goto restart; } } @@ -260,7 +260,7 @@ Session::butler_transport_work () non_realtime_set_audition (); } - g_atomic_int_dec_and_test (&butler->should_do_transport_work); + g_atomic_int_dec_and_test (&_butler->should_do_transport_work); } void @@ -282,7 +282,7 @@ Session::non_realtime_overwrite (int on_entry, bool& finished) if ((*i)->pending_overwrite) { (*i)->overwrite_existing_buffers (); } - if (on_entry != g_atomic_int_get (&butler->should_do_transport_work)) { + if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) { finished = false; return; } @@ -432,7 +432,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) if (!(*i)->hidden()) { (*i)->non_realtime_locate (_transport_frame); } - if (on_entry != g_atomic_int_get (&butler->should_do_transport_work)) { + if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) { finished = false; /* we will be back */ return; @@ -712,7 +712,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll); } - schedule_butler_transport_work (); + _butler->schedule_transport_work (); } else { @@ -906,7 +906,7 @@ Session::set_transport_speed (double speed, bool abort) } if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) { - schedule_butler_transport_work (); + _butler->schedule_transport_work (); } } } @@ -951,7 +951,7 @@ Session::stop_transport (bool abort) } realtime_stop (abort); - schedule_butler_transport_work (); + _butler->schedule_transport_work (); } void @@ -1133,7 +1133,7 @@ Session::set_slave_source (SlaveSource src) if (non_rt_required) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); - schedule_butler_transport_work (); + _butler->schedule_transport_work (); } set_dirty(); @@ -1143,7 +1143,7 @@ void Session::reverse_diskstream_buffers () { post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse); - schedule_butler_transport_work (); + _butler->schedule_transport_work (); } void @@ -1151,7 +1151,7 @@ Session::set_diskstream_speed (Diskstream* stream, double speed) { if (stream->realtime_set_speed (speed, false)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); - schedule_butler_transport_work (); + _butler->schedule_transport_work (); set_dirty (); } } @@ -1278,9 +1278,9 @@ Session::engine_halted () the picture. */ - g_atomic_int_set (&butler->should_do_transport_work, 0); + g_atomic_int_set (&_butler->should_do_transport_work, 0); post_transport_work = PostTransportWork (0); - stop_butler (); + _butler->stop (); realtime_stop (false); non_realtime_stop (false, 0, ignored); |