mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-24 22:27:36 +01:00
fix the way mute operates for MIDI tracks
our policy is that "mute works on outputs", which means that mute should have no effect on what an instrument plugin does. However, MidiTrack::act_on_mute() used to inject sustain=0 messages into the data flow, which would affect the instrument plugin(s) in the track. now, MidiTrack::act_on_mute() simply notifies all Delivery objects in the track that a MIDI mute is needed via a channel mask. The Delivery objects notice this during their ::run() method, and deliver the required MIDI events to their output ports. There is still a potential issue that Amp objects which notice they have been muted also send a similar set of messages. This needs more investigation and possibly other changes. But this commit allows a sustained note to return after the track is muted midway through it.
This commit is contained in:
parent
919ce6309c
commit
8b09becf1d
4 changed files with 69 additions and 15 deletions
|
|
@ -30,6 +30,7 @@
|
|||
#include "ardour/types.h"
|
||||
#include "ardour/chan_count.h"
|
||||
#include "ardour/io_processor.h"
|
||||
#include "ardour/midi_buffer.h"
|
||||
#include "ardour/gain_control.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
|
@ -89,6 +90,8 @@ public:
|
|||
|
||||
void run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool);
|
||||
|
||||
void set_midi_mute_mask (int);
|
||||
|
||||
/* supplemental method used with MIDI */
|
||||
|
||||
void flush_buffers (samplecnt_t nframes);
|
||||
|
|
@ -157,6 +160,7 @@ protected:
|
|||
std::shared_ptr<Amp> _amp;
|
||||
|
||||
gain_t target_gain ();
|
||||
void maybe_merge_midi_mute (BufferSet&);
|
||||
|
||||
private:
|
||||
bool _no_outs_cuz_we_no_monitor;
|
||||
|
|
@ -176,6 +180,8 @@ private:
|
|||
void output_changed (IOChange, void*);
|
||||
|
||||
bool _no_panner_reset;
|
||||
std::atomic<int> _midi_mute_mask;
|
||||
MidiBuffer _midi_mute_buffer;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ Delivery::Delivery (Session& s, std::shared_ptr<IO> io, std::shared_ptr<Pannable
|
|||
, _mute_master (mm)
|
||||
, _rta_active (false)
|
||||
, _no_panner_reset (false)
|
||||
, _midi_mute_mask (0)
|
||||
, _midi_mute_buffer (0)
|
||||
{
|
||||
if (pannable) {
|
||||
bool is_send = false;
|
||||
|
|
@ -74,6 +76,11 @@ Delivery::Delivery (Session& s, std::shared_ptr<IO> io, std::shared_ptr<Pannable
|
|||
|
||||
_display_to_user = false;
|
||||
|
||||
const size_t stamp_size = sizeof(samplepos_t);
|
||||
const size_t etype_size = sizeof(Evoral::EventType);
|
||||
const size_t mmb_size = 16 * (stamp_size + etype_size + 3);
|
||||
_midi_mute_buffer.resize (mmb_size);
|
||||
|
||||
if (_output) {
|
||||
_output->changed.connect_same_thread (*this, std::bind (&Delivery::output_changed, this, _1, _2));
|
||||
}
|
||||
|
|
@ -90,6 +97,8 @@ Delivery::Delivery (Session& s, std::shared_ptr<Pannable> pannable, std::shared_
|
|||
, _mute_master (mm)
|
||||
, _rta_active (false)
|
||||
, _no_panner_reset (false)
|
||||
, _midi_mute_mask (0)
|
||||
, _midi_mute_buffer (0)
|
||||
{
|
||||
if (pannable) {
|
||||
bool is_send = false;
|
||||
|
|
@ -98,6 +107,10 @@ Delivery::Delivery (Session& s, std::shared_ptr<Pannable> pannable, std::shared_
|
|||
}
|
||||
|
||||
_display_to_user = false;
|
||||
const size_t stamp_size = sizeof(samplepos_t);
|
||||
const size_t etype_size = sizeof(Evoral::EventType);
|
||||
const size_t mmb_size = 16 * (stamp_size + etype_size + 3);
|
||||
_midi_mute_buffer.resize (mmb_size);
|
||||
|
||||
if (_output) {
|
||||
_output->changed.connect_same_thread (*this, std::bind (&Delivery::output_changed, this, _1, _2));
|
||||
|
|
@ -267,6 +280,38 @@ Delivery::configure_io (ChanCount in, ChanCount out)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Delivery::maybe_merge_midi_mute (BufferSet& bufs)
|
||||
{
|
||||
if (bufs.available().n_midi()) {
|
||||
|
||||
int mask = _midi_mute_mask.load(); /* atomic */
|
||||
MidiBuffer& pmbuf (bufs.get_midi (0));
|
||||
|
||||
if (mask && (_current_gain < GAIN_COEFF_SMALL)) {
|
||||
|
||||
/* mask set, and we have just been muted */
|
||||
|
||||
_midi_mute_buffer.clear ();
|
||||
|
||||
for (uint8_t channel = 0; channel <= 0xF; channel++) {
|
||||
|
||||
if ((1<<channel) & mask) {
|
||||
|
||||
uint8_t buf[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
|
||||
Evoral::Event<samplepos_t> ev (Evoral::MIDI_EVENT, 0, 3, buf);
|
||||
_midi_mute_buffer.push_back (ev);
|
||||
|
||||
/* Note we do not send MIDI_CTL_ALL_NOTES_OFF here, since this may
|
||||
silence notes that came from another non-muted track. */
|
||||
}
|
||||
}
|
||||
pmbuf.merge_from (_midi_mute_buffer, 0, 0, 0); /* last 3 args do not matter for MIDI */
|
||||
_midi_mute_mask = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Delivery::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool result_required)
|
||||
{
|
||||
|
|
@ -343,6 +388,8 @@ Delivery::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample
|
|||
_amp->run (bufs, start_sample, end_sample, speed, nframes, true);
|
||||
}
|
||||
|
||||
maybe_merge_midi_mute (bufs);
|
||||
|
||||
RTABufferListPtr rtabuffers = _rtabuffers;
|
||||
if (_rta_active.load () && rtabuffers && !rtabuffers->empty ()) {
|
||||
uint32_t n_audio = bufs.count().n_audio();
|
||||
|
|
@ -721,3 +768,8 @@ Delivery::panner () const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Delivery::set_midi_mute_mask (int mask)
|
||||
{
|
||||
_midi_mute_mask = mask; /* atomic */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,6 +333,8 @@ InternalSend::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sa
|
|||
Amp::apply_simple_gain (mixbufs, nframes, tgain);
|
||||
}
|
||||
|
||||
maybe_merge_midi_mute (mixbufs);
|
||||
|
||||
/* apply fader gain automation */
|
||||
_amp->set_gain_automation_buffer (_session.send_gain_automation_buffer ());
|
||||
_amp->setup_gain_automation (start_sample + latency, end_sample + latency, nframes);
|
||||
|
|
|
|||
|
|
@ -915,24 +915,18 @@ MidiTrack::act_on_mute ()
|
|||
|
||||
if (muted() || _mute_master->muted_by_others_soloing_at (MuteMaster::AllPoints)) {
|
||||
/* only send messages for channels we are using */
|
||||
|
||||
uint16_t mask = _playback_filter.get_channel_mask();
|
||||
|
||||
for (uint8_t channel = 0; channel <= 0xF; channel++) {
|
||||
|
||||
if ((1<<channel) & mask) {
|
||||
|
||||
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 delivers mute message to channel %2\n", name(), channel+1));
|
||||
uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
|
||||
write_immediate_event (Evoral::MIDI_EVENT, 3, ev);
|
||||
|
||||
/* Note we do not send MIDI_CTL_ALL_NOTES_OFF here, since this may
|
||||
silence notes that came from another non-muted track. */
|
||||
foreach_processor ([this](std::weak_ptr<Processor> p) {
|
||||
std::shared_ptr<Delivery> delivery = std::dynamic_pointer_cast<Delivery> (p.lock());
|
||||
if (delivery) {
|
||||
delivery->set_midi_mute_mask (_playback_filter.get_channel_mask());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* Resolve active notes. */
|
||||
_disk_reader->resolve_tracker (_immediate_events, 0);
|
||||
|
||||
if (!the_instrument()) {
|
||||
_disk_reader->resolve_tracker (_immediate_events, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue