Allolib  1.0
C++ Components For Interactive Multimedia
al_MIDI.hpp
1 #ifndef INCLUDE_AL_IO_MIDI_HPP
2 #define INCLUDE_AL_IO_MIDI_HPP
3 
4 #include <exception>
5 #include <iostream>
6 #include <queue>
7 #include <string>
8 #include <vector>
9 
10 /**********************************************************************/
11 /* \class MIDI
12  \brief An abstract base class for realtime MIDI input/output.
13 
14  This class implements some common functionality for the realtime
15  MIDI input/output subclasses RtRtMidiIn and RtMidiOut.
16 
17  RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
18 */
19 /**********************************************************************/
20 
21 #define NOMINMAX
22 #include "RtMidi.h"
23 #undef NOMINMAX
24 
25 namespace al {
26 
27 // Internal classes to maintain backward compatibility
28 // class[[depreacated("User RtRtMidiIn directly")]] RtMidiIn : public
29 // RtMidiIn{};
30 
31 // class[[depreacated("User RtMidiOut directly")]] MIDIOut : public RtMidiOut{};
32 
33 // class[[depreacated("User RtMidiError directly")]] MIDIError
34 // : public RtMidiError{};
35 
39 double noteToHz(double noteNumber);
40 
41 int getMIDIDeviceIndex(std::string deviceName);;
42 
46 class MIDIByte {
47  public:
48 #define BITS_(a, b, c, d, e, f, g, h) \
49  (a << 7 | b << 6 | c << 5 | d << 4 | e << 3 | f << 2 | g << 1 | h)
50 
51  // Constants for checking the first message byte
52  // http://www.midi.org/techspecs/midimessages.php
53  static const unsigned char
54  CHANNEL_MASK = BITS_(0, 0, 0, 0, 1, 1, 1,
55  1),
57  BITS_(1, 1, 1, 1, 0, 0, 0, 0),
58 
60  BITS_(1, 0, 0, 0, 0, 0, 0, 0),
62  BITS_(1, 0, 0, 1, 0, 0, 0, 0),
63  CONTROL_CHANGE = BITS_(1, 0, 1, 1, 0, 0, 0,
64  0),
65  BANK_SELECT = 0x00,
66  MODULATION = 0x01,
67  BREATH = 0x02,
68  FOOT = 0x04,
69  PORTAMENTO_TIME = 0x05,
70  VOLUME = 0x07,
71  BALANCE = 0x08,
72  PAN = 0x0A,
73  EXPRESSION = 0x0B,
74  DAMPER_PEDAL = 0x40,
75  PORTAMENTO_ON = 0x41,
76  SOSTENUTO_ON = 0x42,
77  SOFT_PEDAL = 0x43,
78  LEGATO_ON = 0x44,
79 
80  PROGRAM_CHANGE = BITS_(1, 1, 0, 0, 0, 0, 0,
81  0),
83  BITS_(1, 0, 1, 0, 0, 0, 0,
84  0),
86  BITS_(1, 1, 0, 1, 0, 0, 0,
87  0),
89  BITS_(1, 1, 1, 0, 0, 0, 0, 0),
90 
91  SYSTEM_MSG = BITS_(1, 1, 1, 1, 0, 0, 0, 0),
92 
93  SYS_EX = BITS_(1, 1, 1, 1, 0, 0, 0,
94  0),
95  SYS_EX_END = BITS_(1, 1, 1, 1, 0, 1, 1,
96  1),
98  BITS_(1, 1, 1, 1, 0, 0, 0, 1),
100  BITS_(1, 1, 1, 1, 0, 0, 1, 0),
102  BITS_(1, 1, 1, 1, 0, 0, 1, 1),
104  BITS_(1, 1, 1, 1, 0, 1, 1, 0),
106  BITS_(1, 1, 1, 1, 1, 0, 0, 0),
107  SEQ_START = BITS_(1, 1, 1, 1, 1, 0, 1,
108  0),
109  SEQ_CONTINUE = BITS_(1, 1, 1, 1, 1, 0, 1,
110  1),
112  BITS_(1, 1, 1, 1, 1, 1, 0, 0),
113  ACTIVE_SENSING = BITS_(1, 1, 1, 1, 1, 1, 1,
114  0),
115  RESET = BITS_(1, 1, 1, 1, 1, 1, 1,
116  1)
117  ;
118 #undef BITS_
119 
121  static bool isChannelMessage(unsigned char statusByte) {
122  return (statusByte & MESSAGE_MASK) != SYSTEM_MSG;
123  }
124 
126  static const char* messageTypeString(unsigned char statusByte);
127 
129  static const char* controlNumberString(unsigned char controlNumber);
130 
132  static unsigned short convertPitchBend(unsigned char byte2,
133  unsigned char byte3);
134 };
135 
139 class MIDIMessage {
140  public:
141  unsigned char bytes[3];
142 
143  MIDIMessage(double timeStamp, unsigned port, unsigned char b1,
144  unsigned char b2 = 0, unsigned char b3 = 0,
145  unsigned char* data = nullptr);
146 
148  unsigned port() const { return mPort; }
149 
151  double timeStamp() const { return mTimeStamp; }
152 
154  unsigned char status() const { return bytes[0]; }
155 
158 
160  unsigned char channel() const { return bytes[0] & MIDIByte::CHANNEL_MASK; }
161 
163  unsigned char type() const { return bytes[0] & MIDIByte::MESSAGE_MASK; }
164 
166  unsigned char noteNumber() const { return bytes[1]; }
167 
169  double velocity(double mul = 1. / 127.) const { return bytes[2] * mul; }
170 
172  double pitchBend() const {
173  int v = int(MIDIByte::convertPitchBend(bytes[1], bytes[2]));
174  v += 1 - bool(v); // clip interval to [1, 16383]
175  return double(v - 8192) / 8191.;
176  }
177 
179  unsigned char controlNumber() const { return bytes[1]; }
180 
182  double controlValue(double mul = 1. / 127.) const { return bytes[2] * mul; }
183 
185  unsigned char* data() const { return mData; }
186 
188  void print(std::ostream& stream = std::cout) const;
189 
190  protected:
191  double mTimeStamp;
192  unsigned mPort;
193  unsigned char* mData;
194 };
195 
200  public:
201  virtual ~MIDIMessageHandler() {}
202 
204  virtual void onMIDIMessage(const MIDIMessage& m) = 0;
205 
207  void bindTo(RtMidiIn& RtMidiIn, unsigned port = 0);
208 
209  void clearBindings() {
210  for (auto& binding : mBindings) {
211  binding.midiIn->cancelCallback();
212  }
213  mBindings.clear();
214  }
215 
216  protected:
217  struct Binding {
218  RtMidiIn* midiIn;
219  MIDIMessageHandler* handler;
220  unsigned port;
221  };
222 
223  std::vector<Binding> mBindings;
224 };
225 
226 } // namespace al
227 
228 #endif
static const char * controlNumberString(unsigned char controlNumber)
Get string with control type from control number.
static const unsigned char MESSAGE_MASK
Message status byte type mask.
Definition: al_MIDI.hpp:56
static const unsigned char ACTIVE_SENSING
Active sensing system message type.
Definition: al_MIDI.hpp:113
static const unsigned char TIMING_CLOCK
Timing clock system message type.
Definition: al_MIDI.hpp:105
static const unsigned char SYS_EX_END
End of system exclusive system message type.
Definition: al_MIDI.hpp:95
static const unsigned char NOTE_ON
Note on channel message type.
Definition: al_MIDI.hpp:61
static const unsigned char SOFT_PEDAL
Soft pedal control number.
Definition: al_MIDI.hpp:77
static const unsigned char EXPRESSION
Expression controller control number.
Definition: al_MIDI.hpp:73
static const unsigned char RESET
Reset all receivers system message type.
Definition: al_MIDI.hpp:115
static const unsigned char BANK_SELECT
Bank select control number.
Definition: al_MIDI.hpp:65
static const unsigned char CHANNEL_MASK
Channel message status byte channel mask.
Definition: al_MIDI.hpp:54
static const unsigned char NOTE_OFF
Note off channel message type.
Definition: al_MIDI.hpp:59
static const unsigned char PRESSURE_CHAN
Channel pressure (aftertouch) channel message type.
Definition: al_MIDI.hpp:85
static const unsigned char PROGRAM_CHANGE
Program change channel message type.
Definition: al_MIDI.hpp:80
static const unsigned char SYS_EX
System exclusive system message type.
Definition: al_MIDI.hpp:93
static const unsigned char BREATH
Breath controller control number.
Definition: al_MIDI.hpp:67
static const unsigned char DAMPER_PEDAL
Damper pedal control number.
Definition: al_MIDI.hpp:74
static const unsigned char TUNE_REQUEST
Tune request system message type.
Definition: al_MIDI.hpp:103
static const unsigned char PORTAMENTO_TIME
Portamento time control number.
Definition: al_MIDI.hpp:69
static const char * messageTypeString(unsigned char statusByte)
Get string with message type from status byte.
static const unsigned char SEQ_STOP
Stop sequence system message type.
Definition: al_MIDI.hpp:111
static const unsigned char SOSTENUTO_ON
Sostenuto on/off control number.
Definition: al_MIDI.hpp:76
static const unsigned char PITCH_BEND
Pitch bend channel message type.
Definition: al_MIDI.hpp:88
static const unsigned char VOLUME
Channel volume control number.
Definition: al_MIDI.hpp:70
static const unsigned char SONG_POSITION
Song position system message type.
Definition: al_MIDI.hpp:99
static const unsigned char FOOT
Foot controller control number.
Definition: al_MIDI.hpp:68
static const unsigned char BALANCE
Balance control number.
Definition: al_MIDI.hpp:71
static const unsigned char LEGATO_ON
Legato on/off control number.
Definition: al_MIDI.hpp:78
static const unsigned char PORTAMENTO_ON
Portamento on/off control number.
Definition: al_MIDI.hpp:75
static unsigned short convertPitchBend(unsigned char byte2, unsigned char byte3)
Convert pitch bend message bytes into a 14-bit value in [0, 16384)
static const unsigned char SONG_SELECT
Song select system message type.
Definition: al_MIDI.hpp:101
static const unsigned char SEQ_START
Start sequence system message type.
Definition: al_MIDI.hpp:107
static bool isChannelMessage(unsigned char statusByte)
Check status byte to see if the message is a channel message.
Definition: al_MIDI.hpp:121
static const unsigned char PAN
Pan control number.
Definition: al_MIDI.hpp:72
static const unsigned char SEQ_CONTINUE
Continue sequence system message type.
Definition: al_MIDI.hpp:109
static const unsigned char PRESSURE_POLY
Polyphonic pressure (aftertouch) channel message type.
Definition: al_MIDI.hpp:82
static const unsigned char MODULATION
Modulation wheel/stick control number.
Definition: al_MIDI.hpp:66
static const unsigned char SYSTEM_MSG
System message type.
Definition: al_MIDI.hpp:91
static const unsigned char TIME_CODE
Time code system message type.
Definition: al_MIDI.hpp:97
static const unsigned char CONTROL_CHANGE
Control change channel message type.
Definition: al_MIDI.hpp:63
void bindTo(RtMidiIn &RtMidiIn, unsigned port=0)
Bind handler to a MIDI input.
virtual void onMIDIMessage(const MIDIMessage &m)=0
Called when a MIDI message is received.
unsigned char type() const
Get the message type (see MIDIByte)
Definition: al_MIDI.hpp:163
bool isChannelMessage() const
Returns whether this is a channel (versus system) message.
Definition: al_MIDI.hpp:157
double pitchBend() const
Get mapped pitch bend amount in [-1,1] (type must be PITCH_BEND)
Definition: al_MIDI.hpp:172
double timeStamp() const
Get time stamp of message.
Definition: al_MIDI.hpp:151
unsigned char status() const
Get the status byte.
Definition: al_MIDI.hpp:154
unsigned char noteNumber() const
Get note number (type must be NOTE_ON or NOTE_OFF)
Definition: al_MIDI.hpp:166
unsigned char controlNumber() const
Get controller number (type must be CONTROL_CHANGE)
Definition: al_MIDI.hpp:179
double velocity(double mul=1./127.) const
Get mapped note velocity (type must be NOTE_ON or NOTE_OFF)
Definition: al_MIDI.hpp:169
void print(std::ostream &stream=std::cout) const
Print general information about message.
unsigned port() const
Get the MIDI device port.
Definition: al_MIDI.hpp:148
double controlValue(double mul=1./127.) const
Get mapped controller value (type must be CONTROL_CHANGE)
Definition: al_MIDI.hpp:182
unsigned char channel() const
Get the channel number (0-15)
Definition: al_MIDI.hpp:160
unsigned char * data() const
Get sysex message data.
Definition: al_MIDI.hpp:185
double noteToHz(double noteNumber)
Definition: al_App.hpp:23