change MidiPlaylist::dump() into ::render(); change type of initial argument
[ardour.git] / libs / ardour / midi_channel_filter.cc
1 /*
2  * Copyright (C) 2015-2016 David Robillard <d@drobilla.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include "ardour/buffer_set.h"
20 #include "ardour/midi_buffer.h"
21 #include "ardour/midi_channel_filter.h"
22 #include "pbd/ffs.h"
23
24 namespace ARDOUR {
25
26 MidiChannelFilter::MidiChannelFilter()
27         : _mode_mask(0x0000FFFF)
28 {}
29
30 void
31 MidiChannelFilter::filter(BufferSet& bufs)
32 {
33         ChannelMode mode;
34         uint16_t    mask;
35         get_mode_and_mask(&mode, &mask);
36
37         if (mode == AllChannels) {
38                 return;
39         }
40
41         MidiBuffer& buf = bufs.get_midi(0);
42
43         for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) {
44                 Evoral::Event<samplepos_t> ev(*e, false);
45
46                 if (ev.is_channel_event()) {
47                         switch (mode) {
48                         case FilterChannels:
49                                 if (0 == ((1 << ev.channel()) & mask)) {
50                                         e = buf.erase (e);
51                                 } else {
52                                         ++e;
53                                 }
54                                 break;
55                         case ForceChannel:
56                                 ev.set_channel(PBD::ffs(mask) - 1);
57                                 ++e;
58                                 break;
59                         case AllChannels:
60                                 /* handled by the opening if() */
61                                 ++e;
62                                 break;
63                         }
64                 } else {
65                         ++e;
66                 }
67         }
68 }
69
70 bool
71 MidiChannelFilter::filter(uint8_t* buf, uint32_t len)
72 {
73         ChannelMode mode;
74         uint16_t    mask;
75         get_mode_and_mask(&mode, &mask);
76
77         const uint8_t type             = buf[0] & 0xF0;
78         const bool    is_channel_event = (0x80 <= type) && (type <= 0xE0);
79         if (!is_channel_event) {
80                 return false;
81         }
82
83         const uint8_t channel = buf[0] & 0x0F;
84         switch (mode) {
85         case AllChannels:
86                 return false;
87         case FilterChannels:
88                 return !((1 << channel) & mask);
89         case ForceChannel:
90                 buf[0] = (0xF0 & buf[0]) | (0x0F & (PBD::ffs(mask) - 1));
91                 return false;
92         }
93
94         return false;
95 }
96
97 /** If mode is ForceChannel, force mask to the lowest set channel or 1 if no
98  *  channels are set.
99  */
100 static inline uint16_t
101 force_mask(const ChannelMode mode, const uint16_t mask)
102 {
103         return ((mode == ForceChannel)
104                 ? (mask ? (1 << (PBD::ffs(mask) - 1)) : 1)
105                 : mask);
106 }
107
108 bool
109 MidiChannelFilter::set_channel_mode(ChannelMode mode, uint16_t mask)
110 {
111         ChannelMode old_mode;
112         uint16_t    old_mask;
113         get_mode_and_mask(&old_mode, &old_mask);
114
115         if (old_mode != mode || old_mask != mask) {
116                 mask = force_mask(mode, mask);
117                 g_atomic_int_set(&_mode_mask, (uint32_t(mode) << 16) | uint32_t(mask));
118                 ChannelModeChanged();
119                 return true;
120         }
121
122         return false;
123 }
124
125 bool
126 MidiChannelFilter::set_channel_mask(uint16_t mask)
127 {
128         ChannelMode mode;
129         uint16_t    old_mask;
130         get_mode_and_mask(&mode, &old_mask);
131
132         if (old_mask != mask) {
133                 mask = force_mask(mode, mask);
134                 g_atomic_int_set(&_mode_mask, (uint32_t(mode) << 16) | uint32_t(mask));
135                 ChannelMaskChanged();
136                 return true;
137         }
138
139         return false;
140 }
141
142 } /* namespace ARDOUR */