Send note-offs to VST instrument plugins on transport stop. Fixes #3583.

git-svn-id: svn://localhost/ardour2/branches/3.0@8203 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2010-12-07 14:44:47 +00:00
parent 40c162d609
commit 94b4c264d1
11 changed files with 70 additions and 7 deletions

View File

@ -42,7 +42,7 @@ public:
int roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
int declick, bool can_record, bool rec_monitors_input, bool& need_butler);
void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
void realtime_handle_transport_stopped ();
void use_new_diskstream ();
void set_diskstream (boost::shared_ptr<Diskstream>);

View File

@ -128,6 +128,8 @@ class Plugin : public PBD::StatefulDestructible, public Latent
virtual bool parameter_is_input(uint32_t) const = 0;
virtual bool parameter_is_output(uint32_t) const = 0;
virtual void realtime_handle_transport_stopped () {}
bool save_preset (std::string);
void remove_preset (std::string);
virtual bool load_preset (const std::string& uri) = 0;

View File

@ -74,6 +74,8 @@ class PluginInsert : public Processor
bool is_generator() const;
void realtime_handle_transport_stopped ();
struct PluginControl : public AutomationControl
{
PluginControl (PluginInsert* p, const Evoral::Parameter &param,

View File

@ -84,6 +84,8 @@ class Processor : public SessionObject, public Automatable, public Latent
virtual ChanCount input_streams () const { return _configured_input; }
virtual ChanCount output_streams() const { return _configured_output; }
virtual void realtime_handle_transport_stopped () {}
/* note: derived classes should implement state(), NOT get_state(), to allow
us to merge C++ inheritance and XML lack-of-inheritance reasonably
smoothly.

View File

@ -116,7 +116,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
virtual void set_record_enabled (bool /*yn*/, void * /*src*/) {}
virtual bool record_enabled() const { return false; }
virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
virtual void nonrealtime_handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
virtual void realtime_handle_transport_stopped () {}
virtual void set_pending_declick (int);
/* end of vfunc-based API */

View File

@ -28,8 +28,8 @@
#include <dlfcn.h>
#include "pbd/stateful.h"
#include <jack/types.h>
#include "ardour/plugin.h"
#include "ardour/midi_state_tracker.h"
struct _FSTHandle;
struct _FST;
@ -79,6 +79,8 @@ class VSTPlugin : public ARDOUR::Plugin
bool parameter_is_input(uint32_t i) const { return true; }
bool parameter_is_output(uint32_t i) const { return false; }
void realtime_handle_transport_stopped ();
bool load_preset (const std::string& preset_label);
virtual std::vector<PresetRecord> get_presets ();
int first_user_preset_index () const;
@ -103,6 +105,9 @@ private:
FST* _fst;
AEffect* _plugin;
bool been_resumed;
MidiStateTracker _tracker;
BufferSet _pending_stop_events;
bool _have_pending_stop_events;
};
class VSTPluginInfo : public PluginInfo

View File

@ -403,9 +403,16 @@ MidiTrack::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fr
}
void
MidiTrack::handle_transport_stopped (bool abort, bool did_locate, bool flush_processors)
MidiTrack::realtime_handle_transport_stopped ()
{
Route::handle_transport_stopped (abort, did_locate, flush_processors);
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
if (!lm.locked ()) {
return;
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->realtime_handle_transport_stopped ();
}
}
void

View File

@ -1060,3 +1060,11 @@ PluginInsert::add_plugin_with_activation (boost::shared_ptr<Plugin> plugin)
plugin->activate ();
}
}
void
PluginInsert::realtime_handle_transport_stopped ()
{
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
(*i)->realtime_handle_transport_stopped ();
}
}

View File

@ -2686,8 +2686,9 @@ Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
return false;
}
/** Called from the (non-realtime) butler thread when the transport is stopped */
void
Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
{
framepos_t now = _session.transport_frame();

View File

@ -188,6 +188,14 @@ Session::realtime_stop (bool abort, bool clear_state)
todo = PostTransportWork (todo | PostTransportStop);
}
/* call routes */
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin (); i != r->end(); ++i) {
(*i)->realtime_handle_transport_stopped ();
}
if (actively_recording()) {
/* move the transport position back to where the
@ -1487,7 +1495,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (with_stop) {
(*i)->handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
(*i)->nonrealtime_handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
}
framecnt_t old_latency = (*i)->output()->signal_latency ();

View File

@ -63,6 +63,7 @@ using std::max;
VSTPlugin::VSTPlugin (AudioEngine& e, Session& session, FSTHandle* h)
: Plugin (e, session)
, _have_pending_stop_events (false)
{
handle = h;
@ -89,6 +90,7 @@ VSTPlugin::VSTPlugin (AudioEngine& e, Session& session, FSTHandle* h)
VSTPlugin::VSTPlugin (const VSTPlugin &other)
: Plugin (other)
, _have_pending_stop_events (false)
{
handle = other.handle;
@ -514,6 +516,18 @@ VSTPlugin::connect_and_run (BufferSet& bufs,
if (bufs.count().n_midi() > 0) {
/* Track notes that we are sending to the plugin */
MidiBuffer& b = bufs.get_midi (0);
bool looped;
_tracker.track (b.begin(), b.end(), looped);
if (_have_pending_stop_events) {
/* Transmit note-offs that are pending from the last transport stop */
bufs.merge_from (_pending_stop_events, 0);
_have_pending_stop_events = false;
}
VstEvents* v = bufs.get_vst_midi (0);
_plugin->dispatcher (_plugin, effProcessEvents, 0, 0, v, 0);
}
@ -721,6 +735,19 @@ VSTPlugin::first_user_preset_index () const
return _plugin->numPrograms;
}
void
VSTPlugin::realtime_handle_transport_stopped ()
{
/* Create note-offs for any active notes and put them in _pending_stop_events, to be picked
up on the next call to connect_and_run ().
*/
_pending_stop_events.ensure_buffers (DataType::MIDI, 1, 4096);
_pending_stop_events.get_midi(0).clear ();
_tracker.resolve_notes (_pending_stop_events.get_midi (0), 0);
_have_pending_stop_events = true;
}
VSTPluginInfo::VSTPluginInfo()
{
type = ARDOUR::VST;