144 lines
3.2 KiB
C++
144 lines
3.2 KiB
C++
/*
|
|
* Copyright (C) 2015-2016 David Robillard <d@drobilla.net>
|
|
*
|
|
* 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.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.store (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::Event<samplepos_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);
|
|
_mode_mask.store ((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);
|
|
_mode_mask.store ((uint32_t(mode) << 16) | uint32_t(mask));
|
|
ChannelMaskChanged();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
} /* namespace ARDOUR */
|