send sustain=off and all-notes-off when a MIDI track is muted (may fix #4295)
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 14 Dec 2011 17:17:30 +0000 (17:17 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 14 Dec 2011 17:17:30 +0000 (17:17 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@11005 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/midi_track.h
libs/ardour/ardour/route.h
libs/ardour/midi_port.cc
libs/ardour/midi_state_tracker.cc
libs/ardour/midi_track.cc
libs/ardour/route.cc

index 1f2f11b5bcb5cfb59d69776db491a8bf7a7528c0..018b5c4f601e33c17ccf49606726a79f8b861908 100644 (file)
@@ -117,6 +117,8 @@ protected:
        bool should_monitor () const;
        bool send_silence () const;
 
+       void act_on_mute ();
+
   private:
 
        virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
index 2df8ce4414cd96bada5ceccc5adafd6f72aac361..7d93c0c68bea206c4e2c737520d757ccb552fa7a 100644 (file)
@@ -140,7 +140,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
 
        bool muted () const;
        void set_mute (bool yn, void* src);
-
+       
        /* controls use set_solo() to modify this route's solo state
         */
 
@@ -468,6 +468,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
        boost::shared_ptr<MuteControllable> _mute_control;
        boost::shared_ptr<MuteMaster> _mute_master;
 
+       virtual void act_on_mute () {}
+
        std::string    _comment;
        bool           _have_internal_generator;
        bool           _solo_safe;
index 50d4ce64e83f784675136e42db080bd143c018af..9383bb237b84f711cceaed9ad5d22afb3fe8f7d0 100644 (file)
@@ -128,20 +128,16 @@ MidiPort::cycle_split ()
 void
 MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when)
 {
-       uint8_t ev[3];
-
-       ev[2] = 0;
 
        for (uint8_t channel = 0; channel <= 0xF; channel++) {
-               ev[0] = (MIDI_CMD_CONTROL | channel);
+
+               uint8_t ev[3] = { MIDI_CMD_CONTROL | channel, MIDI_CTL_SUSTAIN, 0 };
 
                /* we need to send all notes off AND turn the
                 * sustain/damper pedal off to handle synths
                 * that prioritize sustain over AllNotesOff
                 */
 
-               ev[1] = MIDI_CTL_SUSTAIN;
-
                if (jack_midi_event_write (jack_buffer, when, ev, 3) != 0) {
                        cerr << "failed to deliver sustain-zero on channel " << channel << " on port " << name() << endl;
                }
@@ -164,7 +160,7 @@ MidiPort::flush_buffers (pframes_t nframes, framepos_t /*time*/)
                if (_resolve_required) {
                        /* resolve all notes at the start of the buffer */
                        resolve_notes (jack_buffer, 0);
-                       _resolve_required= false;
+                       _resolve_required = false;
                }
 
                for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
index f5020e08a744acd5da0ff6eccd3efd00f310417b..342d9d0e58cca336ee448bed1d9ee916272f6f8e 100644 (file)
@@ -85,6 +85,14 @@ MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::ite
                        continue;
                }
 
+               /* catch AllNotesOff message and turn off all notes
+                */
+               
+               if (ev.type() == MIDI_CTL_ALL_NOTES_OFF) {
+                       cerr << "State tracker sees ALL_NOTES_OFF, silenceing " << sizeof (_active_notes) << endl;
+                       memset (_active_notes, 0, sizeof (_active_notes));
+               }
+
                track_note_onoffs (ev);
        }
 }
index 3033f3d9529d47b9aa3e9cd23a00fc19fe518216..e835008e67689800ddc1396f5e192ad3117dc38a 100644 (file)
@@ -715,3 +715,33 @@ MidiTrack::get_gui_feed_buffer () const
 {
        return midi_diskstream()->get_gui_feed_buffer ();
 }
+
+void
+MidiTrack::act_on_mute ()
+{
+       /* this is called right after our mute status has changed.
+          if we are now muted, send suitable output to shutdown
+          all our notes.
+
+          XXX we should should also stop all relevant note trackers.
+       */
+
+       if (muted()) {
+               /* only send messages for channels we are using */
+
+               uint16_t mask = 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] = { MIDI_CMD_CONTROL | channel, MIDI_CTL_SUSTAIN, 0 };
+                               write_immediate_event (3, ev);
+                               ev[1] = MIDI_CTL_ALL_NOTES_OFF;
+                               write_immediate_event (3, ev);
+                       }
+               }
+       }
+}
+       
index 46bc9b76961829ac9a838781fc29fea288e1cb8f..c97421a472ce8ed09165be830510a2a19f84cf6b 100644 (file)
@@ -805,6 +805,11 @@ Route::set_mute (bool yn, void *src)
 
        if (muted() != yn) {
                _mute_master->set_muted_by_self (yn);
+               /* allow any derived classes to respond to the mute change
+                  before anybody else knows about it.
+               */
+               act_on_mute ();
+               /* tell everyone else */
                mute_changed (src); /* EMIT SIGNAL */
                _mute_control->Changed (); /* EMIT SIGNAL */
        }