Implement MIDI and LV2 volume control in sampler plugin.
[composite:composite.git] / src / Tritium / src / DefaultMidiImplementation.cpp
1 /*
2  * Copyright(c) 2010 by Gabriel M. Beddingfield <gabriel@teuton.org>
3  *
4  * This file is part of Tritium
5  *
6  * Tritium is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Tritium is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY, without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include <Tritium/DefaultMidiImplementation.hpp>
23 #include <Tritium/SeqEvent.hpp>
24 #include <Tritium/Instrument.hpp>
25 #include <Tritium/InstrumentList.hpp>
26 #include <Tritium/Sampler.hpp>
27
28 #include <cassert>
29
30 namespace Tritium
31 {
32     DefaultMidiImplementation::DefaultMidiImplementation()
33         : _note_min(36),
34           _ignore_note_off(true),
35           _volume(0x3FFF)
36     {
37     }
38
39     DefaultMidiImplementation::~DefaultMidiImplementation()
40     {
41     }
42
43     bool DefaultMidiImplementation::handle_note_off(
44         SeqEvent& dest,
45         uint32_t size,
46         const uint8_t *midi
47         )
48     {
49         if(_ignore_note_off) return false;
50
51         assert(size == 3);
52         assert(0x80 == (midi[0] & 0xF0));
53
54         uint32_t note_no;
55         note_no = midi[1];
56         if(note_no < _note_min) {
57             return false;
58         } else {
59             note_no -= _note_min;
60         }
61
62         T<Sampler>::shared_ptr samp = _sampler;
63         if( !samp ) return false;
64         T<InstrumentList>::shared_ptr i_list = samp->get_instrument_list();
65         T<Instrument>::shared_ptr inst;
66         if( note_no < i_list->get_size() ) {
67             inst = i_list->get(note_no);
68         }
69
70         bool rv = false;
71         if(inst) {
72             dest.type = SeqEvent::NOTE_OFF;
73             dest.note.set_velocity(0.0f);
74             dest.note.set_instrument(inst);
75             rv = true;
76         }
77         return rv;
78     }
79
80     bool DefaultMidiImplementation::handle_note_on(
81         SeqEvent& dest,
82         uint32_t size,
83         const uint8_t *midi
84         )
85     {
86         assert(size == 3);
87         assert(0x90 == (midi[0] & 0xF0));
88
89         uint32_t note_no;
90         float velocity;
91
92         note_no = midi[1];
93         if(note_no < _note_min) {
94             return false;
95         } else {
96             note_no -= _note_min;
97         }
98
99         if( midi[2] == 0 ) {
100             return handle_note_off(dest, size, midi);
101         }
102         velocity = float(midi[2]) / 127.0f;
103
104         T<Sampler>::shared_ptr samp = _sampler;
105         if( !samp ) return false;
106         T<InstrumentList>::shared_ptr i_list = samp->get_instrument_list();
107         T<Instrument>::shared_ptr inst;
108         if( note_no < i_list->get_size() ) {
109             inst = i_list->get(note_no);
110         }
111
112         bool rv = false;
113         if(inst) {
114             dest.type = SeqEvent::NOTE_ON;
115             dest.note.set_velocity(velocity);
116             dest.note.set_instrument(inst);
117             dest.note.set_length(-1);
118             rv = true;
119         }
120         return rv;          
121     }
122
123     bool DefaultMidiImplementation::handle_control_change(
124         SeqEvent& dest,
125         uint32_t size,
126         const uint8_t *midi
127         )
128     {
129         assert(size == 3);
130         assert(0xB0 == (midi[0] & 0xF0));
131         const uint16_t coarse_mask = 0x3F80;
132         const uint16_t fine_mask = 0x7F;
133
134         bool rv = false;
135         const uint8_t& controller = midi[1];
136         const uint8_t& value = midi[2];
137
138         /******************************************************
139          * IF YOU HANDLE THE EVENT, BE SURE TO SET 'rv' TO TRUE
140          *******************************************************
141          */
142         switch(controller) {
143         case 7: // Volume (coarse)
144             /* XXX TODO: Consider using an exponential taper on this.
145              */
146             _volume = (_volume & fine_mask) | ((value << 7) & coarse_mask);
147             dest.type = SeqEvent::VOL_UPDATE;
148             dest.data = float(_volume)/16383.0f;
149             rv = true;
150             break;
151         case 8: // Balance (coarse)
152             break;
153         case 10: // Pan position (coarse)
154             break;
155         case 11: // Expression (coarse)
156             break;
157         case 39: // Volume (fine)
158             /* XXX TODO: Consider using an exponential taper on this.
159              */
160             _volume = (_volume & coarse_mask) | (value & fine_mask);
161             dest.type = SeqEvent::VOL_UPDATE;
162             dest.data = float(_volume)/16383.0f;
163             rv = true;
164             break;
165         case 120: // All Sound Off (See [1])
166             break;
167         case 121: // All Controllers Off (go to default values)
168             break;
169         case 123: // All Notes Off (See [1])
170             break;
171         case 124: // Omni Mode Off
172             break;
173         case 125: // Omni Mode On
174             break;
175         default:
176             rv = false;
177         }
178
179         /* [1] - All Sound Off and All Notes Off are supposed to
180          *       silence everything except notes being played by the
181          *       local keyboard.  I'm not sure what this means for
182          *       Composite/Tritium.  It also says that if we can't
183          *       distinguish between notes being played by the local
184          *       keyboard and "other" notes... then we should not
185          *       implement this controller.
186          */
187
188         assert( _volume == (_volume & 0x3FFF) );
189
190         return rv;
191     } // DefaultMidiImplementation::handle_control_change()
192
193 } // namespace Tritium