remove file manager LRU cache from code.
[ardour.git] / libs / evoral / evoral / PatchChange.hpp
1 /*
2   Copyright (C) 2010 Paul Davis
3   Author: Carl Hetherington <cth@carlh.net>
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #ifndef EVORAL_PATCH_CHANGE_HPP
21 #define EVORAL_PATCH_CHANGE_HPP
22
23 #include "evoral/visibility.h"
24 #include "evoral/Event.hpp"
25 #include "evoral/MIDIEvent.hpp"
26
27 namespace Evoral {
28
29 /** Event representing a `patch change', composed of a LSB and MSB
30  *  bank select and then a program change.
31  */
32 template<typename Time>
33 class /*LIBEVORAL_API*/ PatchChange
34 {
35 public:
36         /** @param t Time.
37          *  @param c Channel.
38          *  @param p Program change number (counted from 0).
39          *  @param b Bank number (counted from 0, 14-bit).
40          */
41         PatchChange (Time t, uint8_t c, uint8_t p, int b)
42                 : _bank_change_msb (0, t, 3, 0, true)
43                 , _bank_change_lsb (0, t, 3, 0, true)
44                 , _program_change (0, t, 2, 0, true)
45         {
46                 _bank_change_msb.buffer()[0] = MIDI_CMD_CONTROL | c;
47                 _bank_change_msb.buffer()[1] = MIDI_CTL_MSB_BANK;
48                 _bank_change_msb.buffer()[2] = (b >> 7) & 0x7f;
49
50                 _bank_change_lsb.buffer()[0] = MIDI_CMD_CONTROL | c;
51                 _bank_change_lsb.buffer()[1] = MIDI_CTL_LSB_BANK;
52                 _bank_change_lsb.buffer()[2] = b & 0x7f;
53
54                 _program_change.buffer()[0] = MIDI_CMD_PGM_CHANGE | c;
55                 _program_change.buffer()[1] = p;
56         }
57
58         PatchChange (const PatchChange & other)
59                 : _bank_change_msb (other._bank_change_msb, true)
60                 , _bank_change_lsb (other._bank_change_lsb, true)
61                 , _program_change (other._program_change, true)
62         {
63                 set_id (other.id ());
64         }
65
66         event_id_t id () const {
67                 return _program_change.id ();
68         }
69
70         void set_id (event_id_t id) {
71                 _bank_change_msb.set_id (id);
72                 _bank_change_lsb.set_id (id);
73                 _program_change.set_id (id);
74         }
75
76         Time time () const {
77                 return _program_change.time ();
78         }
79
80         void set_time (Time t) {
81                 _bank_change_msb.set_time (t);
82                 _bank_change_lsb.set_time (t);
83                 _program_change.set_time (t);
84         }
85
86         void set_channel (uint8_t c) {
87                 _bank_change_msb.buffer()[0] &= 0xf0;
88                 _bank_change_msb.buffer()[0] |= c;
89                 _bank_change_lsb.buffer()[0] &= 0xf0;
90                 _bank_change_lsb.buffer()[0] |= c;
91                 _program_change.buffer()[0] &= 0xf0;
92                 _program_change.buffer()[0] |= c;
93         }
94
95         uint8_t program () const {
96                 return _program_change.buffer()[1];
97         }
98
99         void set_program (uint8_t p) {
100                 _program_change.buffer()[1] = p;
101         }
102
103         int bank () const {
104                 return (bank_msb() << 7) | bank_lsb();
105         }
106
107         void set_bank (int b) {
108                 _bank_change_msb.buffer()[2] = (b >> 7) & 0x7f;
109                 _bank_change_lsb.buffer()[2] = b & 0x7f;
110         }
111
112         uint8_t bank_msb () const {
113                 return _bank_change_msb.buffer()[2];
114         }
115
116         uint8_t bank_lsb () const {
117                 return _bank_change_lsb.buffer()[2];
118         }
119
120         uint8_t channel () const { return _program_change.buffer()[0] & 0xf; }
121
122         inline bool operator< (const PatchChange<Time>& o) const {
123                 if (time() != o.time()) {
124                         return time() < o.time();
125                 }
126
127                 if (bank() != o.bank()) {
128                         return bank() < o.bank();
129                 }
130
131                 return (program() < o.program());
132         }
133
134         inline bool operator== (const PatchChange<Time>& o) const {
135                 return (time() == o.time() && program() == o.program() && bank() == o.bank());
136         }
137
138         /** The PatchChange is made up of messages() MIDI messages; this method returns them by index.
139          *  @param i index of message to return.
140          */
141         MIDIEvent<Time> const & message (int i) const {
142                 switch (i) {
143                 case 0:
144                         return _bank_change_msb;
145                 case 1:
146                         return _bank_change_lsb;
147                 case 2:
148                         return _program_change;
149                 default:
150                         abort(); /*NOTREACHED*/
151                         return _program_change;
152                 }
153         }
154
155         /** @return Number of MIDI messages that make up this change */
156         int messages () const {
157                 return 3;
158         }
159
160 private:
161         MIDIEvent<Time> _bank_change_msb;
162         MIDIEvent<Time> _bank_change_lsb;
163         MIDIEvent<Time> _program_change;
164 };
165
166 }
167
168 template<typename Time>
169 /*LIBEVORAL_API*/ std::ostream& operator<< (std::ostream& o, const Evoral::PatchChange<Time>& p) {
170         o << "Patch Change " << p.id() << " @ " << p.time() << " bank " << (int) p.bank() << " program " << (int) p.program();
171         return o;
172 }
173
174 #endif