composite.desktop.in: Fixing incorrect 'Version' value
[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           _bank(0)
37     {
38     }
39
40     DefaultMidiImplementation::~DefaultMidiImplementation()
41     {
42     }
43
44     bool DefaultMidiImplementation::handle_note_off(
45         SeqEvent& dest,
46         uint32_t size,
47         const uint8_t *midi
48         )
49     {
50         if(_ignore_note_off) return false;
51
52         assert(size == 3);
53         assert(0x80 == (midi[0] & 0xF0));
54
55         uint32_t note_no;
56         note_no = midi[1];
57         if(note_no < _note_min) {
58             return false;
59         } else {
60             note_no -= _note_min;
61         }
62
63         T<Sampler>::shared_ptr samp = _sampler;
64         if( !samp ) return false;
65         T<InstrumentList>::shared_ptr i_list = samp->get_instrument_list();
66         T<Instrument>::shared_ptr inst;
67         if( note_no < i_list->get_size() ) {
68             inst = i_list->get(note_no);
69         }
70
71         bool rv = false;
72         if(inst) {
73             dest.type = SeqEvent::NOTE_OFF;
74             dest.note.set_velocity(0.0f);
75             dest.note.set_instrument(inst);
76             rv = true;
77         }
78         return rv;
79     }
80
81     bool DefaultMidiImplementation::handle_note_on(
82         SeqEvent& dest,
83         uint32_t size,
84         const uint8_t *midi
85         )
86     {
87         assert(size == 3);
88         assert(0x90 == (midi[0] & 0xF0));
89
90         uint32_t note_no;
91         float velocity;
92
93         note_no = midi[1];
94         if(note_no < _note_min) {
95             return false;
96         } else {
97             note_no -= _note_min;
98         }
99
100         if( midi[2] == 0 ) {
101             return handle_note_off(dest, size, midi);
102         }
103         velocity = float(midi[2]) / 127.0f;
104
105         T<Sampler>::shared_ptr samp = _sampler;
106         if( !samp ) return false;
107         T<InstrumentList>::shared_ptr i_list = samp->get_instrument_list();
108         T<Instrument>::shared_ptr inst;
109         if( note_no < i_list->get_size() ) {
110             inst = i_list->get(note_no);
111         }
112
113         bool rv = false;
114         if(inst) {
115             dest.type = SeqEvent::NOTE_ON;
116             dest.note.set_velocity(velocity);
117             dest.note.set_instrument(inst);
118             dest.note.set_length(-1);
119             rv = true;
120         }
121         return rv;          
122     }
123
124     bool DefaultMidiImplementation::handle_control_change(
125         SeqEvent& dest,
126         uint32_t size,
127         const uint8_t *midi
128         )
129     {
130         assert(size == 3);
131         assert(0xB0 == (midi[0] & 0xF0));
132         const uint16_t coarse_mask = 0x3F80;
133         const uint16_t fine_mask = 0x7F;
134
135         bool rv = false;
136         const uint8_t& controller = midi[1];
137         const uint8_t& value = midi[2];
138
139         /******************************************************
140          * IF YOU HANDLE AN EVENT THE RESULTS IN A SeqEvent,
141          * BE SURE TO SET 'rv' TO TRUE
142          *******************************************************
143          */
144         switch(controller) {
145         case 0: // Bank (coarse)
146             _bank = (_bank & fine_mask) | ((value << 7) & coarse_mask);
147             rv = false;
148             break;
149         case 7: // Volume (coarse)
150             /* XXX TODO: Consider using an exponential taper on this.
151              */
152             _volume = (_volume & fine_mask) | ((value << 7) & coarse_mask);
153             dest.type = SeqEvent::VOL_UPDATE;
154             dest.fdata = float(_volume)/16383.0f;
155             rv = true;
156             break;
157         case 8: // Balance (coarse)
158             break;
159         case 10: // Pan position (coarse)
160             break;
161         case 11: // Expression (coarse)
162             break;
163         case 32: // Bank (fine)
164             _bank = (_bank & coarse_mask) | (value & fine_mask);
165             rv = false;
166             break;
167         case 39: // Volume (fine)
168             /* XXX TODO: Consider using an exponential taper on this.
169              */
170             _volume = (_volume & coarse_mask) | (value & fine_mask);
171             dest.type = SeqEvent::VOL_UPDATE;
172             dest.fdata = float(_volume)/16383.0f;
173             rv = true;
174             break;
175         case 120: // All Sound Off
176             dest.type = SeqEvent::ALL_OFF;
177             rv = true;
178             break;
179         case 121: // All Controllers Off (go to default values)
180             break;
181         case 123: // All Notes Off
182             dest.type = SeqEvent::ALL_OFF;
183             rv = true;
184             break;
185         case 124: // Omni Mode Off
186             break;
187         case 125: // Omni Mode On
188             break;
189         default:
190             rv = false;
191         }
192
193         assert( _volume == (_volume & 0x3FFF) );
194
195         return rv;
196     } // DefaultMidiImplementation::handle_control_change()
197
198     bool DefaultMidiImplementation::handle_program_change(
199         SeqEvent& dest,
200         uint32_t size,
201         const uint8_t *midi
202         )
203     {
204         assert(size == 2);
205         assert(0xC0 == (midi[0] & 0xF0));
206
207         bool rv = false;
208
209         dest.type = SeqEvent::PATCH_CHANGE;
210         dest.idata = ((uint32_t(_bank) & 0x3FFF) << 16) | midi[1];
211         rv = true;
212
213         return rv;
214     } // DefaultMidiImplementation::handle_program_change()
215
216     bool DefaultMidiImplementation::handle_system_reset(
217         SeqEvent& dest,
218         uint32_t size,
219         const uint8_t *midi
220         )
221     {
222         /* XXX TODO A system reset should set us back to a "default
223          * state."  (I.e. set volume and banks to default, set patch
224          * to default, etc.)  However, this requires a new SeqEvent
225          * type.  This will need to be done later.
226          */
227         dest.type = SeqEvent::ALL_OFF;
228         return true;
229     }
230 } // namespace Tritium