diff options
Diffstat (limited to 'libs/ardour')
-rw-r--r-- | libs/ardour/ardour/midi_channel_filter.h | 97 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_playlist.h | 4 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_playlist_source.h | 3 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_region.h | 13 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_source.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_track.h | 67 | ||||
-rw-r--r-- | libs/ardour/ardour/smf_source.h | 3 | ||||
-rw-r--r-- | libs/ardour/midi_channel_filter.cc | 143 | ||||
-rw-r--r-- | libs/ardour/midi_diskstream.cc | 47 | ||||
-rw-r--r-- | libs/ardour/midi_playlist.cc | 8 | ||||
-rw-r--r-- | libs/ardour/midi_playlist_source.cc | 3 | ||||
-rw-r--r-- | libs/ardour/midi_region.cc | 14 | ||||
-rw-r--r-- | libs/ardour/midi_source.cc | 15 | ||||
-rw-r--r-- | libs/ardour/midi_track.cc | 86 | ||||
-rw-r--r-- | libs/ardour/smf_source.cc | 14 | ||||
-rw-r--r-- | libs/ardour/wscript | 1 |
16 files changed, 337 insertions, 186 deletions
diff --git a/libs/ardour/ardour/midi_channel_filter.h b/libs/ardour/ardour/midi_channel_filter.h new file mode 100644 index 0000000000..934b369b8c --- /dev/null +++ b/libs/ardour/ardour/midi_channel_filter.h @@ -0,0 +1,97 @@ +/* + Copyright (C) 2006-2015 Paul Davis + Author: David Robillard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_channel_filter_h__ +#define __ardour_channel_filter_h__ + +#include <stdint.h> + +#include <glib.h> + +#include "ardour/types.h" +#include "pbd/signals.h" + +namespace ARDOUR +{ + +class BufferSet; + +/** Filter/mapper for MIDI channels. + * + * Channel mapping is configured by setting a mode and "mask", where the + * meaning of the mask depends on the mode. + * + * If mode is FilterChannels, each mask bit represents a midi channel (bit 0 = + * channel 0, bit 1 = channel 1, ...). Only events whose channel corresponds + * to a 1 bit will be passed. + * + * If mode is ForceChannel, mask is simply a channel number which all events + * will be forced to. + */ +class LIBARDOUR_API MidiChannelFilter +{ +public: + MidiChannelFilter(); + + /** Filter `bufs` in-place. */ + void filter(BufferSet& bufs); + + /** Filter/map a MIDI message by channel. + * + * May modify the channel in `buf` if necessary. + * + * @return true if this event should be filtered out. + */ + bool filter(uint8_t* buf, uint32_t len); + + /** Atomically set the channel mode and corresponding mask. + * @return true iff configuration changed. + */ + bool set_channel_mode(ChannelMode mode, uint16_t mask); + + /** Atomically set the channel mask for the current mode. + * @return true iff configuration changed. + */ + bool set_channel_mask(uint16_t mask); + + /** Atomically get both the channel mode and mask. */ + void get_mode_and_mask(ChannelMode* mode, uint16_t* mask) const { + const uint32_t mm = g_atomic_int_get(&_mode_mask); + *mode = static_cast<ChannelMode>((mm & 0xFFFF0000) >> 16); + *mask = (mm & 0x0000FFFF); + } + + ChannelMode get_channel_mode() const { + return static_cast<ChannelMode>((g_atomic_int_get(&_mode_mask) & 0xFFFF0000) >> 16); + } + + uint16_t get_channel_mask() const { + return g_atomic_int_get(&_mode_mask) & 0x0000FFFF; + } + + PBD::Signal0<void> ChannelMaskChanged; + PBD::Signal0<void> ChannelModeChanged; + +private: + uint32_t _mode_mask; ///< 16 bits mode, 16 bits mask +}; + +} /* namespace ARDOUR */ + +#endif /* __ardour_channel_filter_h__ */ diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h index 614a5e1c1f..cb07bc1820 100644 --- a/libs/ardour/ardour/midi_playlist.h +++ b/libs/ardour/ardour/midi_playlist.h @@ -42,6 +42,7 @@ namespace ARDOUR { class BeatsFramesConverter; +class MidiChannelFilter; class MidiRegion; class Session; class Source; @@ -77,7 +78,8 @@ public: framecnt_t read (Evoral::EventSink<framepos_t>& buf, framepos_t start, framecnt_t cnt, - uint32_t chan_n = 0); + uint32_t chan_n = 0, + MidiChannelFilter* filter = NULL); int set_state (const XMLNode&, int version); diff --git a/libs/ardour/ardour/midi_playlist_source.h b/libs/ardour/ardour/midi_playlist_source.h index 6633be3c9e..12c184d7b5 100644 --- a/libs/ardour/ardour/midi_playlist_source.h +++ b/libs/ardour/ardour/midi_playlist_source.h @@ -65,7 +65,8 @@ protected: framepos_t position, framepos_t start, framecnt_t cnt, - MidiStateTracker* tracker) const; + MidiStateTracker* tracker, + MidiChannelFilter* filter) const; framecnt_t write_unlocked (const Lock& lock, MidiRingBuffer<framepos_t>& dst, diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index f7e6c97ea0..87e89c695b 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -43,13 +43,14 @@ template<typename Time> class EventSink; namespace ARDOUR { -class Route; -class Playlist; -class Session; +class MidiChannelFilter; class MidiFilter; class MidiModel; class MidiSource; class MidiStateTracker; +class Playlist; +class Route; +class Session; template<typename T> class MidiRingBuffer; @@ -74,7 +75,8 @@ class LIBARDOUR_API MidiRegion : public Region framecnt_t dur, uint32_t chan_n = 0, NoteMode mode = Sustained, - MidiStateTracker* tracker = 0) const; + MidiStateTracker* tracker = 0, + MidiChannelFilter* filter = 0) const; framecnt_t master_read_at (MidiRingBuffer<framepos_t>& dst, framepos_t position, @@ -121,7 +123,8 @@ class LIBARDOUR_API MidiRegion : public Region framecnt_t dur, uint32_t chan_n = 0, NoteMode mode = Sustained, - MidiStateTracker* tracker = 0) const; + MidiStateTracker* tracker = 0, + MidiChannelFilter* filter = 0) const; void register_properties (); void post_set (const PBD::PropertyChange&); diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 156f3dbfa0..6a55398ca9 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -34,6 +34,7 @@ namespace ARDOUR { +class MidiChannelFilter; class MidiStateTracker; class MidiModel; @@ -77,6 +78,7 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha framepos_t start, framecnt_t cnt, MidiStateTracker* tracker, + MidiChannelFilter* filter, const std::set<Evoral::Parameter>& filtered) const; /** Write data from a MidiRingBuffer to this source. @@ -192,7 +194,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha framepos_t position, framepos_t start, framecnt_t cnt, - MidiStateTracker* tracker) const = 0; + MidiStateTracker* tracker, + MidiChannelFilter* filter) const = 0; /** Write data to this source from a MidiRingBuffer. * @param source Buffer to read from. diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index a12a0c6087..f2542f0f6b 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -20,10 +20,9 @@ #ifndef __ardour_midi_track_h__ #define __ardour_midi_track_h__ -#include "pbd/ffs.h" - -#include "ardour/track.h" +#include "ardour/midi_channel_filter.h" #include "ardour/midi_ring_buffer.h" +#include "ardour/track.h" namespace ARDOUR { @@ -109,38 +108,22 @@ public: boost::shared_ptr<SMFSource> write_source (uint32_t n = 0); - /** Channel filtering mode. - * @param mask If mode is FilterChannels, each bit represents a midi channel: - * bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only - * process events whose channel bit is 1. - * If mode is ForceChannel, mask is simply a channel number which all events will - * be forced to while reading. - */ + /* Configure capture/playback channels (see MidiChannelFilter). */ void set_capture_channel_mode (ChannelMode mode, uint16_t mask); void set_playback_channel_mode (ChannelMode mode, uint16_t mask); void set_playback_channel_mask (uint16_t mask); void set_capture_channel_mask (uint16_t mask); - ChannelMode get_playback_channel_mode() const { - return static_cast<ChannelMode>((g_atomic_int_get(&_playback_channel_mask) & 0xffff0000) >> 16); - } - uint16_t get_playback_channel_mask() const { - return g_atomic_int_get(&_playback_channel_mask) & 0x0000ffff; - } - ChannelMode get_capture_channel_mode() const { - return static_cast<ChannelMode>((g_atomic_int_get(&_capture_channel_mask) & 0xffff0000) >> 16); - } - uint16_t get_capture_channel_mask() const { - return g_atomic_int_get(&_capture_channel_mask) & 0x0000ffff; - } + ChannelMode get_playback_channel_mode() const { return _playback_filter.get_channel_mode(); } + ChannelMode get_capture_channel_mode() const { return _capture_filter.get_channel_mode(); } + uint16_t get_playback_channel_mask() const { return _playback_filter.get_channel_mask(); } + uint16_t get_capture_channel_mask() const { return _capture_filter.get_channel_mask(); } + + MidiChannelFilter& playback_filter() { return _playback_filter; } + MidiChannelFilter& capture_filter() { return _capture_filter; } boost::shared_ptr<MidiPlaylist> midi_playlist (); - PBD::Signal0<void> PlaybackChannelMaskChanged; - PBD::Signal0<void> PlaybackChannelModeChanged; - PBD::Signal0<void> CaptureChannelMaskChanged; - PBD::Signal0<void> CaptureChannelModeChanged; - PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded; boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const; @@ -162,8 +145,8 @@ private: NoteMode _note_mode; bool _step_editing; bool _input_active; - uint32_t _playback_channel_mask; // 16 bits mode, 16 bits mask - uint32_t _capture_channel_mask; // 16 bits mode, 16 bits mask + MidiChannelFilter _playback_filter; + MidiChannelFilter _capture_filter; virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &); @@ -186,32 +169,6 @@ private: /** Update automation controls to reflect any changes in buffers. */ void update_controls (const BufferSet& bufs); - - void filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask); - -/* if mode is ForceChannel, force mask to the lowest set channel or 1 if no - * channels are set. - */ -#define force_mask(mode,mask) (((mode) == ForceChannel) ? (((mask) ? (1<<(PBD::ffs((mask))-1)) : 1)) : mask) - - void _set_playback_channel_mode(ChannelMode mode, uint16_t mask) { - mask = force_mask (mode, mask); - g_atomic_int_set(&_playback_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask)); - } - void _set_playback_channel_mask (uint16_t mask) { - mask = force_mask (get_playback_channel_mode(), mask); - g_atomic_int_set(&_playback_channel_mask, (uint32_t(get_playback_channel_mode()) << 16) | uint32_t(mask)); - } - void _set_capture_channel_mode(ChannelMode mode, uint16_t mask) { - mask = force_mask (mode, mask); - g_atomic_int_set(&_capture_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask)); - } - void _set_capture_channel_mask (uint16_t mask) { - mask = force_mask (get_capture_channel_mode(), mask); - g_atomic_int_set(&_capture_channel_mask, (uint32_t(get_capture_channel_mode()) << 16) | uint32_t(mask)); - } - -#undef force_mask }; } /* namespace ARDOUR*/ diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 29c6403694..d088f2d867 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -93,7 +93,8 @@ public: framepos_t position, framepos_t start, framecnt_t cnt, - MidiStateTracker* tracker) const; + MidiStateTracker* tracker, + MidiChannelFilter* filter) const; framecnt_t write_unlocked (const Lock& lock, MidiRingBuffer<framepos_t>& src, diff --git a/libs/ardour/midi_channel_filter.cc b/libs/ardour/midi_channel_filter.cc new file mode 100644 index 0000000000..40658802e5 --- /dev/null +++ b/libs/ardour/midi_channel_filter.cc @@ -0,0 +1,143 @@ +/* + Copyright (C) 2006-2015 Paul Davis + Author: David Robillard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "ardour/buffer_set.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_channel_filter.h" +#include "pbd/ffs.h" + +namespace ARDOUR { + +MidiChannelFilter::MidiChannelFilter() + : _mode_mask(0x0000FFFF) +{} + +void +MidiChannelFilter::filter(BufferSet& bufs) +{ + ChannelMode mode; + uint16_t mask; + get_mode_and_mask(&mode, &mask); + + if (mode == AllChannels) { + return; + } + + MidiBuffer& buf = bufs.get_midi(0); + + for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) { + Evoral::MIDIEvent<framepos_t> ev(*e, false); + + if (ev.is_channel_event()) { + switch (mode) { + case FilterChannels: + if (0 == ((1 << ev.channel()) & mask)) { + e = buf.erase (e); + } else { + ++e; + } + break; + case ForceChannel: + ev.set_channel(PBD::ffs(mask) - 1); + ++e; + break; + case AllChannels: + /* handled by the opening if() */ + ++e; + break; + } + } else { + ++e; + } + } +} + +bool +MidiChannelFilter::filter(uint8_t* buf, uint32_t len) +{ + ChannelMode mode; + uint16_t mask; + get_mode_and_mask(&mode, &mask); + + const uint8_t type = buf[0] & 0xF0; + const bool is_channel_event = (0x80 <= type) && (type <= 0xE0); + if (!is_channel_event) { + return false; + } + + const uint8_t channel = buf[0] & 0x0F; + switch (mode) { + case AllChannels: + return false; + case FilterChannels: + return !((1 << channel) & mask); + case ForceChannel: + buf[0] = (0xF0 & buf[0]) | (0x0F & (PBD::ffs(mask) - 1)); + return false; + } + + return false; +} + +/** If mode is ForceChannel, force mask to the lowest set channel or 1 if no + * channels are set. + */ +static inline uint16_t +force_mask(const ChannelMode mode, const uint16_t mask) +{ + return ((mode == ForceChannel) + ? (mask ? (1 << (PBD::ffs(mask) - 1)) : 1) + : mask); +} + +bool +MidiChannelFilter::set_channel_mode(ChannelMode mode, uint16_t mask) +{ + ChannelMode old_mode; + uint16_t old_mask; + get_mode_and_mask(&old_mode, &old_mask); + + if (old_mode != mode || old_mask != mask) { + mask = force_mask(mode, mask); + g_atomic_int_set(&_mode_mask, (uint32_t(mode) << 16) | uint32_t(mask)); + ChannelModeChanged(); + return true; + } + + return false; +} + +bool +MidiChannelFilter::set_channel_mask(uint16_t mask) +{ + ChannelMode mode; + uint16_t old_mask; + get_mode_and_mask(&mode, &old_mask); + + if (old_mask != mask) { + mask = force_mask(mode, mask); + g_atomic_int_set(&_mode_mask, (uint32_t(mode) << 16) | uint32_t(mask)); + ChannelMaskChanged(); + return true; + } + + return false; +} + +} /* namespace ARDOUR */ diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index f6ba10342a..e8b23b3431 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -403,17 +403,10 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t } if (nominally_recording || rec_nframes) { - - // Pump entire port buffer into the ring buffer (FIXME: split cycles?) - MidiBuffer& buf = sp->get_midi_buffer(nframes); - ChannelMode mode = AllChannels; - uint32_t mask = 0xffff; - - MidiTrack * mt = dynamic_cast<MidiTrack*> (_track); - if (mt) { - mode = mt->get_capture_channel_mode (); - mask = mt->get_capture_channel_mask (); - } + // Pump entire port buffer into the ring buffer (TODO: split cycles?) + MidiBuffer& buf = sp->get_midi_buffer(nframes); + MidiTrack* mt = dynamic_cast<MidiTrack*>(_track); + MidiChannelFilter* filter = mt ? &mt->capture_filter() : NULL; for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) { Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false); @@ -447,31 +440,12 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t const framecnt_t loop_offset = _num_captured_loops * loop_length; const framepos_t event_time = transport_frame + loop_offset - _accumulated_capture_offset + ev.time(); if (event_time < 0 || event_time < first_recordable_frame) { + /* Event out of range, skip */ continue; } - switch (mode) { - case AllChannels: - _capture_buf->write(event_time, - ev.type(), ev.size(), ev.buffer()); - break; - case FilterChannels: - if (ev.is_channel_event()) { - if ((1<<ev.channel()) & mask) { - _capture_buf->write(event_time, - ev.type(), ev.size(), ev.buffer()); - } - } else { - _capture_buf->write(event_time, - ev.type(), ev.size(), ev.buffer()); - } - break; - case ForceChannel: - if (ev.is_channel_event()) { - ev.set_channel (PBD::ffs(mask) - 1); - } - _capture_buf->write(event_time, - ev.type(), ev.size(), ev.buffer()); - break; + + if (!filter || !filter->filter(ev.buffer(), ev.size())) { + _capture_buf->write(event_time, ev.type(), ev.size(), ev.buffer()); } } g_atomic_int_add(const_cast<gint*>(&_frames_pending_write), nframes); @@ -736,6 +710,9 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) framecnt_t loop_length = 0; Location* loc = 0; + MidiTrack* mt = dynamic_cast<MidiTrack*>(_track); + MidiChannelFilter* filter = mt ? &mt->playback_filter() : NULL; + if (!reversed) { loc = loop_location; @@ -772,7 +749,7 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) this_read = min(dur,this_read); - if (midi_playlist()->read (*_playback_buf, start, this_read) != this_read) { + if (midi_playlist()->read (*_playback_buf, start, this_read, 0, filter) != this_read) { error << string_compose( _("MidiDiskstream %1: cannot read %2 from playlist at frame %3"), id(), this_read, start) << endmsg; diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc index 398234e2ba..c0badf7a0d 100644 --- a/libs/ardour/midi_playlist.cc +++ b/libs/ardour/midi_playlist.cc @@ -106,7 +106,11 @@ struct EventsSortByTimeAndType { }; framecnt_t -MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framecnt_t dur, unsigned chan_n) +MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, + framepos_t start, + framecnt_t dur, + unsigned chan_n, + MidiChannelFilter* filter) { typedef pair<MidiStateTracker*,framepos_t> TrackerInfo; @@ -185,7 +189,7 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec } /* Read from region into target. */ - mr->read_at (tgt, start, dur, chan_n, _note_mode, &tracker->tracker); + mr->read_at (tgt, start, dur, chan_n, _note_mode, &tracker->tracker, filter); DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tPost-read: %1 active notes\n", tracker->tracker.on())); diff --git a/libs/ardour/midi_playlist_source.cc b/libs/ardour/midi_playlist_source.cc index 4f474f7119..3d9c5b1e9f 100644 --- a/libs/ardour/midi_playlist_source.cc +++ b/libs/ardour/midi_playlist_source.cc @@ -126,7 +126,8 @@ MidiPlaylistSource::read_unlocked (const Lock& lock, Evoral::EventSink<framepos_t>& dst, framepos_t /*position*/, framepos_t start, framecnt_t cnt, - MidiStateTracker*) const + MidiStateTracker*, + MidiChannelFilter*) const { boost::shared_ptr<MidiPlaylist> mp = boost::dynamic_pointer_cast<MidiPlaylist> (_playlist); diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 5c197761ac..3e4a656ebe 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -230,9 +230,15 @@ MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute) } framecnt_t -MidiRegion::read_at (Evoral::EventSink<framepos_t>& out, framepos_t position, framecnt_t dur, uint32_t chan_n, NoteMode mode, MidiStateTracker* tracker) const +MidiRegion::read_at (Evoral::EventSink<framepos_t>& out, + framepos_t position, + framecnt_t dur, + uint32_t chan_n, + NoteMode mode, + MidiStateTracker* tracker, + MidiChannelFilter* filter) const { - return _read_at (_sources, out, position, dur, chan_n, mode, tracker); + return _read_at (_sources, out, position, dur, chan_n, mode, tracker, filter); } framecnt_t @@ -248,7 +254,8 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, framecnt_t dur, uint32_t chan_n, NoteMode mode, - MidiStateTracker* tracker) const + MidiStateTracker* tracker, + MidiChannelFilter* filter) const { frameoffset_t internal_offset = 0; framecnt_t to_read = 0; @@ -301,6 +308,7 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, _start + internal_offset, // where to start reading in the source to_read, // read duration in frames tracker, + filter, _filtered_parameters ) != to_read) { return 0; /* "read nothing" */ diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 47cfb1b0a0..ab972fabd8 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -38,10 +38,11 @@ #include "evoral/EventSink.hpp" #include "ardour/debug.h" +#include "ardour/file_source.h" +#include "ardour/midi_channel_filter.h" #include "ardour/midi_model.h" -#include "ardour/midi_state_tracker.h" #include "ardour/midi_source.h" -#include "ardour/file_source.h" +#include "ardour/midi_state_tracker.h" #include "ardour/session.h" #include "ardour/session_directory.h" #include "ardour/source_factory.h" @@ -190,6 +191,7 @@ MidiSource::midi_read (const Lock& lm, framepos_t start, framecnt_t cnt, MidiStateTracker* tracker, + MidiChannelFilter* filter, const std::set<Evoral::Parameter>& filtered) const { BeatsFramesConverter converter(_session.tempo_map(), source_start); @@ -218,6 +220,13 @@ MidiSource::midi_read (const Lock& lm, for (; i != _model->end(); ++i) { const framecnt_t time_frames = converter.to(i->time()); if (time_frames < start + cnt) { + if (filter && filter->filter(i->buffer(), i->size())) { + DEBUG_TRACE (DEBUG::MidiSourceIO, + string_compose ("%1: filter event @ %2 type %3 size %4\n", + _name, time_frames + source_start, i->event_type(), i->size())); + continue; + } + // Offset by source start to convert event time to session time dst.write (time_frames + source_start, i->event_type(), i->size(), i->buffer()); @@ -237,7 +246,7 @@ MidiSource::midi_read (const Lock& lm, } return cnt; } else { - return read_unlocked (lm, dst, source_start, start, cnt, tracker); + return read_unlocked (lm, dst, source_start, start, cnt, tracker, filter); } } diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index b8f53a87d0..3f15464481 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -29,7 +29,6 @@ #define isnan_local std::isnan #endif -#include "pbd/ffs.h" #include "pbd/enumwriter.h" #include "pbd/convert.h" #include "evoral/midi_util.h" @@ -72,8 +71,6 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo , _note_mode(Sustained) , _step_editing (false) , _input_active (true) - , _playback_channel_mask(0x0000ffff) - , _capture_channel_mask(0x0000ffff) { } @@ -387,7 +384,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame fill_buffers_with_input (bufs, _input, nframes); /* filter captured data before meter sees it */ - filter_channels (bufs, get_capture_channel_mode(), get_capture_channel_mask()); + _capture_filter.filter (bufs); if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) { _meter->run (bufs, start_frame, end_frame, nframes, true); @@ -402,9 +399,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame return dret; } - /* filter playback data before we do anything else */ - - filter_channels (bufs, get_playback_channel_mode(), get_playback_channel_mask ()); + /* note diskstream uses our filter to filter/map playback channels appropriately. */ if (monitoring_state() == MonitoringInput) { @@ -549,43 +544,6 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes) } } -void -MidiTrack::filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask) -{ - if (mode == AllChannels) { - return; - } - - MidiBuffer& buf (bufs.get_midi (0)); - - for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) { - - Evoral::MIDIEvent<framepos_t> ev(*e, false); - - if (ev.is_channel_event()) { - switch (mode) { - case FilterChannels: - if (0 == ((1<<ev.channel()) & mask)) { - e = buf.erase (e); - } else { - ++e; - } - break; - case ForceChannel: - ev.set_channel (PBD::ffs (mask) - 1); - ++e; - break; - case AllChannels: - /* handled by the opening if() */ - ++e; - break; - } - } else { - ++e; - } - } -} - void MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes) { @@ -815,52 +773,34 @@ MidiTrack::write_source (uint32_t) } void -MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask) +MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask) { - ChannelMode old = get_playback_channel_mode (); - uint16_t old_mask = get_playback_channel_mask (); - - if (old != mode || mask != old_mask) { - _set_playback_channel_mode (mode, mask); - PlaybackChannelModeChanged (); - _session.set_dirty (); + if (_playback_filter.set_channel_mode(mode, mask)) { + _session.set_dirty(); } } void -MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask) +MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask) { - ChannelMode old = get_capture_channel_mode (); - uint16_t old_mask = get_capture_channel_mask (); - - if (old != mode || mask != old_mask) { - _set_capture_channel_mode (mode, mask); - CaptureChannelModeChanged (); - _session.set_dirty (); + if (_capture_filter.set_channel_mode(mode, mask)) { + _session.set_dirty(); } } void MidiTrack::set_playback_channel_mask (uint16_t mask) { - uint16_t old = get_playback_channel_mask(); - - if (old != mask) { - _set_playback_channel_mask (mask); - PlaybackChannelMaskChanged (); - _session.set_dirty (); + if (_playback_filter.set_channel_mask(mask)) { + _session.set_dirty(); } } void MidiTrack::set_capture_channel_mask (uint16_t mask) { - uint16_t old = get_capture_channel_mask(); - - if (old != mask) { - _set_capture_channel_mask (mask); - CaptureChannelMaskChanged (); - _session.set_dirty (); + if (_capture_filter.set_channel_mask(mask)) { + _session.set_dirty(); } } @@ -949,7 +889,7 @@ MidiTrack::act_on_mute () if (muted() || _mute_master->muted_by_others_at(MuteMaster::AllPoints)) { /* only send messages for channels we are using */ - uint16_t mask = get_playback_channel_mask(); + uint16_t mask = _playback_filter.get_channel_mask(); for (uint8_t channel = 0; channel <= 0xF; channel++) { diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 7f5e8059c9..d5c89b5ee9 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -37,13 +37,14 @@ #include "evoral/Control.hpp" #include "evoral/SMF.hpp" +#include "ardour/debug.h" +#include "ardour/midi_channel_filter.h" #include "ardour/midi_model.h" #include "ardour/midi_ring_buffer.h" #include "ardour/midi_state_tracker.h" #include "ardour/parameter_types.h" #include "ardour/session.h" #include "ardour/smf_source.h" -#include "ardour/debug.h" #include "i18n.h" @@ -208,7 +209,8 @@ SMFSource::read_unlocked (const Lock& lock, framepos_t const source_start, framepos_t start, framecnt_t duration, - MidiStateTracker* tracker) const + MidiStateTracker* tracker, + MidiChannelFilter* filter) const { int ret = 0; uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn @@ -281,9 +283,11 @@ SMFSource::read_unlocked (const Lock& lock, const framepos_t ev_frame_time = converter.to(Evoral::Beats::ticks_at_rate(time, ppqn())) + source_start; if (ev_frame_time < start + duration) { - destination.write (ev_frame_time, ev_type, ev_size, ev_buffer); - if (tracker) { - tracker->track(ev_buffer); + if (!filter || !filter->filter(ev_buffer, ev_size)) { + destination.write (ev_frame_time, ev_type, ev_size, ev_buffer); + if (tracker) { + tracker->track(ev_buffer); + } } } else { break; diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 82aa2085f8..41d0edc3dd 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -109,6 +109,7 @@ libardour_sources = [ 'meter.cc', 'midi_automation_list_binder.cc', 'midi_buffer.cc', + 'midi_channel_filter.cc', 'midi_clock_slave.cc', 'midi_diskstream.cc', 'midi_model.cc', |