X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudioengine.cc;h=cbdd1fda1ce8fc088c66161295cd3775a356dd66;hb=c7e404a1c0ee9af941a335e4bdd2f667b0c6317a;hp=2268411aca6cac499625623ab75e120fabbb3c8a;hpb=af757a1b6abaea867445ba8783676d71c30d47a1;p=ardour.git diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 2268411aca..cbdd1fda1c 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -15,19 +15,24 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ #include #include #include +#include +#include #include #include +#include +#include #include #include #include +#include +#include #include #include #include @@ -43,8 +48,13 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -nframes_t Port::_short_over_length = 2; -nframes_t Port::_long_over_length = 10; +gint AudioEngine::m_meter_exit; + +static void +ardour_jack_error (const char* msg) +{ + error << "JACK: " << msg << endmsg; +} AudioEngine::AudioEngine (string client_name) : ports (new Ports) @@ -65,7 +75,7 @@ AudioEngine::AudioEngine (string client_name) _freewheel_thread_registered = false; m_meter_thread = 0; - m_meter_exit = false; + g_atomic_int_set (&m_meter_exit, 0); if (connect_to_jack (client_name)) { throw NoBackendAvailable (); @@ -77,12 +87,15 @@ AudioEngine::AudioEngine (string client_name) AudioEngine::~AudioEngine () { - if (_running) { - jack_client_close (_jack); - } - - if(m_meter_thread) { - g_atomic_int_inc(&m_meter_exit); + { + Glib::Mutex::Lock tm (_process_lock); + session_removed.signal (); + + if (_running) { + jack_client_close (_jack); + } + + stop_metering_thread (); } } @@ -151,11 +164,18 @@ AudioEngine::start () } int -AudioEngine::stop () +AudioEngine::stop (bool forever) { if (_running) { _running = false; - jack_deactivate (_jack); + if (forever) { + jack_client_t* foo = _jack; + _jack = 0; + jack_client_close (foo); + stop_metering_thread (); + } else { + jack_deactivate (_jack); + } Stopped(); /* EMIT SIGNAL */ } @@ -163,7 +183,6 @@ AudioEngine::stop () } - bool AudioEngine::get_sync_offset (nframes_t& offset) const { @@ -195,7 +214,7 @@ void AudioEngine::jack_timebase_callback (jack_transport_state_t state, nframes_t nframes, jack_position_t* pos, int new_position) { - if (session && session->synced_to_jack()) { + if (_jack && session && session->synced_to_jack()) { session->jack_timebase_callback (state, nframes, pos, new_position); } } @@ -209,27 +228,38 @@ AudioEngine::_jack_sync_callback (jack_transport_state_t state, jack_position_t* int AudioEngine::jack_sync_callback (jack_transport_state_t state, jack_position_t* pos) { - if (session) { + if (_jack && session) { return session->jack_sync_callback (state, pos); - } else { - return true; } + + return true; } int AudioEngine::_xrun_callback (void *arg) { - static_cast(arg)->Xrun (); /* EMIT SIGNAL */ + AudioEngine* ae = static_cast (arg); + if (ae->jack()) { + ae->Xrun (); /* EMIT SIGNAL */ + } return 0; } int AudioEngine::_graph_order_callback (void *arg) { - static_cast(arg)->GraphReordered (); /* EMIT SIGNAL */ + AudioEngine* ae = static_cast (arg); + if (ae->jack()) { + ae->GraphReordered (); /* EMIT SIGNAL */ + } return 0; } +/** Wrapped which is called by JACK as its process callback. It is just + * here to get us back into C++ land by calling AudioEngine::process_callback() + * @param nframes Number of frames passed by JACK. + * @param arg User argument passed by JACK, which will be the AudioEngine*. + */ int AudioEngine::_process_callback (nframes_t nframes, void *arg) { @@ -242,11 +272,17 @@ AudioEngine::_freewheel_callback (int onoff, void *arg) static_cast(arg)->_freewheeling = onoff; } +/** Method called by JACK (via _process_callback) which says that there + * is work to be done. + * @param nframes Number of frames to process. + */ int AudioEngine::process_callback (nframes_t nframes) { // CycleTimer ct ("AudioEngine::process"); Glib::Mutex::Lock tm (_process_lock, Glib::TRY_LOCK); + + /// The number of frames that will have been processed when we've finished nframes_t next_processed_frames; /* handle wrap around of total frames counter */ @@ -256,13 +292,15 @@ AudioEngine::process_callback (nframes_t nframes) } else { next_processed_frames = _processed_frames + nframes; } - + if (!tm.locked() || session == 0) { + /* return having done nothing */ _processed_frames = next_processed_frames; return 0; } if (session_remove_pending) { + /* perform the actual session removal */ session = 0; session_remove_pending = false; session_removed.signal(); @@ -271,23 +309,35 @@ AudioEngine::process_callback (nframes_t nframes) } if (_freewheeling) { + /* emit the Freewheel signal and stop freewheeling in the event of trouble */ if (Freewheel (nframes)) { + cerr << "Freewheeling returned non-zero!\n"; _freewheeling = false; jack_set_freewheel (_jack, false); } return 0; } - session->process (nframes); + boost::shared_ptr p = ports.reader(); + + // Prepare ports (ie read data if necessary) + for (Ports::iterator i = p->begin(); i != p->end(); ++i) { + (*i)->cycle_start (nframes); + } + + if (session) { + session->process (nframes); + } if (!_running) { - /* we were zombified, maybe because a ladspa plugin took - too long, or jackd exited, or something like that. - */ - _processed_frames = next_processed_frames; return 0; } + + // Finalize ports (ie write data if necessary) + for (Ports::iterator i = p->begin(); i != p->end(); ++i) { + (*i)->cycle_end (); + } if (last_monitor_check + monitor_check_interval < next_processed_frames) { @@ -365,29 +415,69 @@ AudioEngine::jack_bufsize_callback (nframes_t nframes) return 0; } +void +AudioEngine::stop_metering_thread () +{ + if (m_meter_thread) { + g_atomic_int_set (&m_meter_exit, 1); + m_meter_thread->join (); + m_meter_thread = 0; + } +} + void AudioEngine::start_metering_thread () { - if(m_meter_thread == 0) { - m_meter_thread = Glib::Thread::create (sigc::mem_fun(this, &AudioEngine::meter_thread), false); + if (m_meter_thread == 0) { + m_meter_thread = Glib::Thread::create (sigc::mem_fun(this, &AudioEngine::meter_thread), + 500000, true, true, Glib::THREAD_PRIORITY_NORMAL); } } void AudioEngine::meter_thread () { - while (g_atomic_int_get(&m_meter_exit) != true) { - Glib::usleep (10000); /* 1/100th sec interval */ - IO::update_meters (); + while (true) { + Glib::usleep (10000); /* 1/100th sec interval */ + if (g_atomic_int_get(&m_meter_exit)) { + break; + } + IO::update_meters (); } - return; } void AudioEngine::set_session (Session *s) { + Glib::Mutex::Lock pl (_process_lock); + if (!session) { + session = s; + + nframes_t blocksize = jack_get_buffer_size (_jack); + + /* page in as much of the session process code as we + can before we really start running. + */ + + boost::shared_ptr p = ports.reader(); + + for (Ports::iterator i = p->begin(); i != p->end(); ++i) + (*i)->cycle_start (blocksize); + + s->process (blocksize); + s->process (blocksize); + s->process (blocksize); + s->process (blocksize); + s->process (blocksize); + s->process (blocksize); + s->process (blocksize); + s->process (blocksize); + + for (Ports::iterator i = p->begin(); i != p->end(); ++i) + (*i)->cycle_end (); + } } @@ -401,16 +491,13 @@ AudioEngine::remove_session () if (session) { session_remove_pending = true; session_removed.wait(_process_lock); - } + } } else { - session = 0; - } remove_all_ports (); - } Port * @@ -429,9 +516,16 @@ AudioEngine::register_input_port (DataType type, const string& portname) if (p) { - Port *newport; - - if ((newport = new Port (p)) != 0) { + Port* newport = 0; + + if (type == DataType::AUDIO) + newport = new AudioPort (p); + else if (type == DataType::MIDI) + newport = new MidiPort (p); + else + throw unknown_type(); + + if (newport != 0) { RCUWriter writer (ports); boost::shared_ptr ps = writer.get_copy (); ps->insert (ps->begin(), newport); @@ -441,8 +535,6 @@ AudioEngine::register_input_port (DataType type, const string& portname) return newport; } else { - - _process_lock.unlock(); throw PortRegistrationFailure(); } @@ -461,28 +553,30 @@ AudioEngine::register_output_port (DataType type, const string& portname) } } - jack_port_t *p; - + jack_port_t* p = 0; + if ((p = jack_port_register (_jack, portname.c_str(), - type.to_jack_type(), JackPortIsOutput, 0)) != 0) { - - Port *newport = 0; - - { + type.to_jack_type(), JackPortIsOutput, 0)) != 0) { + + Port* newport = 0; + + if (type == DataType::AUDIO) + newport = new AudioPort (p); + else if (type == DataType::MIDI) + newport = new MidiPort (p); + else + throw unknown_type (); + + if (newport != 0) { RCUWriter writer (ports); boost::shared_ptr ps = writer.get_copy (); - - newport = new Port (p); ps->insert (ps->begin(), newport); - /* writer goes out of scope, forces update */ } - + return newport; - + } else { - - _process_lock.unlock(); throw PortRegistrationFailure (); } @@ -491,44 +585,38 @@ AudioEngine::register_output_port (DataType type, const string& portname) int -AudioEngine::unregister_port (Port *port) +AudioEngine::unregister_port (Port& port) { if (!_running) { /* probably happening when the engine has been halted by JACK, in which case, there is nothing we can do here. - */ + */ return 0; } - if (port) { + int ret = jack_port_unregister (_jack, port._port); - int ret = jack_port_unregister (_jack, port->_port); - - if (ret == 0) { - - { - - RCUWriter writer (ports); - boost::shared_ptr ps = writer.get_copy (); - - for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) { - if ((*i) == port) { - ps->erase (i); - break; - } - } + if (ret == 0) { + + { - /* writer goes out of scope, forces update */ + RCUWriter writer (ports); + boost::shared_ptr ps = writer.get_copy (); + + for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) { + if ((*i) == &port) { + ps->erase (i); + break; + } } - remove_connections_for (port); + /* writer goes out of scope, forces update */ } - return ret; - - } else { - return -1; + remove_connections_for (port); } + + return ret; } int @@ -594,7 +682,7 @@ AudioEngine::disconnect (const string& source, const string& destination) } int -AudioEngine::disconnect (Port *port) +AudioEngine::disconnect (Port& port) { if (!_running) { if (!_has_run) { @@ -605,7 +693,7 @@ AudioEngine::disconnect (Port *port) } } - int ret = jack_port_disconnect (_jack, port->_port); + int ret = jack_port_disconnect (_jack, port._port); if (ret == 0) { remove_connections_for (port); @@ -615,7 +703,7 @@ AudioEngine::disconnect (Port *port) } -nframes_t +ARDOUR::nframes_t AudioEngine::frame_rate () { if (_jack) { @@ -632,7 +720,7 @@ AudioEngine::frame_rate () } } -nframes_t +ARDOUR::nframes_t AudioEngine::frames_per_cycle () { if (_jack) { @@ -649,6 +737,9 @@ AudioEngine::frames_per_cycle () } } +/** Get a port by name. + * Note this can return NULL, it will NOT create a port if it is not found (any more). + */ Port * AudioEngine::get_port_by_name (const string& portname, bool keep) { @@ -663,8 +754,6 @@ AudioEngine::get_port_by_name (const string& portname, bool keep) } } - /* check to see if we have a Port for this name already */ - boost::shared_ptr pr = ports.reader(); for (Ports::iterator i = pr->begin(); i != pr->end(); ++i) { @@ -673,26 +762,7 @@ AudioEngine::get_port_by_name (const string& portname, bool keep) } } - jack_port_t *p; - - if ((p = jack_port_by_name (_jack, portname.c_str())) != 0) { - Port *newport = new Port (p); - - { - if (keep && newport->is_mine (_jack)) { - RCUWriter writer (ports); - boost::shared_ptr ps = writer.get_copy (); - ps->insert (newport); - /* writer goes out of scope, forces update */ - } - } - - return newport; - - } else { - - return 0; - } + return 0; } const char ** @@ -712,13 +782,12 @@ AudioEngine::get_ports (const string& port_name_pattern, const string& type_name void AudioEngine::halted (void *arg) { - AudioEngine *ae = reinterpret_cast (arg); + AudioEngine* ae = static_cast (arg); ae->_running = false; - ae->_jack = 0; - ae->_buffer_size = 0; ae->_frame_rate = 0; + ae->_jack = 0; ae->Halted(); /* EMIT SIGNAL */ } @@ -810,12 +879,14 @@ AudioEngine::get_physical_outputs (vector& outs) } string -AudioEngine::get_nth_physical (uint32_t n, int flag) +AudioEngine::get_nth_physical (DataType type, uint32_t n, int flag) { const char ** ports; uint32_t i; string ret; + assert(type != DataType::NIL); + if (!_running || !_jack) { if (!_has_run) { fatal << _("get_nth_physical called before engine was started") << endmsg; @@ -825,7 +896,7 @@ AudioEngine::get_nth_physical (uint32_t n, int flag) } } - ports = jack_get_ports (_jack, NULL, NULL, JackPortIsPhysical|flag); + ports = jack_get_ports (_jack, NULL, type.to_jack_type(), JackPortIsPhysical|flag); if (ports == 0) { return ""; @@ -842,7 +913,7 @@ AudioEngine::get_nth_physical (uint32_t n, int flag) return ret; } -nframes_t +ARDOUR::nframes_t AudioEngine::get_port_total_latency (const Port& port) { if (!_jack) { @@ -951,7 +1022,7 @@ AudioEngine::remove_all_ports () } void -AudioEngine::remove_connections_for (Port* port) +AudioEngine::remove_connections_for (Port& port) { for (PortConnections::iterator i = port_connections.begin(); i != port_connections.end(); ) { PortConnections::iterator tmp; @@ -959,7 +1030,7 @@ AudioEngine::remove_connections_for (Port* port) tmp = i; ++tmp; - if ((*i).first == port->name()) { + if ((*i).first == port.name()) { port_connections.erase (i); } @@ -997,6 +1068,8 @@ AudioEngine::connect_to_jack (string client_name) if (status & JackNameNotUnique) { jack_client_name = jack_get_client_name (_jack); } + + jack_set_error_function (ardour_jack_error); return 0; } @@ -1024,9 +1097,7 @@ AudioEngine::disconnect_from_jack () return 0; } - if (jack_client_close (_jack)) { - error << _("cannot shutdown connection to JACK") << endmsg; - } + jack_client_close (_jack); _buffer_size = 0; _frame_rate = 0; @@ -1067,7 +1138,7 @@ AudioEngine::reconnect_to_jack () short_name = long_name.substr (long_name.find_last_of (':') + 1); - if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type(), (*i)->flags(), 0)) == 0) { + if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type().to_jack_type(), (*i)->flags(), 0)) == 0) { error << string_compose (_("could not reregister %1"), (*i)->name()) << endmsg; break; } else { @@ -1076,7 +1147,7 @@ AudioEngine::reconnect_to_jack () (*i)->reset (); if ((*i)->flags() & JackPortIsOutput) { - (*i)->silence (jack_get_buffer_size (_jack), 0); + (*i)->get_buffer().silence (jack_get_buffer_size (_jack), 0); } } @@ -1090,6 +1161,7 @@ AudioEngine::reconnect_to_jack () if (session) { + session->reset_jack_connection (_jack); nframes_t blocksize = jack_get_buffer_size (_jack); session->set_block_size (blocksize); session->set_frame_rate (jack_get_sample_rate (_jack)); @@ -1142,8 +1214,13 @@ int AudioEngine::request_buffer_size (nframes_t nframes) { if (_jack) { - int ret = jack_set_buffer_size (_jack, nframes); - return ret; + + if (nframes == jack_get_buffer_size (_jack)) { + return 0; + } + + return jack_set_buffer_size (_jack, nframes); + } else { return -1; } @@ -1194,3 +1271,12 @@ AudioEngine::make_port_name_non_relative (string portname) return str; } +bool +AudioEngine::is_realtime () const +{ + if (_jack) { + return jack_is_realtime (_jack); + } else { + return false; + } +}