| 
							- // Copyright 2013 Olivier Gillet.
 - //
 - // Author: Olivier Gillet (ol.gillet@gmail.com)
 - //
 - // Permission is hereby granted, free of charge, to any person obtaining a copy
 - // of this software and associated documentation files (the "Software"), to deal
 - // in the Software without restriction, including without limitation the rights
 - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 - // copies of the Software, and to permit persons to whom the Software is
 - // furnished to do so, subject to the following conditions:
 - // 
 - // The above copyright notice and this permission notice shall be included in
 - // all copies or substantial portions of the Software.
 - // 
 - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 - // THE SOFTWARE.
 - // 
 - // See http://creativecommons.org/licenses/MIT/ for more information.
 - //
 - // -----------------------------------------------------------------------------
 - //
 - // MIDI event handler.
 - 
 - #include "yarns/midi_handler.h"
 - 
 - #include <algorithm>
 - 
 - #include "yarns/multi.h"
 - #ifndef TEST
 - #include "yarns/storage_manager.h"
 - #endif // TEST
 - 
 - namespace yarns {
 - 
 - using namespace std;
 - 
 - /* static */
 - MidiHandler::MidiBuffer MidiHandler::input_buffer_; 
 - 
 - /* static */
 - MidiHandler::MidiBuffer MidiHandler::output_buffer_;
 - 
 - /* static */
 - MidiHandler::SmallMidiBuffer MidiHandler::high_priority_output_buffer_;
 - 
 - /* static */
 - stmlib_midi::MidiStreamParser<MidiHandler> MidiHandler::parser_;
 - 
 - /* static */
 - const MidiHandler::SysExDescription MidiHandler::accepted_sysex_[] = {
 -   { { 0xf0, 0x00, 0x21, 0x02, 0x00, 0x0b }, 6, 0xff,
 -       &MidiHandler::HandleYarnsSpecificMessage },
 -   { { 0xf0, 0x7f, 0xff, 0x08, 0x08 }, 5, 21,
 -       &MidiHandler::HandleScaleOctaveTuning1ByteForm },
 -   { { 0xf0, 0x7e, 0xff, 0x08, 0x08 }, 5, 21,
 -       &MidiHandler::HandleScaleOctaveTuning1ByteForm },
 -   { { 0xf0, 0x7f, 0xff, 0x08, 0x09 }, 5, 33,
 -       &MidiHandler::HandleScaleOctaveTuning2ByteForm },
 -   { { 0xf0, 0x7e, 0xff, 0x08, 0x09 }, 5, 33,
 -       &MidiHandler::HandleScaleOctaveTuning2ByteForm }
 - };
 - 
 - /* static */
 - uint8_t MidiHandler::sysex_rx_write_ptr_;
 - 
 - /* static */
 - uint8_t MidiHandler::previous_packet_index_;
 - 
 - /* static */
 - uint8_t MidiHandler::sysex_rx_buffer_[kSysexRxBufferSize];
 - 
 - /* static */
 - uint8_t MidiHandler::calibration_voice_;
 - 
 - /* static */
 - uint8_t MidiHandler::calibration_note_;
 - 
 - /* static */
 - bool MidiHandler::factory_testing_requested_;
 - 
 - /* static */
 - void MidiHandler::Init() {
 -   input_buffer_.Init();
 -   output_buffer_.Init();
 -   high_priority_output_buffer_.Init();
 -   sysex_rx_write_ptr_ = 0;
 -   previous_packet_index_ = 0;
 -   calibration_voice_ = 0xff;
 -   calibration_note_ = 0xff;
 -   factory_testing_requested_ = false;
 - }
 - 
 - /* static */
 - void MidiHandler::DecodeSysExMessage() {
 -   uint8_t length = sysex_rx_write_ptr_;
 - 
 -   if (sysex_rx_buffer_[length - 1] != 0xf7) {
 -     // Discard long messages that have been truncated.
 -     return;
 -   }
 -   
 -   for (uint8_t i = 0;
 -        i < sizeof(accepted_sysex_) / sizeof(SysExDescription);
 -        ++i) {
 -     const SysExDescription& description = accepted_sysex_[i];
 -     if (description.expected_size == length ||
 -         description.expected_size == 0xff) {
 -       bool match = true;
 -       for (uint8_t j = 0; j < description.prefix_length; ++j) {
 -         if (description.prefix[j] != sysex_rx_buffer_[j] &&
 -             description.prefix[j] != 0xff) {
 -           match = false;
 -           break;
 -         }
 -       }
 -       if (match) {
 -         (*description.handler)();
 -         break;
 -       }
 -     }
 -   }
 - }
 - 
 - /* static */
 - void MidiHandler::HandleScaleOctaveTuning1ByteForm() {
 -   for (uint8_t pitch_class = 0; pitch_class < 12; ++pitch_class) {
 -     int16_t correction = sysex_rx_buffer_[8 + pitch_class];
 -     correction -= 64;
 -     correction = (correction * 128 + (correction > 0 ? 64 : -64)) / 100;
 -     multi.set_custom_pitch(pitch_class, correction);
 -   }
 - }
 - 
 - /* static */
 - void MidiHandler::HandleScaleOctaveTuning2ByteForm() {
 -   for (uint8_t pitch_class = 0; pitch_class < 12; ++pitch_class) {
 -     int16_t correction = sysex_rx_buffer_[8 + pitch_class * 2] << 7;
 -     correction += sysex_rx_buffer_[9 + pitch_class * 2];
 -     correction -= 8192;
 -     correction >>= 6;
 -     multi.set_custom_pitch(pitch_class, correction);
 -   }
 - }
 - 
 - 
 - enum SysExCommand {
 -   SYSEX_COMMAND_DUMP_PACKET = 1,
 -   SYSEX_COMMAND_REQUEST_PACKETS = 17,
 -   SYSEX_COMMAND_FACTORY_TESTING_MODE = 32,
 -   SYSEX_COMMAND_CALIBRATE = 33,
 - };
 - 
 - /* static */
 - void MidiHandler::HandleYarnsSpecificMessage() {
 - #ifndef TEST
 -   uint8_t command = sysex_rx_buffer_[6];
 -   if (command == SYSEX_COMMAND_DUMP_PACKET) {
 -     uint8_t packet_index = sysex_rx_buffer_[7];
 -     
 -     // Handle packet reception.
 -     if (packet_index != 0 && packet_index != previous_packet_index_ + 1) {
 -       // Packet not in sequence!
 -       return;
 -     }
 -     previous_packet_index_ = packet_index;
 -     
 -     // Denibblize.
 -     uint8_t* data = &sysex_rx_buffer_[8];
 -     uint8_t* byte_ptr = data;
 -     uint8_t* nibble_ptr = data;
 -     uint8_t checksum = 0;
 -     while (*nibble_ptr != 0xf7 &&
 -            static_cast<size_t>(byte_ptr - data) <= kSysexMaxChunkSize + 1) {
 -       *byte_ptr = (*nibble_ptr++) << 4;
 -       *byte_ptr |= (*nibble_ptr++);
 -       // Warning! The last byte of the block, which is the checksum
 -       // is summed here!
 -       checksum += *byte_ptr++;
 -     }
 -     size_t size = byte_ptr - data - 1;
 -     checksum -= data[size];
 -     if (checksum != data[size]) {
 -       previous_packet_index_ = 0xff;
 -       return;
 -     }
 -     if (size != 0) {
 -       storage_manager.AppendData(data, size, packet_index == 0);
 -     } else if (packet_index) {
 -       storage_manager.DeserializeMulti();
 -     }
 -   } else if (command == SYSEX_COMMAND_REQUEST_PACKETS) {
 -     if (sysex_rx_buffer_[7] == 0 &&
 -         sysex_rx_buffer_[8] == 0 && 
 -         sysex_rx_buffer_[9] == 0 &&
 -         sysex_rx_buffer_[10] == 0xf7) {
 -       storage_manager.SysExSendMulti();
 -     }
 -   } else if (command == SYSEX_COMMAND_FACTORY_TESTING_MODE) {
 -     if (sysex_rx_buffer_[7] == 0 &&
 -         sysex_rx_buffer_[8] == 0 && 
 -         sysex_rx_buffer_[9] == 0 &&
 -         sysex_rx_buffer_[10] == 0xf7) {
 -       factory_testing_requested_ = true;
 -     }
 -   } else if (command == SYSEX_COMMAND_CALIBRATE) {
 -     calibration_voice_ = sysex_rx_buffer_[7] >> 4;
 -     calibration_note_ = sysex_rx_buffer_[7] & 0xf;
 -     if (calibrating()) {
 -       uint16_t dac_code = (sysex_rx_buffer_[8] << 12) | (sysex_rx_buffer_[9] << 8) |
 -         (sysex_rx_buffer_[10] << 4) | (sysex_rx_buffer_[11] << 0);
 -       Voice* voice = multi.mutable_voice(calibration_voice_);
 -       voice->set_calibration_dac_code(calibration_note_, dac_code);
 -     } else {
 -       storage_manager.SaveCalibration();
 -     }
 -   }
 - #endif  // TEST
 - }
 - 
 - /* static */
 - void MidiHandler::SysExSendPacket(
 -     uint8_t packet_index,
 -     const uint8_t* data,
 -     size_t size) {
 -   Flush();
 -   
 -   for (uint8_t i = 0; i < 6; ++i) {
 -     SendBlocking(accepted_sysex_[0].prefix[i]);
 -   }
 -   SendBlocking(SYSEX_COMMAND_DUMP_PACKET);
 -   SendBlocking(packet_index);
 -   
 -   // Outputs the data.
 -   uint8_t checksum = 0;
 -   for (uint8_t i = 0; i < size; ++i) {
 -     checksum += data[i];
 -     SendBlocking(data[i] >> 4);
 -     SendBlocking(data[i] & 0x0f);
 -   }
 -   // Outputs a checksum.
 -   SendBlocking(checksum >> 4);
 -   SendBlocking(checksum & 0x0f);
 - 
 -   // End of SysEx block.
 -   SendBlocking(0xf7);
 -   Flush();
 - }
 - 
 - /* static */
 - void MidiHandler::SysExSendPackets(const uint8_t* data, size_t size) {
 -   uint8_t block_index = 0;
 -   while (size) {
 -     size_t chunk_size = min(size, kSysexMaxChunkSize);
 -     SysExSendPacket(block_index, data, chunk_size);
 -     size -= chunk_size;
 -     data += chunk_size;
 -     ++block_index;
 -   }
 -   // Send a NULL packet to indicate end of transmission.
 -   SysExSendPacket(block_index, NULL, 0);
 - }
 - 
 - /* extern */
 - MidiHandler midi_handler;
 - 
 - }  // namespace yarns
 
 
  |