| 
							- // Copyright 2009 Olivier Gillet.
 - //
 - // Author: Olivier Gillet (ol.gillet@gmail.com)
 - //
 - // This program is free software: you can redistribute it and/or modify
 - // it under the terms of the GNU General Public License as published by
 - // the Free Software Foundation, either version 3 of the License, or
 - // (at your option) any later version.
 - // This program is distributed in the hope that it will be useful,
 - // but WITHOUT ANY WARRANTY; without even the implied warranty of
 - // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 - // GNU General Public License for more details.
 - // You should have received a copy of the GNU General Public License
 - // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 - //
 - // -----------------------------------------------------------------------------
 - //
 - // Decoding of MIDI messages.
 - 
 - #ifndef EDGES_MIDI_H_
 - #define EDGES_MIDI_H_
 - 
 - namespace midi {
 - 
 - const uint8_t kBankMsb = 0x00;
 - const uint8_t kBankLsb = 0x20;
 - const uint8_t kModulationWheelMsb = 0x01;
 - const uint8_t kBreathController = 0x02;
 - const uint8_t kFootPedalMsb = 0x04;
 - const uint8_t kDataEntryMsb = 0x06;
 - const uint8_t kVolume = 0x07;
 - const uint8_t kFootPedalLsb = 0x24;
 - const uint8_t kDataEntryLsb = 0x26;
 - const uint8_t kPortamentoTimeMsb = 0x05;
 - const uint8_t kHoldPedal = 0x40;
 - const uint8_t kHarmonicIntensity = 0x47;
 - const uint8_t kRelease = 0x48;
 - const uint8_t kAttack = 0x49;
 - const uint8_t kBrightness = 0x4a;
 - const uint8_t kDataIncrement = 0x60;
 - const uint8_t kDataDecrement = 0x61;
 - const uint8_t kNrpnMsb = 0x63;
 - const uint8_t kNrpnLsb = 0x62;
 - const uint8_t kAssignableCcA = 0x10;
 - const uint8_t kAssignableCcB = 0x11;
 - const uint8_t kAssignableCcC = 0x12;
 - const uint8_t kAssignableCcD = 0x13;
 - 
 - // A device that responds to MIDI messages should implement this interface.
 - // Everything is static - this is because the main synth class is a "static
 - // singleton". Note that this allows all the MIDI processing code to be inlined!
 - struct MidiDevice {
 -   static void NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) { }
 -   static void NoteOff(uint8_t channel, uint8_t note, uint8_t velocity) { }
 -   static void Aftertouch(uint8_t channel, uint8_t note, uint8_t velocity) { }
 -   static void Aftertouch(uint8_t channel, uint8_t velocity) { }
 -   static void ControlChange(uint8_t channel, uint8_t controller,
 -                              uint8_t value) { }
 -   static void ProgramChange(uint8_t channel, uint8_t program) { }
 -   static void PitchBend(uint8_t channel, uint16_t pitch_bend) { }
 - 
 -   static void AllSoundOff(uint8_t channel) { }
 -   static void ResetAllControllers(uint8_t channel) { }
 -   static void LocalControl(uint8_t channel, uint8_t state) { }
 -   static void AllNotesOff(uint8_t channel) { }
 -   static void OmniModeOff(uint8_t channel) { }
 -   static void OmniModeOn(uint8_t channel) { }
 -   static void MonoModeOn(uint8_t channel, uint8_t num_channels) { }
 -   static void PolyModeOn(uint8_t channel) { }
 -   static void SysExStart() { }
 -   static void SysExByte(uint8_t sysex_byte) { }
 -   static void SysExEnd() { }
 -   static void BozoByte(uint8_t bozo_byte) { }
 - 
 -   static void Clock() { }
 -   static void Start() { }
 -   static void Continue() { }
 -   static void Stop() { }
 -   static void ActiveSensing() { }
 -   static void Reset() { }
 - 
 -   static uint8_t CheckChannel(uint8_t channel) { return 1; }
 -   static void RawByte(uint8_t byte) { }
 -   static void RawMidiData(
 -       uint8_t status,
 -       uint8_t* data,
 -       uint8_t data_size,
 -       uint8_t accepted_channel) { }
 - };
 - 
 - template<typename Device>
 - class MidiStreamParser {
 -  public:
 -   MidiStreamParser();
 -   void PushByte(uint8_t byte);
 - 
 -  private:
 -   void MessageReceived(uint8_t status);
 -  
 -   uint8_t running_status_;
 -   uint8_t data_[3];
 -   uint8_t data_size_;  // Number of non-status byte received.
 -   uint8_t expected_data_size_;  // Expected number of non-status bytes.
 - 
 -   DISALLOW_COPY_AND_ASSIGN(MidiStreamParser);
 - };
 - 
 - template<typename Device>
 - MidiStreamParser<Device>::MidiStreamParser() {
 -   running_status_ = 0;
 -   data_size_ = 0;
 -   expected_data_size_ = 0;
 - }
 - 
 - template<typename Device>
 - void MidiStreamParser<Device>::PushByte(uint8_t byte) {
 -   // Realtime messages are immediately passed-through, and do not modify the
 -   // state of the parser.
 -   Device::RawByte(byte);
 -   if (byte >= 0xf8) {
 -     MessageReceived(byte);
 -   } else {
 -     if (byte >= 0x80) {
 -       uint8_t hi = byte & 0xf0;
 -       uint8_t lo = byte & 0x0f;
 -       data_size_ = 0;
 -       expected_data_size_ = 1;
 -       switch (hi) {
 -         case 0x80:
 -         case 0x90:
 -         case 0xa0:
 -         case 0xb0:
 -           expected_data_size_ = 2;
 -           break;
 -         case 0xc0:
 -         case 0xd0:
 -           break;  // default data size of 1.
 -         case 0xe0:
 -           expected_data_size_ = 2;
 -           break;
 -         case 0xf0:
 -           if (lo > 0 && lo < 3) {
 -             expected_data_size_ = 2;
 -           } else if (lo >= 4) {
 -             expected_data_size_ = 0;
 -           }
 -           break;
 -       }
 -       if (byte == 0xf7) {
 -         if (running_status_ == 0xf0) {
 -           Device::SysExEnd();
 -         }
 -         running_status_ = 0;
 -       } else if (byte == 0xf0) {
 -         running_status_ = 0xf0;
 -         Device::SysExStart();
 -       } else {
 -         running_status_ = byte;
 -       }
 -     } else {
 -       data_[data_size_++] = byte;
 -     }
 -     if (data_size_ >= expected_data_size_) {
 -       MessageReceived(running_status_);
 -       data_size_ = 0;
 -       if (running_status_ > 0xf0) {
 -         expected_data_size_ = 0;
 -         running_status_ = 0;
 -       }
 -     }
 -   }
 - }
 - 
 - template<typename Device>
 - void MidiStreamParser<Device>::MessageReceived(uint8_t status) {
 -   if (!status) {
 -     Device::BozoByte(data_[0]);
 -   }
 - 
 -   uint8_t hi = status & 0xf0;
 -   uint8_t lo = status & 0x0f;
 - 
 -   // If this is a channel-specific message, check first that the receiver is
 -   // tune to this channel.
 -   if (hi != 0xf0 && !Device::CheckChannel(lo)) {
 -     Device::RawMidiData(status, data_, data_size_, 0);
 -     return;
 -   }
 -   Device::RawMidiData(status, data_, data_size_, 1);
 -   switch (hi) {
 -     case 0x80:
 -       Device::NoteOff(lo, data_[0], data_[1]);
 -       break;
 - 
 -     case 0x90:
 -       if (data_[1]) {
 -         Device::NoteOn(lo, data_[0], data_[1]);
 -       } else {
 -         Device::NoteOff(lo, data_[0], 0);
 -       }
 -       break;
 - 
 -     case 0xa0:
 -       Device::Aftertouch(lo, data_[0], data_[1]);
 -       break;
 - 
 -     case 0xb0:
 -       switch (data_[0]) {
 -         case 0x78:
 -           Device::AllSoundOff(lo);
 -           break;
 -         case 0x79:
 -           Device::ResetAllControllers(lo);
 -           break;
 -         case 0x7a:
 -           Device::LocalControl(lo, data_[1]);
 -           break;
 -         case 0x7b:
 -           Device::AllNotesOff(lo);
 -           break;
 -         case 0x7c:
 -           Device::OmniModeOff(lo);
 -           break;
 -         case 0x7d:
 -           Device::OmniModeOn(lo);
 -           break;
 -         case 0x7e:
 -           Device::MonoModeOn(lo, data_[1]);
 -           break;
 -         case 0x7f:
 -           Device::PolyModeOn(lo);
 -           break;
 -         default:
 -           Device::ControlChange(lo, data_[0], data_[1]);
 -           break;
 -       }
 -       break;
 - 
 -     case 0xc0:
 -       Device::ProgramChange(lo, data_[0]);
 -       break;
 - 
 -     case 0xd0:
 -       Device::Aftertouch(lo, data_[0]);
 -       break;
 - 
 -     case 0xe0:
 -       Device::PitchBend(lo, (static_cast<uint16_t>(data_[1]) << 7) + data_[0]);
 -       break;
 - 
 -     case 0xf0:
 -       switch(lo) {
 -         case 0x0:
 -           Device::SysExByte(data_[0]);
 -           break;
 -         case 0x1:
 -         case 0x2:
 -         case 0x3:
 -         case 0x4:
 -         case 0x5:
 -         case 0x6:
 -           // TODO(pichenettes): implement this if it makes sense.
 -           break;
 -         case 0x8:
 -           Device::Clock();
 -           break;
 -         case 0x9:
 -           break;
 -         case 0xa:
 -           Device::Start();
 -           break;
 -         case 0xb:
 -           Device::Continue();
 -           break;
 -         case 0xc:
 -           Device::Stop();
 -           break;
 -         case 0xe:
 -           Device::ActiveSensing();
 -           break;
 -         case 0xf:
 -           Device::Reset();
 -           break;
 -       }
 -       break;
 -   }
 - }
 - 
 - }  // namespace midi
 - 
 - #endif  // EDGES_MIDI_H_
 
 
  |