smooth 0.5 second fade out during quit, plus MIDI panic to turn everything off (someone will want an opton for that, no doubt)

git-svn-id: svn://localhost/ardour2/branches/3.0@12814 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-06-21 20:31:14 +00:00
parent 33d17f176b
commit 39becbeb70
6 changed files with 93 additions and 44 deletions

View File

@ -755,11 +755,6 @@ ARDOUR_UI::finish()
if (_session) {
int tries = 0;
if (_session->transport_rolling() && (++tries < 8)) {
_session->request_stop (false, true);
usleep (10000);
}
if (_session->dirty()) {
vector<string> actions;
actions.push_back (_("Don't quit"));

View File

@ -49,9 +49,12 @@ class AudioPort : public Port
friend class AudioEngine;
AudioPort (std::string const &, Flags);
/* special access for engine only */
Sample* engine_get_whole_audio_buffer ();
private:
AudioBuffer* _buffer;
bool _buf_valid;
};
} // namespace ARDOUR

View File

@ -268,6 +268,9 @@ private:
Glib::Mutex _process_lock;
Glib::Cond session_removed;
bool session_remove_pending;
frameoffset_t session_removal_countdown;
gain_t session_removal_gain;
gain_t session_removal_gain_step;
bool _running;
bool _has_run;
mutable framecnt_t _buffer_size;
@ -283,6 +286,8 @@ private:
bool _pre_freewheel_mmc_enabled;
int _usecs_per_cycle;
bool port_remove_in_progress;
Glib::Thread* m_meter_thread;
ProcessThread* _main_thread;
SerializedRCUManager<Ports> ports;
@ -331,11 +336,8 @@ private:
void start_metering_thread ();
void stop_metering_thread ();
Glib::Thread* m_meter_thread;
static gint m_meter_exit;
ProcessThread* _main_thread;
struct ThreadData {
AudioEngine* engine;
boost::function<void()> f;

View File

@ -73,10 +73,18 @@ AudioBuffer&
AudioPort::get_audio_buffer (pframes_t nframes)
{
/* caller must hold process lock */
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
_global_port_buffer_offset + _port_buffer_offset, nframes);
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
_global_port_buffer_offset + _port_buffer_offset, nframes);
return *_buffer;
}
Sample*
AudioPort::engine_get_whole_audio_buffer ()
{
/* caller must hold process lock */
return (Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes);
}

View File

@ -62,26 +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;
_pre_freewheel_mmc_enabled = 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)) {
@ -476,28 +476,43 @@ AudioEngine::process_callback (pframes_t nframes)
}
if (session_remove_pending) {
/* perform the actual session removal */
_session = 0;
session_remove_pending = false;
/* pump one cycle of silence into the ports
before the session tears them all down
(asynchronously).
*/
if (session_removal_countdown < 0) {
boost::shared_ptr<Ports> 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);
/* 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 ();
}
}
session_removed.signal();
} 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();
@ -574,8 +589,6 @@ AudioEngine::process_callback (pframes_t nframes)
if (_session->silent()) {
boost::shared_ptr<Ports> p = ports.reader();
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
if (i->second->sends_output()) {
@ -584,6 +597,34 @@ AudioEngine::process_callback (pframes_t nframes)
}
}
if (session_remove_pending && session_removal_countdown) {
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
if (i->second->sends_output()) {
boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (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) {

View File

@ -158,7 +158,7 @@ Session::process_routes (pframes_t nframes, bool& need_butler)
const framepos_t start_frame = _transport_frame;
const framepos_t end_frame = _transport_frame + floor (nframes * _transport_speed);
if (_process_graph) {
DEBUG_TRACE(DEBUG::ProcessThreads,"calling graph/process-routes\n");
_process_graph->process_routes (nframes, start_frame, end_frame, declick, need_butler);