From 47eeb6dd983965eea0906b27851f4b74a7ece60f Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 6 Nov 2025 09:18:01 -0700 Subject: [PATCH] make Route::input_change_handler() virtual and use it in MidiTrack to notice incoming notes --- libs/ardour/ardour/midi_port.h | 3 +++ libs/ardour/ardour/midi_track.h | 9 ++++++++- libs/ardour/ardour/route.h | 3 ++- libs/ardour/midi_port.cc | 8 ++++++++ libs/ardour/midi_track.cc | 22 ++++++++++++++++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h index 47017dddc1..e66272285e 100644 --- a/libs/ardour/ardour/midi_port.h +++ b/libs/ardour/ardour/midi_port.h @@ -68,6 +68,9 @@ class LIBARDOUR_API MidiPort : public Port { void read_and_parse_entire_midi_buffer_with_no_speed_adjustment (pframes_t nframes, MIDI::Parser& parser, samplepos_t now); + PBD::Signal NoteOn; + PBD::Signal NoteOff; + protected: friend class PortManager; diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index eeea1ab190..bfbdf8a35c 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -142,6 +142,8 @@ public: void realtime_handle_transport_stopped (); void region_edited (std::shared_ptr); + int last_seen_external_midi_note () const { return _last_seen_external_midi_note; } + protected: XMLNode& state (bool save_template) const; @@ -152,6 +154,8 @@ protected: void snapshot_out_of_band_data (samplecnt_t nframes); void write_out_of_band_data (BufferSet& bufs, samplecnt_t /* nframes */) const; + void input_change_handler (IOChange, void *src); + private: MidiRingBuffer _immediate_events; @@ -165,6 +169,7 @@ private: bool _restore_pgm_on_load; MidiChannelFilter _playback_filter; MidiChannelFilter _capture_filter; + int _last_seen_external_midi_note; std::shared_ptr _velocity_control; @@ -185,7 +190,9 @@ private: void playlist_contents_changed (); PBD::ScopedConnection playlist_content_change_connection; + + PBD::ScopedConnectionList note_connections; + void note_on_handler (int); }; } /* namespace ARDOUR*/ - diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index b451d83801..07a9547f38 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -710,6 +710,8 @@ protected: SlavableAutomationControlList slavables () const; + virtual void input_change_handler (IOChange, void *src); + private: /* no copy construction */ Route (Route const &); @@ -717,7 +719,6 @@ private: int set_state_2X (const XMLNode&, int); void set_processor_state_2X (XMLNodeList const &, int); - void input_change_handler (IOChange, void *src); void output_change_handler (IOChange, void *src); void sidechain_change_handler (IOChange, void *src); diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index ed93667b75..00d20dffa0 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -152,6 +152,14 @@ MidiPort::get_midi_buffer (pframes_t nframes) timestamp -= _global_port_buffer_offset; + if (size == 3) { + if (((buf[0] & 0xF0) == 0x90) && (buf[2] != 0)) { + NoteOn (buf[1]); + } else if (((buf[0] & 0xF0) == 0x80) || (((buf[0] & 0xF0) == 0x90) && (buf[2] == 0))) { + NoteOff (buf[1]); + } + } + if ((buf[0] & 0xF0) == 0x90 && buf[2] == 0) { /* normalize note on with velocity 0 to proper note off */ uint8_t ev[3]; diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 4a793c33d0..7b00509417 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -90,6 +90,7 @@ MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode) , _step_editing (false) , _input_active (true) , _restore_pgm_on_load (true) + , _last_seen_external_midi_note (-1) { _session.SessionLoaded.connect_same_thread (*this, std::bind (&MidiTrack::restore_controls, this)); @@ -979,3 +980,24 @@ MidiTrack::playlist_contents_changed () { } + +void +MidiTrack::input_change_handler (IOChange change, void *src) +{ + note_connections.drop_connections (); + + for (auto const & p : *_input->ports()) { + std::shared_ptr mp = std::dynamic_pointer_cast (p); + if (mp) { + mp->NoteOn.connect_same_thread (note_connections, std::bind (&MidiTrack::note_on_handler, this, _1)); + } + } + + Track::input_change_handler (change, src); +} + +void +MidiTrack::note_on_handler (int notenum) +{ + _last_seen_external_midi_note = notenum; +}