You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
7.9KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  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 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Decoding of MIDI messages.
  19. #ifndef EDGES_MIDI_H_
  20. #define EDGES_MIDI_H_
  21. namespace midi {
  22. const uint8_t kBankMsb = 0x00;
  23. const uint8_t kBankLsb = 0x20;
  24. const uint8_t kModulationWheelMsb = 0x01;
  25. const uint8_t kBreathController = 0x02;
  26. const uint8_t kFootPedalMsb = 0x04;
  27. const uint8_t kDataEntryMsb = 0x06;
  28. const uint8_t kVolume = 0x07;
  29. const uint8_t kFootPedalLsb = 0x24;
  30. const uint8_t kDataEntryLsb = 0x26;
  31. const uint8_t kPortamentoTimeMsb = 0x05;
  32. const uint8_t kHoldPedal = 0x40;
  33. const uint8_t kHarmonicIntensity = 0x47;
  34. const uint8_t kRelease = 0x48;
  35. const uint8_t kAttack = 0x49;
  36. const uint8_t kBrightness = 0x4a;
  37. const uint8_t kDataIncrement = 0x60;
  38. const uint8_t kDataDecrement = 0x61;
  39. const uint8_t kNrpnMsb = 0x63;
  40. const uint8_t kNrpnLsb = 0x62;
  41. const uint8_t kAssignableCcA = 0x10;
  42. const uint8_t kAssignableCcB = 0x11;
  43. const uint8_t kAssignableCcC = 0x12;
  44. const uint8_t kAssignableCcD = 0x13;
  45. // A device that responds to MIDI messages should implement this interface.
  46. // Everything is static - this is because the main synth class is a "static
  47. // singleton". Note that this allows all the MIDI processing code to be inlined!
  48. struct MidiDevice {
  49. static void NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) { }
  50. static void NoteOff(uint8_t channel, uint8_t note, uint8_t velocity) { }
  51. static void Aftertouch(uint8_t channel, uint8_t note, uint8_t velocity) { }
  52. static void Aftertouch(uint8_t channel, uint8_t velocity) { }
  53. static void ControlChange(uint8_t channel, uint8_t controller,
  54. uint8_t value) { }
  55. static void ProgramChange(uint8_t channel, uint8_t program) { }
  56. static void PitchBend(uint8_t channel, uint16_t pitch_bend) { }
  57. static void AllSoundOff(uint8_t channel) { }
  58. static void ResetAllControllers(uint8_t channel) { }
  59. static void LocalControl(uint8_t channel, uint8_t state) { }
  60. static void AllNotesOff(uint8_t channel) { }
  61. static void OmniModeOff(uint8_t channel) { }
  62. static void OmniModeOn(uint8_t channel) { }
  63. static void MonoModeOn(uint8_t channel, uint8_t num_channels) { }
  64. static void PolyModeOn(uint8_t channel) { }
  65. static void SysExStart() { }
  66. static void SysExByte(uint8_t sysex_byte) { }
  67. static void SysExEnd() { }
  68. static void BozoByte(uint8_t bozo_byte) { }
  69. static void Clock() { }
  70. static void Start() { }
  71. static void Continue() { }
  72. static void Stop() { }
  73. static void ActiveSensing() { }
  74. static void Reset() { }
  75. static uint8_t CheckChannel(uint8_t channel) { return 1; }
  76. static void RawByte(uint8_t byte) { }
  77. static void RawMidiData(
  78. uint8_t status,
  79. uint8_t* data,
  80. uint8_t data_size,
  81. uint8_t accepted_channel) { }
  82. };
  83. template<typename Device>
  84. class MidiStreamParser {
  85. public:
  86. MidiStreamParser();
  87. void PushByte(uint8_t byte);
  88. private:
  89. void MessageReceived(uint8_t status);
  90. uint8_t running_status_;
  91. uint8_t data_[3];
  92. uint8_t data_size_; // Number of non-status byte received.
  93. uint8_t expected_data_size_; // Expected number of non-status bytes.
  94. DISALLOW_COPY_AND_ASSIGN(MidiStreamParser);
  95. };
  96. template<typename Device>
  97. MidiStreamParser<Device>::MidiStreamParser() {
  98. running_status_ = 0;
  99. data_size_ = 0;
  100. expected_data_size_ = 0;
  101. }
  102. template<typename Device>
  103. void MidiStreamParser<Device>::PushByte(uint8_t byte) {
  104. // Realtime messages are immediately passed-through, and do not modify the
  105. // state of the parser.
  106. Device::RawByte(byte);
  107. if (byte >= 0xf8) {
  108. MessageReceived(byte);
  109. } else {
  110. if (byte >= 0x80) {
  111. uint8_t hi = byte & 0xf0;
  112. uint8_t lo = byte & 0x0f;
  113. data_size_ = 0;
  114. expected_data_size_ = 1;
  115. switch (hi) {
  116. case 0x80:
  117. case 0x90:
  118. case 0xa0:
  119. case 0xb0:
  120. expected_data_size_ = 2;
  121. break;
  122. case 0xc0:
  123. case 0xd0:
  124. break; // default data size of 1.
  125. case 0xe0:
  126. expected_data_size_ = 2;
  127. break;
  128. case 0xf0:
  129. if (lo > 0 && lo < 3) {
  130. expected_data_size_ = 2;
  131. } else if (lo >= 4) {
  132. expected_data_size_ = 0;
  133. }
  134. break;
  135. }
  136. if (byte == 0xf7) {
  137. if (running_status_ == 0xf0) {
  138. Device::SysExEnd();
  139. }
  140. running_status_ = 0;
  141. } else if (byte == 0xf0) {
  142. running_status_ = 0xf0;
  143. Device::SysExStart();
  144. } else {
  145. running_status_ = byte;
  146. }
  147. } else {
  148. data_[data_size_++] = byte;
  149. }
  150. if (data_size_ >= expected_data_size_) {
  151. MessageReceived(running_status_);
  152. data_size_ = 0;
  153. if (running_status_ > 0xf0) {
  154. expected_data_size_ = 0;
  155. running_status_ = 0;
  156. }
  157. }
  158. }
  159. }
  160. template<typename Device>
  161. void MidiStreamParser<Device>::MessageReceived(uint8_t status) {
  162. if (!status) {
  163. Device::BozoByte(data_[0]);
  164. }
  165. uint8_t hi = status & 0xf0;
  166. uint8_t lo = status & 0x0f;
  167. // If this is a channel-specific message, check first that the receiver is
  168. // tune to this channel.
  169. if (hi != 0xf0 && !Device::CheckChannel(lo)) {
  170. Device::RawMidiData(status, data_, data_size_, 0);
  171. return;
  172. }
  173. Device::RawMidiData(status, data_, data_size_, 1);
  174. switch (hi) {
  175. case 0x80:
  176. Device::NoteOff(lo, data_[0], data_[1]);
  177. break;
  178. case 0x90:
  179. if (data_[1]) {
  180. Device::NoteOn(lo, data_[0], data_[1]);
  181. } else {
  182. Device::NoteOff(lo, data_[0], 0);
  183. }
  184. break;
  185. case 0xa0:
  186. Device::Aftertouch(lo, data_[0], data_[1]);
  187. break;
  188. case 0xb0:
  189. switch (data_[0]) {
  190. case 0x78:
  191. Device::AllSoundOff(lo);
  192. break;
  193. case 0x79:
  194. Device::ResetAllControllers(lo);
  195. break;
  196. case 0x7a:
  197. Device::LocalControl(lo, data_[1]);
  198. break;
  199. case 0x7b:
  200. Device::AllNotesOff(lo);
  201. break;
  202. case 0x7c:
  203. Device::OmniModeOff(lo);
  204. break;
  205. case 0x7d:
  206. Device::OmniModeOn(lo);
  207. break;
  208. case 0x7e:
  209. Device::MonoModeOn(lo, data_[1]);
  210. break;
  211. case 0x7f:
  212. Device::PolyModeOn(lo);
  213. break;
  214. default:
  215. Device::ControlChange(lo, data_[0], data_[1]);
  216. break;
  217. }
  218. break;
  219. case 0xc0:
  220. Device::ProgramChange(lo, data_[0]);
  221. break;
  222. case 0xd0:
  223. Device::Aftertouch(lo, data_[0]);
  224. break;
  225. case 0xe0:
  226. Device::PitchBend(lo, (static_cast<uint16_t>(data_[1]) << 7) + data_[0]);
  227. break;
  228. case 0xf0:
  229. switch(lo) {
  230. case 0x0:
  231. Device::SysExByte(data_[0]);
  232. break;
  233. case 0x1:
  234. case 0x2:
  235. case 0x3:
  236. case 0x4:
  237. case 0x5:
  238. case 0x6:
  239. // TODO(pichenettes): implement this if it makes sense.
  240. break;
  241. case 0x8:
  242. Device::Clock();
  243. break;
  244. case 0x9:
  245. break;
  246. case 0xa:
  247. Device::Start();
  248. break;
  249. case 0xb:
  250. Device::Continue();
  251. break;
  252. case 0xc:
  253. Device::Stop();
  254. break;
  255. case 0xe:
  256. Device::ActiveSensing();
  257. break;
  258. case 0xf:
  259. Device::Reset();
  260. break;
  261. }
  262. break;
  263. }
  264. }
  265. } // namespace midi
  266. #endif // EDGES_MIDI_H_