Files

copied
Last update 6 years 4 months by Olivier Gillet
Filesedges
..
bootloader
hardware_design
resources
__init__.py
adc_acquisition.cc
adc_acquisition.h
audio_buffer.cc
audio_buffer.h
digital_oscillator.cc
digital_oscillator.h
edges.cc
hardware_config.h
makefile
midi.h
midi_handler.cc
midi_handler.h
note_stack.h
resources.cc
resources.h
settings.cc
settings.h
storage.h
timer_oscillator.cc
timer_oscillator.h
ui.cc
ui.h
voice_allocator.cc
voice_allocator.h
midi.h
// 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_
Report a bug