summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/midi_channel_selector.cc9
-rw-r--r--gtk2_ardour/midi_region_view.cc2
-rw-r--r--gtk2_ardour/midi_time_axis.cc28
-rw-r--r--libs/ardour/ardour/midi_channel_filter.h97
-rw-r--r--libs/ardour/ardour/midi_playlist.h4
-rw-r--r--libs/ardour/ardour/midi_playlist_source.h3
-rw-r--r--libs/ardour/ardour/midi_region.h13
-rw-r--r--libs/ardour/ardour/midi_source.h5
-rw-r--r--libs/ardour/ardour/midi_track.h67
-rw-r--r--libs/ardour/ardour/smf_source.h3
-rw-r--r--libs/ardour/midi_channel_filter.cc143
-rw-r--r--libs/ardour/midi_diskstream.cc47
-rw-r--r--libs/ardour/midi_playlist.cc8
-rw-r--r--libs/ardour/midi_playlist_source.cc3
-rw-r--r--libs/ardour/midi_region.cc14
-rw-r--r--libs/ardour/midi_source.cc15
-rw-r--r--libs/ardour/midi_track.cc86
-rw-r--r--libs/ardour/smf_source.cc14
-rw-r--r--libs/ardour/wscript1
19 files changed, 359 insertions, 203 deletions
diff --git a/gtk2_ardour/midi_channel_selector.cc b/gtk2_ardour/midi_channel_selector.cc
index 4884d72328..1895b5c52f 100644
--- a/gtk2_ardour/midi_channel_selector.cc
+++ b/gtk2_ardour/midi_channel_selector.cc
@@ -27,6 +27,7 @@
#include <gtkmm/table.h>
#include "pbd/compose.h"
+#include "pbd/ffs.h"
#include "gtkmm2ext/gtk_ui.h"
#include "gtkmm2ext/gui_thread.h"
@@ -343,10 +344,10 @@ MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr<MidiTrac
playback_mask_changed ();
capture_mask_changed ();
- track->PlaybackChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context());
- track->PlaybackChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mode_changed, this), gui_context());
- track->CaptureChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mask_changed, this), gui_context());
- track->CaptureChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
+ track->playback_filter().ChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context());
+ track->playback_filter().ChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mode_changed, this), gui_context());
+ track->capture_filter().ChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mask_changed, this), gui_context());
+ track->capture_filter().ChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
}
MidiChannelSelectorWindow::~MidiChannelSelectorWindow()
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 7bed675ac3..eed9017d0d 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -299,7 +299,7 @@ MidiRegionView::init (bool wfd)
group->raise_to_top();
- midi_view()->midi_track()->PlaybackChannelModeChanged.connect (_channel_mode_changed_connection, invalidator (*this),
+ midi_view()->midi_track()->playback_filter().ChannelModeChanged.connect (_channel_mode_changed_connection, invalidator (*this),
boost::bind (&MidiRegionView::midi_channel_mode_changed, this),
gui_context ());
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index bbf0473ded..be475216c1 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -243,18 +243,22 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
_view->RegionViewAdded.connect (
sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
- midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
- boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
- gui_context());
- midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
- boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
- gui_context());
- midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
- boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
- gui_context());
- midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
- boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
- gui_context());
+ midi_track()->playback_filter().ChannelModeChanged.connect (
+ *this, invalidator (*this),
+ boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
+ gui_context());
+ midi_track()->playback_filter().ChannelMaskChanged.connect (
+ *this, invalidator (*this),
+ boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
+ gui_context());
+ midi_track()->capture_filter().ChannelModeChanged.connect (
+ *this, invalidator (*this),
+ boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
+ gui_context());
+ midi_track()->capture_filter().ChannelMaskChanged.connect (
+ *this, invalidator (*this),
+ boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
+ gui_context());
playback_channel_mode_changed ();
capture_channel_mode_changed ();
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',