X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudioengine.cc;h=004ba33a6e235e4bc98731cee347d927ff5bf765;hb=80d9eaf96cd00f3084d18c32b4b31aabda0e6737;hp=74936fbc34ab53c3ff632033e3c2120b76079b3b;hpb=26366a40629693b387331c81ed255116fa8f7f7c;p=ardour.git diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 74936fbc34..004ba33a6e 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -34,27 +34,20 @@ #include #include "midi++/port.h" +#include "midi++/jack_midi_port.h" #include "midi++/mmc.h" #include "midi++/manager.h" -#include "ardour/amp.h" #include "ardour/audio_port.h" #include "ardour/audioengine.h" #include "ardour/buffer.h" -#include "ardour/buffer_set.h" #include "ardour/cycle_timer.h" -#include "ardour/delivery.h" -#include "ardour/event_type_map.h" -#include "ardour/internal_return.h" -#include "ardour/io.h" +#include "ardour/internal_send.h" #include "ardour/meter.h" #include "ardour/midi_port.h" -#include "ardour/process_thread.h" #include "ardour/port.h" -#include "ardour/port_set.h" +#include "ardour/process_thread.h" #include "ardour/session.h" -#include "ardour/timestamps.h" -#include "ardour/utils.h" #include "i18n.h" @@ -69,25 +62,26 @@ AudioEngine* AudioEngine::_instance = 0; #define GET_PRIVATE_JACK_POINTER_RET(j,r) jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return r; } AudioEngine::AudioEngine (string client_name, string session_uuid) - : ports (new Ports) + : _jack (0) + , session_remove_pending (false) + , session_removal_countdown (-1) + , _running (false) + , _has_run (false) + , _buffer_size (0) + , _frame_rate (0) + , monitor_check_interval (INT32_MAX) + , last_monitor_check (0) + , _processed_frames (0) + , _freewheeling (false) + , _pre_freewheel_mmc_enabled (false) + , _usecs_per_cycle (0) + , port_remove_in_progress (false) + , m_meter_thread (0) + , _main_thread (0) + , ports (new Ports) { _instance = this; /* singleton */ - session_remove_pending = false; - _running = false; - _has_run = false; - last_monitor_check = 0; - monitor_check_interval = INT32_MAX; - _processed_frames = 0; - _usecs_per_cycle = 0; - _jack = 0; - _frame_rate = 0; - _buffer_size = 0; - _freewheeling = false; - _main_thread = 0; - port_remove_in_progress = false; - - m_meter_thread = 0; g_atomic_int_set (&m_meter_exit, 0); if (connect_to_jack (client_name, session_uuid)) { @@ -132,7 +126,7 @@ _thread_init_callback (void * /*arg*/) SessionEvent::create_per_thread_pool (X_("Audioengine"), 512); - MIDI::Port::set_process_thread (pthread_self()); + MIDI::JackMIDIPort::set_process_thread (pthread_self()); } static void @@ -232,7 +226,7 @@ AudioEngine::stop (bool forever) } else { jack_deactivate (_priv_jack); Stopped(); /* EMIT SIGNAL */ - MIDI::Port::JackHalted (); /* EMIT SIGNAL */ + MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */ } } @@ -316,13 +310,13 @@ AudioEngine::_xrun_callback (void *arg) void AudioEngine::_session_callback (jack_session_event_t *event, void *arg) { - printf( "helo.... " ); AudioEngine* ae = static_cast (arg); if (ae->connected()) { ae->JackSessionEvent ( event ); /* EMIT SIGNAL */ } } #endif + int AudioEngine::_graph_order_callback (void *arg) { @@ -335,17 +329,6 @@ AudioEngine::_graph_order_callback (void *arg) 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 (pframes_t nframes, void *arg) -{ - return static_cast (arg)->process_callback (nframes); -} - void* AudioEngine::_process_thread (void *arg) { @@ -355,7 +338,20 @@ AudioEngine::_process_thread (void *arg) void AudioEngine::_freewheel_callback (int onoff, void *arg) { - static_cast(arg)->_freewheeling = onoff; + static_cast(arg)->freewheel_callback (onoff); +} + +void +AudioEngine::freewheel_callback (int onoff) +{ + _freewheeling = onoff; + + if (onoff) { + _pre_freewheel_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled (); + MIDI::Manager::instance()->mmc()->enable_send (false); + } else { + MIDI::Manager::instance()->mmc()->enable_send (_pre_freewheel_mmc_enabled); + } } void @@ -394,10 +390,10 @@ AudioEngine::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int co boost::shared_ptr pr = ae->ports.reader (); Ports::iterator i = pr->begin (); while (i != pr->end() && (port_a == 0 || port_b == 0)) { - if (jack_port_a == (*i)->jack_port()) { - port_a = *i; - } else if (jack_port_b == (*i)->jack_port()) { - port_b = *i; + if (jack_port_a == i->second->jack_port()) { + port_a = i->second; + } else if (jack_port_b == i->second->jack_port()) { + port_b = i->second; } ++i; } @@ -421,7 +417,7 @@ AudioEngine::split_cycle (pframes_t offset) boost::shared_ptr p = ports.reader(); for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - (*i)->cycle_split (); + i->second->cycle_split (); } } @@ -450,17 +446,18 @@ AudioEngine::process_thread () return 0; } -/** Method called by JACK (via _process_callback) which says that there - * is work to be done. - * @param nframes Number of frames to process. +/** Method called by our ::process_thread when there is work to be done. + * @param nframes Number of frames to process. */ int AudioEngine::process_callback (pframes_t nframes) { GET_PRIVATE_JACK_POINTER_RET(_jack,0); - // CycleTimer ct ("AudioEngine::process"); Glib::Mutex::Lock tm (_process_lock, Glib::TRY_LOCK); + PT_TIMING_REF; + PT_TIMING_CHECK (1); + /// The number of frames that will have been processed when we've finished pframes_t next_processed_frames; @@ -472,24 +469,63 @@ AudioEngine::process_callback (pframes_t nframes) next_processed_frames = _processed_frames + nframes; } - if (!tm.locked() || _session == 0) { + if (!tm.locked()) { /* 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(); + + if (session_removal_countdown < 0) { + + /* fade out over 1 second */ + session_removal_countdown = _frame_rate/2; + session_removal_gain = 1.0; + session_removal_gain_step = 1.0/session_removal_countdown; + + } else if (session_removal_countdown > 0) { + + /* we'll be fading audio out. + + if this is the last time we do this as part + of session removal, do a MIDI panic now + to get MIDI stopped. This relies on the fact + that "immediate data" (aka "out of band data") from + MIDI tracks is *appended* after any other data, + so that it emerges after any outbound note ons, etc. + */ + + if (session_removal_countdown <= nframes) { + _session->midi_panic (); + } + + } else { + /* fade out done */ + _session = 0; + session_removal_countdown = -1; // reset to "not in progress" + session_remove_pending = false; + session_removed.signal(); // wakes up thread that initiated session removal + } + } + + if (_session == 0) { + + if (!_freewheeling) { + MIDI::Manager::instance()->cycle_start(nframes); + MIDI::Manager::instance()->cycle_end(); + } + _processed_frames = next_processed_frames; + return 0; } /* tell all relevant objects that we're starting a new cycle */ - Delivery::CycleStart (nframes); + InternalSend::CycleStart (nframes); Port::set_global_port_buffer_offset (0); Port::set_cycle_framecnt (nframes); @@ -498,7 +534,7 @@ AudioEngine::process_callback (pframes_t nframes) boost::shared_ptr p = ports.reader(); for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - (*i)->cycle_start (nframes); + i->second->cycle_start (nframes); } /* test if we are freewheeling and there are freewheel signals connected. @@ -514,10 +550,13 @@ AudioEngine::process_callback (pframes_t nframes) } } else { + MIDI::Manager::instance()->cycle_start(nframes); + if (_session) { _session->process (nframes); - } + + MIDI::Manager::instance()->cycle_end(); } if (_freewheeling) { @@ -537,12 +576,12 @@ AudioEngine::process_callback (pframes_t nframes) bool x; - if ((*i)->last_monitor() != (x = (*i)->monitoring_input ())) { - (*i)->set_last_monitor (x); + if (i->second->last_monitor() != (x = i->second->jack_monitoring_input ())) { + i->second->set_last_monitor (x); /* XXX I think this is dangerous, due to a likely mutex in the signal handlers ... */ - (*i)->MonitorInputChanged (x); /* EMIT SIGNAL */ + i->second->MonitorInputChanged (x); /* EMIT SIGNAL */ } } last_monitor_check = next_processed_frames; @@ -550,23 +589,52 @@ AudioEngine::process_callback (pframes_t nframes) if (_session->silent()) { - boost::shared_ptr p = ports.reader(); + for (Ports::iterator i = p->begin(); i != p->end(); ++i) { + + if (i->second->sends_output()) { + i->second->get_buffer(nframes).silence(nframes); + } + } + } + + if (session_remove_pending && session_removal_countdown) { for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - if ((*i)->sends_output()) { - (*i)->get_buffer(nframes).silence(nframes); + if (i->second->sends_output()) { + + boost::shared_ptr ap = boost::dynamic_pointer_cast (i->second); + if (ap) { + Sample* s = ap->engine_get_whole_audio_buffer (); + gain_t g = session_removal_gain; + + for (pframes_t n = 0; n < nframes; ++n) { + *s++ *= g; + g -= session_removal_gain_step; + } + } } } + + if (session_removal_countdown > nframes) { + session_removal_countdown -= nframes; + } else { + session_removal_countdown = 0; + } + + session_removal_gain -= (nframes * session_removal_gain_step); } // Finalize ports for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - (*i)->cycle_end (nframes); + i->second->cycle_end (nframes); } _processed_frames = next_processed_frames; + + PT_TIMING_CHECK (2); + return 0; } @@ -651,7 +719,7 @@ AudioEngine::jack_bufsize_callback (pframes_t nframes) boost::shared_ptr p = ports.reader(); for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - (*i)->reset(); + i->second->reset(); } } @@ -716,7 +784,7 @@ AudioEngine::set_session (Session *s) boost::shared_ptr p = ports.reader(); for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - (*i)->cycle_start (blocksize); + i->second->cycle_start (blocksize); } _session->process (blocksize); @@ -729,7 +797,7 @@ AudioEngine::set_session (Session *s) _session->process (blocksize); for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - (*i)->cycle_end (blocksize); + i->second->cycle_end (blocksize); } } } @@ -770,7 +838,7 @@ AudioEngine::port_registration_failure (const std::string& portname) if (p) { reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname); } else { - reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with ports if you need this many tracks."), PROGRAM_NAME); + reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME); } throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str()); @@ -792,7 +860,7 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input) RCUWriter writer (ports); boost::shared_ptr ps = writer.get_copy (); - ps->insert (ps->begin(), newport); + ps->insert (make_pair (make_port_name_relative (portname), newport)); /* writer goes out of scope, forces update */ @@ -836,7 +904,11 @@ AudioEngine::unregister_port (boost::shared_ptr port) { RCUWriter writer (ports); boost::shared_ptr ps = writer.get_copy (); - ps->erase (port); + Ports::iterator x = ps->find (make_port_name_relative (port->name())); + + if (x != ps->end()) { + ps->erase (x); + } /* writer goes out of scope, forces update */ } @@ -985,19 +1057,40 @@ AudioEngine::get_port_by_name (const string& portname) return boost::shared_ptr (); } - std::string const rel = make_port_name_relative (portname); - boost::shared_ptr pr = ports.reader(); - - for (Ports::iterator i = pr->begin(); i != pr->end(); ++i) { - if (rel == (*i)->name()) { - return *i; + std::string rel = make_port_name_relative (portname); + Ports::iterator x = pr->find (rel); + + if (x != pr->end()) { + /* its possible that the port was renamed by some 3rd party and + we don't know about it. check for this (the check is quick + and cheap), and if so, rename the port (which will alter + the port map as a side effect). + */ + const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port())); + if (check != rel) { + x->second->set_name (check); } + return x->second; } return boost::shared_ptr (); } +void +AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name) +{ + RCUWriter writer (ports); + boost::shared_ptr p = writer.get_copy(); + Ports::iterator x = p->find (old_relative_name); + + if (x != p->end()) { + boost::shared_ptr port = x->second; + p->erase (x); + p->insert (make_pair (new_relative_name, port)); + } +} + const char ** AudioEngine::get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags) { @@ -1062,7 +1155,7 @@ AudioEngine::halted (void *arg) if (was_running) { ae->Halted(""); /* EMIT SIGNAL */ - MIDI::Port::JackHalted (); /* EMIT SIGNAL */ + MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */ } } @@ -1256,9 +1349,7 @@ AudioEngine::connect_to_jack (string client_name, string session_uuid) { EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa (); boost::scoped_ptr current_epa; - jack_options_t options = JackNullOption; jack_status_t status; - const char *server_name = NULL; /* revert all environment settings back to whatever they were when ardour started */ @@ -1274,7 +1365,7 @@ AudioEngine::connect_to_jack (string client_name, string session_uuid) _jack = jack_client_open (jack_client_name.c_str(), JackSessionID, &status, session_uuid.c_str()); else #endif - _jack = jack_client_open (jack_client_name.c_str(), options, &status, server_name); + _jack = jack_client_open (jack_client_name.c_str(), JackNullOption, &status, 0); if (_jack == NULL) { // error message is not useful here @@ -1312,7 +1403,7 @@ AudioEngine::disconnect_from_jack () if (_running) { _running = false; Stopped(); /* EMIT SIGNAL */ - MIDI::Port::JackHalted (); /* EMIT SIGNAL */ + MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */ } return 0; @@ -1337,7 +1428,7 @@ AudioEngine::reconnect_to_jack () boost::shared_ptr p = ports.reader (); for (i = p->begin(); i != p->end(); ++i) { - if ((*i)->reestablish ()) { + if (i->second->reestablish ()) { break; } } @@ -1372,7 +1463,7 @@ AudioEngine::reconnect_to_jack () /* re-establish connections */ for (i = p->begin(); i != p->end(); ++i) { - (*i)->reconnect (); + i->second->reconnect (); } MIDI::Manager::instance()->reconnect (); @@ -1492,7 +1583,7 @@ AudioEngine::port_is_physical (const std::string& portname) const } void -AudioEngine::ensure_monitor_input (const std::string& portname, bool yn) const +AudioEngine::request_jack_monitors_input (const std::string& portname, bool yn) const { GET_PRIVATE_JACK_POINTER(_jack); @@ -1513,3 +1604,10 @@ AudioEngine::update_latencies () jack_recompute_total_latencies (_priv_jack); } } + +void +AudioEngine::destroy () +{ + delete _instance; + _instance = 0; +}