1 /************************************************************************
2     FAUST Architecture File
3     Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
4     ---------------------------------------------------------------------
5     This Architecture section is free software; you can redistribute it
6     and/or modify it under the terms of the GNU General Public License
7     as published by the Free Software Foundation; either version 3 of
8     the License, or (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, see <http://www.gnu.org/licenses/>.
17 
18     EXCEPTION : As a special exception, you may create a larger work
19     that contains this FAUST architecture section and distribute
20     that work under terms of your choice, so long as this FAUST
21     architecture section is not modified.
22 
23  ************************************************************************
24  ************************************************************************/
25 
26 #ifndef __midi__
27 #define __midi__
28 
29 #include <vector>
30 #include <string>
31 #include <algorithm>
32 
33 class MapUI;
34 
35 //----------------------------------------------------------------
36 //  MIDI processor definition
37 //----------------------------------------------------------------
38 
39 class midi {
40 
41     public:
42 
midi()43         midi() {}
~midi()44         virtual ~midi() {}
45 
46         // Additional time-stamped API for MIDI input
keyOn(double,int channel,int pitch,int velocity)47         virtual MapUI* keyOn(double, int channel, int pitch, int velocity)
48         {
49             return keyOn(channel, pitch, velocity);
50         }
51 
52         virtual void keyOff(double, int channel, int pitch, int velocity = 127)
53         {
54             keyOff(channel, pitch, velocity);
55         }
56 
pitchWheel(double,int channel,int wheel)57         virtual void pitchWheel(double, int channel, int wheel)
58         {
59             pitchWheel(channel, wheel);
60         }
61 
ctrlChange(double,int channel,int ctrl,int value)62         virtual void ctrlChange(double, int channel, int ctrl, int value)
63         {
64             ctrlChange(channel, ctrl, value);
65         }
66 
progChange(double,int channel,int pgm)67         virtual void progChange(double, int channel, int pgm)
68         {
69             progChange(channel, pgm);
70         }
71 
keyPress(double,int channel,int pitch,int press)72         virtual void keyPress(double, int channel, int pitch, int press)
73         {
74             keyPress(channel, pitch, press);
75         }
76 
chanPress(double date,int channel,int press)77         virtual void chanPress(double date, int channel, int press)
78         {
79             chanPress(channel, press);
80         }
81 
ctrlChange14bits(double,int channel,int ctrl,int value)82         virtual void ctrlChange14bits(double, int channel, int ctrl, int value)
83         {
84             ctrlChange14bits(channel, ctrl, value);
85         }
86 
87         // MIDI sync
start_sync(double date)88         virtual void start_sync(double date)  {}
stop_sync(double date)89         virtual void stop_sync(double date)   {}
clock(double date)90         virtual void clock(double date)  {}
91 
92         // Standard MIDI API
keyOn(int channel,int pitch,int velocity)93         virtual MapUI* keyOn(int channel, int pitch, int velocity)      { return 0; }
keyOff(int channel,int pitch,int velocity)94         virtual void keyOff(int channel, int pitch, int velocity)       {}
keyPress(int channel,int pitch,int press)95         virtual void keyPress(int channel, int pitch, int press)        {}
chanPress(int channel,int press)96         virtual void chanPress(int channel, int press)                  {}
ctrlChange(int channel,int ctrl,int value)97         virtual void ctrlChange(int channel, int ctrl, int value)       {}
ctrlChange14bits(int channel,int ctrl,int value)98         virtual void ctrlChange14bits(int channel, int ctrl, int value) {}
pitchWheel(int channel,int wheel)99         virtual void pitchWheel(int channel, int wheel)                 {}
progChange(int channel,int pgm)100         virtual void progChange(int channel, int pgm)                   {}
101 
102         enum MidiStatus {
103 
104             // channel voice messages
105             MIDI_NOTE_OFF           = 0x80,
106             MIDI_NOTE_ON            = 0x90,
107             MIDI_CONTROL_CHANGE     = 0xB0,
108             MIDI_PROGRAM_CHANGE     = 0xC0,
109             MIDI_PITCH_BEND         = 0xE0,
110             MIDI_AFTERTOUCH         = 0xD0,	// aka channel pressure
111             MIDI_POLY_AFTERTOUCH    = 0xA0,	// aka key pressure
112             MIDI_CLOCK              = 0xF8,
113             MIDI_START              = 0xFA,
114             MIDI_STOP               = 0xFC
115 
116         };
117 
118         enum MidiCtrl {
119 
120             ALL_NOTES_OFF = 123,
121             ALL_SOUND_OFF = 120
122 
123         };
124 };
125 
126 //----------------------------------------------------------------
127 //  Base class for MIDI API handling
128 //----------------------------------------------------------------
129 
130 class midi_handler : public midi {
131 
132     protected:
133 
134         std::vector<midi*> fMidiInputs;
135         std::string fName;
136 
137     public:
138 
fName(name)139         midi_handler(const std::string& name = "MIDIHandler"):fName(name) {}
~midi_handler()140         virtual ~midi_handler() {}
141 
addMidiIn(midi * midi_dsp)142         virtual void addMidiIn(midi* midi_dsp) { if (midi_dsp) fMidiInputs.push_back(midi_dsp); }
removeMidiIn(midi * midi_dsp)143         virtual void removeMidiIn(midi* midi_dsp)
144         {
145             std::vector<midi*>::iterator it = std::find(fMidiInputs.begin(), fMidiInputs.end(), midi_dsp);
146             if (it != fMidiInputs.end()) {
147                 fMidiInputs.erase(it);
148             }
149         }
150 
start_midi()151         virtual bool start_midi() { return true; }
stop_midi()152         virtual void stop_midi() {}
153 
handleSync(double time,int type)154         void handleSync(double time, int type)
155         {
156             if (type == MIDI_CLOCK) {
157                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
158                     fMidiInputs[i]->clock(time);
159                 }
160             } else if (type == MIDI_START) {
161                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
162                     fMidiInputs[i]->start_sync(time);
163                 }
164             } else if (type == MIDI_STOP) {
165                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
166                     fMidiInputs[i]->stop_sync(time);
167                 }
168             }
169         }
170 
handleData1(double time,int type,int channel,int data1)171         void handleData1(double time, int type, int channel, int data1)
172         {
173             if (type == MIDI_PROGRAM_CHANGE) {
174                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
175                     fMidiInputs[i]->progChange(time, channel, data1);
176                 }
177             } else if (type == MIDI_AFTERTOUCH) {
178                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
179                     fMidiInputs[i]->chanPress(time, channel, data1);
180                 }
181             }
182         }
183 
handleData2(double time,int type,int channel,int data1,int data2)184         void handleData2(double time, int type, int channel, int data1, int data2)
185         {
186             if (type == MIDI_NOTE_OFF || ((type == MIDI_NOTE_ON) && (data2 == 0))) {
187                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
188                     fMidiInputs[i]->keyOff(time, channel, data1, data2);
189                 }
190             } else if (type == MIDI_NOTE_ON) {
191                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
192                     fMidiInputs[i]->keyOn(time, channel, data1, data2);
193                 }
194             } else if (type == MIDI_CONTROL_CHANGE) {
195                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
196                     fMidiInputs[i]->ctrlChange(time, channel, data1, data2);
197                 }
198             } else if (type == MIDI_PITCH_BEND) {
199                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
200                     fMidiInputs[i]->pitchWheel(time, channel, (data2 * 128.0) + data1);
201                 }
202             } else if (type == MIDI_POLY_AFTERTOUCH) {
203                 for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
204                     fMidiInputs[i]->keyPress(time, channel, data1, data2);
205                 }
206             }
207         }
208 
209 
210 };
211 
212 #endif // __midi__
213