mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
Fix mute of MIDI tracks with channel forcing.
This moves MIDI channel filtering into a reusable class and moves filtering to the source, rather than modifying the buffer afterwards. This is necessary so that the playlist trackers reflect the emitted notes (and thus are able to stop them in situations like mute). As a perk, this is also faster because events are just dropped on read, rather than pushed into a buffer then later removed (which is very slow). Really hammering on mute or solo still seems to produce stuck notes occasionally (perhaps related to multiple-on warnings). I am not yet sure why, but occasional beats always.
This commit is contained in:
parent
88146f0e3a
commit
546cd974ec
19 changed files with 360 additions and 204 deletions
|
|
@ -27,6 +27,7 @@
|
||||||
#include <gtkmm/table.h>
|
#include <gtkmm/table.h>
|
||||||
|
|
||||||
#include "pbd/compose.h"
|
#include "pbd/compose.h"
|
||||||
|
#include "pbd/ffs.h"
|
||||||
|
|
||||||
#include "gtkmm2ext/gtk_ui.h"
|
#include "gtkmm2ext/gtk_ui.h"
|
||||||
#include "gtkmm2ext/gui_thread.h"
|
#include "gtkmm2ext/gui_thread.h"
|
||||||
|
|
@ -343,10 +344,10 @@ MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr<MidiTrac
|
||||||
playback_mask_changed ();
|
playback_mask_changed ();
|
||||||
capture_mask_changed ();
|
capture_mask_changed ();
|
||||||
|
|
||||||
track->PlaybackChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context());
|
track->playback_filter().ChannelMaskChanged.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->playback_filter().ChannelModeChanged.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->capture_filter().ChannelMaskChanged.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->capture_filter().ChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiChannelSelectorWindow::~MidiChannelSelectorWindow()
|
MidiChannelSelectorWindow::~MidiChannelSelectorWindow()
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ MidiRegionView::init (bool wfd)
|
||||||
|
|
||||||
group->raise_to_top();
|
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),
|
boost::bind (&MidiRegionView::midi_channel_mode_changed, this),
|
||||||
gui_context ());
|
gui_context ());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -243,18 +243,22 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
||||||
_view->RegionViewAdded.connect (
|
_view->RegionViewAdded.connect (
|
||||||
sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
|
sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
|
||||||
|
|
||||||
midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
|
midi_track()->playback_filter().ChannelModeChanged.connect (
|
||||||
boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
|
*this, invalidator (*this),
|
||||||
gui_context());
|
boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
|
||||||
midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
|
gui_context());
|
||||||
boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
|
midi_track()->playback_filter().ChannelMaskChanged.connect (
|
||||||
gui_context());
|
*this, invalidator (*this),
|
||||||
midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
|
boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
|
||||||
boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
|
gui_context());
|
||||||
gui_context());
|
midi_track()->capture_filter().ChannelModeChanged.connect (
|
||||||
midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
|
*this, invalidator (*this),
|
||||||
boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
|
boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
|
||||||
gui_context());
|
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 ();
|
playback_channel_mode_changed ();
|
||||||
capture_channel_mode_changed ();
|
capture_channel_mode_changed ();
|
||||||
|
|
|
||||||
97
libs/ardour/ardour/midi_channel_filter.h
Normal file
97
libs/ardour/ardour/midi_channel_filter.h
Normal file
|
|
@ -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__ */
|
||||||
|
|
@ -42,6 +42,7 @@ namespace ARDOUR
|
||||||
{
|
{
|
||||||
|
|
||||||
class BeatsFramesConverter;
|
class BeatsFramesConverter;
|
||||||
|
class MidiChannelFilter;
|
||||||
class MidiRegion;
|
class MidiRegion;
|
||||||
class Session;
|
class Session;
|
||||||
class Source;
|
class Source;
|
||||||
|
|
@ -77,7 +78,8 @@ public:
|
||||||
framecnt_t read (Evoral::EventSink<framepos_t>& buf,
|
framecnt_t read (Evoral::EventSink<framepos_t>& buf,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
uint32_t chan_n = 0);
|
uint32_t chan_n = 0,
|
||||||
|
MidiChannelFilter* filter = NULL);
|
||||||
|
|
||||||
int set_state (const XMLNode&, int version);
|
int set_state (const XMLNode&, int version);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,8 @@ protected:
|
||||||
framepos_t position,
|
framepos_t position,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker) const;
|
MidiStateTracker* tracker,
|
||||||
|
MidiChannelFilter* filter) const;
|
||||||
|
|
||||||
framecnt_t write_unlocked (const Lock& lock,
|
framecnt_t write_unlocked (const Lock& lock,
|
||||||
MidiRingBuffer<framepos_t>& dst,
|
MidiRingBuffer<framepos_t>& dst,
|
||||||
|
|
|
||||||
|
|
@ -43,13 +43,14 @@ template<typename Time> class EventSink;
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class Route;
|
class MidiChannelFilter;
|
||||||
class Playlist;
|
|
||||||
class Session;
|
|
||||||
class MidiFilter;
|
class MidiFilter;
|
||||||
class MidiModel;
|
class MidiModel;
|
||||||
class MidiSource;
|
class MidiSource;
|
||||||
class MidiStateTracker;
|
class MidiStateTracker;
|
||||||
|
class Playlist;
|
||||||
|
class Route;
|
||||||
|
class Session;
|
||||||
|
|
||||||
template<typename T> class MidiRingBuffer;
|
template<typename T> class MidiRingBuffer;
|
||||||
|
|
||||||
|
|
@ -74,7 +75,8 @@ class LIBARDOUR_API MidiRegion : public Region
|
||||||
framecnt_t dur,
|
framecnt_t dur,
|
||||||
uint32_t chan_n = 0,
|
uint32_t chan_n = 0,
|
||||||
NoteMode mode = Sustained,
|
NoteMode mode = Sustained,
|
||||||
MidiStateTracker* tracker = 0) const;
|
MidiStateTracker* tracker = 0,
|
||||||
|
MidiChannelFilter* filter = 0) const;
|
||||||
|
|
||||||
framecnt_t master_read_at (MidiRingBuffer<framepos_t>& dst,
|
framecnt_t master_read_at (MidiRingBuffer<framepos_t>& dst,
|
||||||
framepos_t position,
|
framepos_t position,
|
||||||
|
|
@ -121,7 +123,8 @@ class LIBARDOUR_API MidiRegion : public Region
|
||||||
framecnt_t dur,
|
framecnt_t dur,
|
||||||
uint32_t chan_n = 0,
|
uint32_t chan_n = 0,
|
||||||
NoteMode mode = Sustained,
|
NoteMode mode = Sustained,
|
||||||
MidiStateTracker* tracker = 0) const;
|
MidiStateTracker* tracker = 0,
|
||||||
|
MidiChannelFilter* filter = 0) const;
|
||||||
|
|
||||||
void register_properties ();
|
void register_properties ();
|
||||||
void post_set (const PBD::PropertyChange&);
|
void post_set (const PBD::PropertyChange&);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
class MidiChannelFilter;
|
||||||
class MidiStateTracker;
|
class MidiStateTracker;
|
||||||
class MidiModel;
|
class MidiModel;
|
||||||
|
|
||||||
|
|
@ -77,6 +78,7 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker,
|
MidiStateTracker* tracker,
|
||||||
|
MidiChannelFilter* filter,
|
||||||
const std::set<Evoral::Parameter>& filtered) const;
|
const std::set<Evoral::Parameter>& filtered) const;
|
||||||
|
|
||||||
/** Write data from a MidiRingBuffer to this source.
|
/** 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 position,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker) const = 0;
|
MidiStateTracker* tracker,
|
||||||
|
MidiChannelFilter* filter) const = 0;
|
||||||
|
|
||||||
/** Write data to this source from a MidiRingBuffer.
|
/** Write data to this source from a MidiRingBuffer.
|
||||||
* @param source Buffer to read from.
|
* @param source Buffer to read from.
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,9 @@
|
||||||
#ifndef __ardour_midi_track_h__
|
#ifndef __ardour_midi_track_h__
|
||||||
#define __ardour_midi_track_h__
|
#define __ardour_midi_track_h__
|
||||||
|
|
||||||
#include "pbd/ffs.h"
|
#include "ardour/midi_channel_filter.h"
|
||||||
|
|
||||||
#include "ardour/track.h"
|
|
||||||
#include "ardour/midi_ring_buffer.h"
|
#include "ardour/midi_ring_buffer.h"
|
||||||
|
#include "ardour/track.h"
|
||||||
|
|
||||||
namespace ARDOUR
|
namespace ARDOUR
|
||||||
{
|
{
|
||||||
|
|
@ -109,38 +108,22 @@ public:
|
||||||
|
|
||||||
boost::shared_ptr<SMFSource> write_source (uint32_t n = 0);
|
boost::shared_ptr<SMFSource> write_source (uint32_t n = 0);
|
||||||
|
|
||||||
/** Channel filtering mode.
|
/* Configure capture/playback channels (see MidiChannelFilter). */
|
||||||
* @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.
|
|
||||||
*/
|
|
||||||
void set_capture_channel_mode (ChannelMode mode, uint16_t mask);
|
void set_capture_channel_mode (ChannelMode mode, uint16_t mask);
|
||||||
void set_playback_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_playback_channel_mask (uint16_t mask);
|
||||||
void set_capture_channel_mask (uint16_t mask);
|
void set_capture_channel_mask (uint16_t mask);
|
||||||
|
|
||||||
ChannelMode get_playback_channel_mode() const {
|
ChannelMode get_playback_channel_mode() const { return _playback_filter.get_channel_mode(); }
|
||||||
return static_cast<ChannelMode>((g_atomic_int_get(&_playback_channel_mask) & 0xffff0000) >> 16);
|
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_playback_channel_mask() const {
|
uint16_t get_capture_channel_mask() const { return _capture_filter.get_channel_mask(); }
|
||||||
return g_atomic_int_get(&_playback_channel_mask) & 0x0000ffff;
|
|
||||||
}
|
MidiChannelFilter& playback_filter() { return _playback_filter; }
|
||||||
ChannelMode get_capture_channel_mode() const {
|
MidiChannelFilter& capture_filter() { return _capture_filter; }
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<MidiPlaylist> midi_playlist ();
|
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;
|
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
|
||||||
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
|
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
|
||||||
|
|
||||||
|
|
@ -162,8 +145,8 @@ private:
|
||||||
NoteMode _note_mode;
|
NoteMode _note_mode;
|
||||||
bool _step_editing;
|
bool _step_editing;
|
||||||
bool _input_active;
|
bool _input_active;
|
||||||
uint32_t _playback_channel_mask; // 16 bits mode, 16 bits mask
|
MidiChannelFilter _playback_filter;
|
||||||
uint32_t _capture_channel_mask; // 16 bits mode, 16 bits mask
|
MidiChannelFilter _capture_filter;
|
||||||
|
|
||||||
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
|
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
|
||||||
|
|
||||||
|
|
@ -186,32 +169,6 @@ private:
|
||||||
|
|
||||||
/** Update automation controls to reflect any changes in buffers. */
|
/** Update automation controls to reflect any changes in buffers. */
|
||||||
void update_controls (const BufferSet& bufs);
|
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*/
|
} /* namespace ARDOUR*/
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,8 @@ public:
|
||||||
framepos_t position,
|
framepos_t position,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker) const;
|
MidiStateTracker* tracker,
|
||||||
|
MidiChannelFilter* filter) const;
|
||||||
|
|
||||||
framecnt_t write_unlocked (const Lock& lock,
|
framecnt_t write_unlocked (const Lock& lock,
|
||||||
MidiRingBuffer<framepos_t>& src,
|
MidiRingBuffer<framepos_t>& src,
|
||||||
|
|
|
||||||
143
libs/ardour/midi_channel_filter.cc
Normal file
143
libs/ardour/midi_channel_filter.cc
Normal file
|
|
@ -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 */
|
||||||
|
|
@ -403,17 +403,10 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nominally_recording || rec_nframes) {
|
if (nominally_recording || rec_nframes) {
|
||||||
|
// Pump entire port buffer into the ring buffer (TODO: split cycles?)
|
||||||
// Pump entire port buffer into the ring buffer (FIXME: split cycles?)
|
MidiBuffer& buf = sp->get_midi_buffer(nframes);
|
||||||
MidiBuffer& buf = sp->get_midi_buffer(nframes);
|
MidiTrack* mt = dynamic_cast<MidiTrack*>(_track);
|
||||||
ChannelMode mode = AllChannels;
|
MidiChannelFilter* filter = mt ? &mt->capture_filter() : NULL;
|
||||||
uint32_t mask = 0xffff;
|
|
||||||
|
|
||||||
MidiTrack * mt = dynamic_cast<MidiTrack*> (_track);
|
|
||||||
if (mt) {
|
|
||||||
mode = mt->get_capture_channel_mode ();
|
|
||||||
mask = mt->get_capture_channel_mask ();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
|
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
|
||||||
Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
|
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 framecnt_t loop_offset = _num_captured_loops * loop_length;
|
||||||
const framepos_t event_time = transport_frame + loop_offset - _accumulated_capture_offset + ev.time();
|
const framepos_t event_time = transport_frame + loop_offset - _accumulated_capture_offset + ev.time();
|
||||||
if (event_time < 0 || event_time < first_recordable_frame) {
|
if (event_time < 0 || event_time < first_recordable_frame) {
|
||||||
|
/* Event out of range, skip */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (mode) {
|
|
||||||
case AllChannels:
|
if (!filter || !filter->filter(ev.buffer(), ev.size())) {
|
||||||
_capture_buf->write(event_time,
|
_capture_buf->write(event_time, ev.type(), ev.size(), ev.buffer());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_atomic_int_add(const_cast<gint*>(&_frames_pending_write), nframes);
|
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;
|
framecnt_t loop_length = 0;
|
||||||
Location* loc = 0;
|
Location* loc = 0;
|
||||||
|
|
||||||
|
MidiTrack* mt = dynamic_cast<MidiTrack*>(_track);
|
||||||
|
MidiChannelFilter* filter = mt ? &mt->playback_filter() : NULL;
|
||||||
|
|
||||||
if (!reversed) {
|
if (!reversed) {
|
||||||
|
|
||||||
loc = loop_location;
|
loc = loop_location;
|
||||||
|
|
@ -772,7 +749,7 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
|
||||||
|
|
||||||
this_read = min(dur,this_read);
|
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(
|
error << string_compose(
|
||||||
_("MidiDiskstream %1: cannot read %2 from playlist at frame %3"),
|
_("MidiDiskstream %1: cannot read %2 from playlist at frame %3"),
|
||||||
id(), this_read, start) << endmsg;
|
id(), this_read, start) << endmsg;
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,11 @@ struct EventsSortByTimeAndType {
|
||||||
};
|
};
|
||||||
|
|
||||||
framecnt_t
|
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;
|
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. */
|
/* 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,
|
DEBUG_TRACE (DEBUG::MidiPlaylistIO,
|
||||||
string_compose ("\tPost-read: %1 active notes\n", tracker->tracker.on()));
|
string_compose ("\tPost-read: %1 active notes\n", tracker->tracker.on()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,8 @@ MidiPlaylistSource::read_unlocked (const Lock& lock,
|
||||||
Evoral::EventSink<framepos_t>& dst,
|
Evoral::EventSink<framepos_t>& dst,
|
||||||
framepos_t /*position*/,
|
framepos_t /*position*/,
|
||||||
framepos_t start, framecnt_t cnt,
|
framepos_t start, framecnt_t cnt,
|
||||||
MidiStateTracker*) const
|
MidiStateTracker*,
|
||||||
|
MidiChannelFilter*) const
|
||||||
{
|
{
|
||||||
boost::shared_ptr<MidiPlaylist> mp = boost::dynamic_pointer_cast<MidiPlaylist> (_playlist);
|
boost::shared_ptr<MidiPlaylist> mp = boost::dynamic_pointer_cast<MidiPlaylist> (_playlist);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -230,9 +230,15 @@ MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
|
||||||
}
|
}
|
||||||
|
|
||||||
framecnt_t
|
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
|
framecnt_t
|
||||||
|
|
@ -248,7 +254,8 @@ MidiRegion::_read_at (const SourceList& /*srcs*/,
|
||||||
framecnt_t dur,
|
framecnt_t dur,
|
||||||
uint32_t chan_n,
|
uint32_t chan_n,
|
||||||
NoteMode mode,
|
NoteMode mode,
|
||||||
MidiStateTracker* tracker) const
|
MidiStateTracker* tracker,
|
||||||
|
MidiChannelFilter* filter) const
|
||||||
{
|
{
|
||||||
frameoffset_t internal_offset = 0;
|
frameoffset_t internal_offset = 0;
|
||||||
framecnt_t to_read = 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
|
_start + internal_offset, // where to start reading in the source
|
||||||
to_read, // read duration in frames
|
to_read, // read duration in frames
|
||||||
tracker,
|
tracker,
|
||||||
|
filter,
|
||||||
_filtered_parameters
|
_filtered_parameters
|
||||||
) != to_read) {
|
) != to_read) {
|
||||||
return 0; /* "read nothing" */
|
return 0; /* "read nothing" */
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,11 @@
|
||||||
#include "evoral/EventSink.hpp"
|
#include "evoral/EventSink.hpp"
|
||||||
|
|
||||||
#include "ardour/debug.h"
|
#include "ardour/debug.h"
|
||||||
#include "ardour/midi_model.h"
|
|
||||||
#include "ardour/midi_state_tracker.h"
|
|
||||||
#include "ardour/midi_source.h"
|
|
||||||
#include "ardour/file_source.h"
|
#include "ardour/file_source.h"
|
||||||
|
#include "ardour/midi_channel_filter.h"
|
||||||
|
#include "ardour/midi_model.h"
|
||||||
|
#include "ardour/midi_source.h"
|
||||||
|
#include "ardour/midi_state_tracker.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
#include "ardour/session_directory.h"
|
#include "ardour/session_directory.h"
|
||||||
#include "ardour/source_factory.h"
|
#include "ardour/source_factory.h"
|
||||||
|
|
@ -190,6 +191,7 @@ MidiSource::midi_read (const Lock& lm,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker,
|
MidiStateTracker* tracker,
|
||||||
|
MidiChannelFilter* filter,
|
||||||
const std::set<Evoral::Parameter>& filtered) const
|
const std::set<Evoral::Parameter>& filtered) const
|
||||||
{
|
{
|
||||||
BeatsFramesConverter converter(_session.tempo_map(), source_start);
|
BeatsFramesConverter converter(_session.tempo_map(), source_start);
|
||||||
|
|
@ -218,6 +220,13 @@ MidiSource::midi_read (const Lock& lm,
|
||||||
for (; i != _model->end(); ++i) {
|
for (; i != _model->end(); ++i) {
|
||||||
const framecnt_t time_frames = converter.to(i->time());
|
const framecnt_t time_frames = converter.to(i->time());
|
||||||
if (time_frames < start + cnt) {
|
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
|
// Offset by source start to convert event time to session time
|
||||||
dst.write (time_frames + source_start, i->event_type(), i->size(), i->buffer());
|
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;
|
return cnt;
|
||||||
} else {
|
} else {
|
||||||
return read_unlocked (lm, dst, source_start, start, cnt, tracker);
|
return read_unlocked (lm, dst, source_start, start, cnt, tracker, filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
#define isnan_local std::isnan
|
#define isnan_local std::isnan
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "pbd/ffs.h"
|
|
||||||
#include "pbd/enumwriter.h"
|
#include "pbd/enumwriter.h"
|
||||||
#include "pbd/convert.h"
|
#include "pbd/convert.h"
|
||||||
#include "evoral/midi_util.h"
|
#include "evoral/midi_util.h"
|
||||||
|
|
@ -72,8 +71,6 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
|
||||||
, _note_mode(Sustained)
|
, _note_mode(Sustained)
|
||||||
, _step_editing (false)
|
, _step_editing (false)
|
||||||
, _input_active (true)
|
, _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);
|
fill_buffers_with_input (bufs, _input, nframes);
|
||||||
|
|
||||||
/* filter captured data before meter sees it */
|
/* 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())) {
|
if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
|
||||||
_meter->run (bufs, start_frame, end_frame, nframes, true);
|
_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;
|
return dret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* filter playback data before we do anything else */
|
/* note diskstream uses our filter to filter/map playback channels appropriately. */
|
||||||
|
|
||||||
filter_channels (bufs, get_playback_channel_mode(), get_playback_channel_mask ());
|
|
||||||
|
|
||||||
if (monitoring_state() == MonitoringInput) {
|
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
|
void
|
||||||
MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes)
|
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
|
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 ();
|
if (_playback_filter.set_channel_mode(mode, mask)) {
|
||||||
uint16_t old_mask = get_playback_channel_mask ();
|
_session.set_dirty();
|
||||||
|
|
||||||
if (old != mode || mask != old_mask) {
|
|
||||||
_set_playback_channel_mode (mode, mask);
|
|
||||||
PlaybackChannelModeChanged ();
|
|
||||||
_session.set_dirty ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 ();
|
if (_capture_filter.set_channel_mode(mode, mask)) {
|
||||||
uint16_t old_mask = get_capture_channel_mask ();
|
_session.set_dirty();
|
||||||
|
|
||||||
if (old != mode || mask != old_mask) {
|
|
||||||
_set_capture_channel_mode (mode, mask);
|
|
||||||
CaptureChannelModeChanged ();
|
|
||||||
_session.set_dirty ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiTrack::set_playback_channel_mask (uint16_t mask)
|
MidiTrack::set_playback_channel_mask (uint16_t mask)
|
||||||
{
|
{
|
||||||
uint16_t old = get_playback_channel_mask();
|
if (_playback_filter.set_channel_mask(mask)) {
|
||||||
|
_session.set_dirty();
|
||||||
if (old != mask) {
|
|
||||||
_set_playback_channel_mask (mask);
|
|
||||||
PlaybackChannelMaskChanged ();
|
|
||||||
_session.set_dirty ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiTrack::set_capture_channel_mask (uint16_t mask)
|
MidiTrack::set_capture_channel_mask (uint16_t mask)
|
||||||
{
|
{
|
||||||
uint16_t old = get_capture_channel_mask();
|
if (_capture_filter.set_channel_mask(mask)) {
|
||||||
|
_session.set_dirty();
|
||||||
if (old != mask) {
|
|
||||||
_set_capture_channel_mask (mask);
|
|
||||||
CaptureChannelMaskChanged ();
|
|
||||||
_session.set_dirty ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -949,7 +889,7 @@ MidiTrack::act_on_mute ()
|
||||||
if (muted() || _mute_master->muted_by_others_at(MuteMaster::AllPoints)) {
|
if (muted() || _mute_master->muted_by_others_at(MuteMaster::AllPoints)) {
|
||||||
/* only send messages for channels we are using */
|
/* 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++) {
|
for (uint8_t channel = 0; channel <= 0xF; channel++) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,14 @@
|
||||||
#include "evoral/Control.hpp"
|
#include "evoral/Control.hpp"
|
||||||
#include "evoral/SMF.hpp"
|
#include "evoral/SMF.hpp"
|
||||||
|
|
||||||
|
#include "ardour/debug.h"
|
||||||
|
#include "ardour/midi_channel_filter.h"
|
||||||
#include "ardour/midi_model.h"
|
#include "ardour/midi_model.h"
|
||||||
#include "ardour/midi_ring_buffer.h"
|
#include "ardour/midi_ring_buffer.h"
|
||||||
#include "ardour/midi_state_tracker.h"
|
#include "ardour/midi_state_tracker.h"
|
||||||
#include "ardour/parameter_types.h"
|
#include "ardour/parameter_types.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
#include "ardour/smf_source.h"
|
#include "ardour/smf_source.h"
|
||||||
#include "ardour/debug.h"
|
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
@ -208,7 +209,8 @@ SMFSource::read_unlocked (const Lock& lock,
|
||||||
framepos_t const source_start,
|
framepos_t const source_start,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t duration,
|
framecnt_t duration,
|
||||||
MidiStateTracker* tracker) const
|
MidiStateTracker* tracker,
|
||||||
|
MidiChannelFilter* filter) const
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
|
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;
|
const framepos_t ev_frame_time = converter.to(Evoral::Beats::ticks_at_rate(time, ppqn())) + source_start;
|
||||||
|
|
||||||
if (ev_frame_time < start + duration) {
|
if (ev_frame_time < start + duration) {
|
||||||
destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
|
if (!filter || !filter->filter(ev_buffer, ev_size)) {
|
||||||
if (tracker) {
|
destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
|
||||||
tracker->track(ev_buffer);
|
if (tracker) {
|
||||||
|
tracker->track(ev_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ libardour_sources = [
|
||||||
'meter.cc',
|
'meter.cc',
|
||||||
'midi_automation_list_binder.cc',
|
'midi_automation_list_binder.cc',
|
||||||
'midi_buffer.cc',
|
'midi_buffer.cc',
|
||||||
|
'midi_channel_filter.cc',
|
||||||
'midi_clock_slave.cc',
|
'midi_clock_slave.cc',
|
||||||
'midi_diskstream.cc',
|
'midi_diskstream.cc',
|
||||||
'midi_model.cc',
|
'midi_model.cc',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue