mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 16:46:35 +01:00
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:
parent
33d17f176b
commit
39becbeb70
6 changed files with 93 additions and 44 deletions
|
|
@ -755,11 +755,6 @@ ARDOUR_UI::finish()
|
||||||
if (_session) {
|
if (_session) {
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
|
|
||||||
if (_session->transport_rolling() && (++tries < 8)) {
|
|
||||||
_session->request_stop (false, true);
|
|
||||||
usleep (10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_session->dirty()) {
|
if (_session->dirty()) {
|
||||||
vector<string> actions;
|
vector<string> actions;
|
||||||
actions.push_back (_("Don't quit"));
|
actions.push_back (_("Don't quit"));
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,12 @@ class AudioPort : public Port
|
||||||
friend class AudioEngine;
|
friend class AudioEngine;
|
||||||
|
|
||||||
AudioPort (std::string const &, Flags);
|
AudioPort (std::string const &, Flags);
|
||||||
|
/* special access for engine only */
|
||||||
|
Sample* engine_get_whole_audio_buffer ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioBuffer* _buffer;
|
AudioBuffer* _buffer;
|
||||||
|
bool _buf_valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,9 @@ private:
|
||||||
Glib::Mutex _process_lock;
|
Glib::Mutex _process_lock;
|
||||||
Glib::Cond session_removed;
|
Glib::Cond session_removed;
|
||||||
bool session_remove_pending;
|
bool session_remove_pending;
|
||||||
|
frameoffset_t session_removal_countdown;
|
||||||
|
gain_t session_removal_gain;
|
||||||
|
gain_t session_removal_gain_step;
|
||||||
bool _running;
|
bool _running;
|
||||||
bool _has_run;
|
bool _has_run;
|
||||||
mutable framecnt_t _buffer_size;
|
mutable framecnt_t _buffer_size;
|
||||||
|
|
@ -283,6 +286,8 @@ private:
|
||||||
bool _pre_freewheel_mmc_enabled;
|
bool _pre_freewheel_mmc_enabled;
|
||||||
int _usecs_per_cycle;
|
int _usecs_per_cycle;
|
||||||
bool port_remove_in_progress;
|
bool port_remove_in_progress;
|
||||||
|
Glib::Thread* m_meter_thread;
|
||||||
|
ProcessThread* _main_thread;
|
||||||
|
|
||||||
SerializedRCUManager<Ports> ports;
|
SerializedRCUManager<Ports> ports;
|
||||||
|
|
||||||
|
|
@ -331,11 +336,8 @@ private:
|
||||||
void start_metering_thread ();
|
void start_metering_thread ();
|
||||||
void stop_metering_thread ();
|
void stop_metering_thread ();
|
||||||
|
|
||||||
Glib::Thread* m_meter_thread;
|
|
||||||
static gint m_meter_exit;
|
static gint m_meter_exit;
|
||||||
|
|
||||||
ProcessThread* _main_thread;
|
|
||||||
|
|
||||||
struct ThreadData {
|
struct ThreadData {
|
||||||
AudioEngine* engine;
|
AudioEngine* engine;
|
||||||
boost::function<void()> f;
|
boost::function<void()> f;
|
||||||
|
|
|
||||||
|
|
@ -73,10 +73,18 @@ AudioBuffer&
|
||||||
AudioPort::get_audio_buffer (pframes_t nframes)
|
AudioPort::get_audio_buffer (pframes_t nframes)
|
||||||
{
|
{
|
||||||
/* caller must hold process lock */
|
/* caller must hold process lock */
|
||||||
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
|
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
|
||||||
_global_port_buffer_offset + _port_buffer_offset, nframes);
|
_global_port_buffer_offset + _port_buffer_offset, nframes);
|
||||||
return *_buffer;
|
return *_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sample*
|
||||||
|
AudioPort::engine_get_whole_audio_buffer ()
|
||||||
|
{
|
||||||
|
/* caller must hold process lock */
|
||||||
|
return (Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
#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)
|
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 */
|
_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);
|
g_atomic_int_set (&m_meter_exit, 0);
|
||||||
|
|
||||||
if (connect_to_jack (client_name, session_uuid)) {
|
if (connect_to_jack (client_name, session_uuid)) {
|
||||||
|
|
@ -476,28 +476,43 @@ AudioEngine::process_callback (pframes_t nframes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session_remove_pending) {
|
if (session_remove_pending) {
|
||||||
|
|
||||||
/* perform the actual session removal */
|
/* perform the actual session removal */
|
||||||
_session = 0;
|
|
||||||
session_remove_pending = false;
|
|
||||||
|
|
||||||
/* pump one cycle of silence into the ports
|
if (session_removal_countdown < 0) {
|
||||||
before the session tears them all down
|
|
||||||
(asynchronously).
|
|
||||||
*/
|
|
||||||
|
|
||||||
boost::shared_ptr<Ports> p = ports.reader();
|
/* fade out over 1 second */
|
||||||
|
session_removal_countdown = _frame_rate/2;
|
||||||
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
|
session_removal_gain = 1.0;
|
||||||
|
session_removal_gain_step = 1.0/session_removal_countdown;
|
||||||
if (i->second->sends_output()) {
|
|
||||||
i->second->get_buffer (nframes).silence (nframes);
|
} 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 (_session == 0) {
|
||||||
|
|
||||||
if (!_freewheeling) {
|
if (!_freewheeling) {
|
||||||
MIDI::Manager::instance()->cycle_start(nframes);
|
MIDI::Manager::instance()->cycle_start(nframes);
|
||||||
MIDI::Manager::instance()->cycle_end();
|
MIDI::Manager::instance()->cycle_end();
|
||||||
|
|
@ -574,8 +589,6 @@ AudioEngine::process_callback (pframes_t nframes)
|
||||||
|
|
||||||
if (_session->silent()) {
|
if (_session->silent()) {
|
||||||
|
|
||||||
boost::shared_ptr<Ports> p = ports.reader();
|
|
||||||
|
|
||||||
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
|
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
|
||||||
|
|
||||||
if (i->second->sends_output()) {
|
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
|
// Finalize ports
|
||||||
|
|
||||||
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
|
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ Session::process_routes (pframes_t nframes, bool& need_butler)
|
||||||
|
|
||||||
const framepos_t start_frame = _transport_frame;
|
const framepos_t start_frame = _transport_frame;
|
||||||
const framepos_t end_frame = _transport_frame + floor (nframes * _transport_speed);
|
const framepos_t end_frame = _transport_frame + floor (nframes * _transport_speed);
|
||||||
|
|
||||||
if (_process_graph) {
|
if (_process_graph) {
|
||||||
DEBUG_TRACE(DEBUG::ProcessThreads,"calling graph/process-routes\n");
|
DEBUG_TRACE(DEBUG::ProcessThreads,"calling graph/process-routes\n");
|
||||||
_process_graph->process_routes (nframes, start_frame, end_frame, declick, need_butler);
|
_process_graph->process_routes (nframes, start_frame, end_frame, declick, need_butler);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue