LCOV - code coverage report
Current view: top level - src/Control_Surface - Control_Surface_Class.cpp (source / functions) Hit Total Coverage
Test: ffed98f648fe78e7aa7bdd228474317d40dadbec Lines: 13 143 9.1 %
Date: 2022-05-28 15:22:59 Functions: 3 17 17.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "Control_Surface_Class.hpp"
       2             : #include <AH/Debug/Debug.hpp>
       3             : #include <AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp>
       4             : #include <AH/Hardware/FilteredAnalog.hpp>
       5             : #include <MIDI_Constants/Control_Change.hpp>
       6             : #include <MIDI_Inputs/MIDIInputElement.hpp>
       7             : #include <MIDI_Interfaces/DebugMIDI_Interface.hpp>
       8             : #include <MIDI_Outputs/Abstract/MIDIOutputElement.hpp>
       9             : #include <Selectors/Selector.hpp>
      10             : 
      11             : #include <AH/Arduino-Wrapper.h>
      12             : 
      13             : BEGIN_CS_NAMESPACE
      14             : 
      15             : using AH::ExtendedIOElement;
      16             : 
      17         584 : Control_Surface_ &Control_Surface_::getInstance() {
      18         584 :     static Control_Surface_ instance;
      19         584 :     return instance;
      20             : }
      21             : 
      22           0 : void Control_Surface_::begin() {
      23             : #if defined(ARDUINO) && defined(DEBUG_OUT)
      24             :     DEBUG_OUT.begin(AH::defaultBaudRate);
      25             :     delay(250);
      26             : #endif
      27             : 
      28           0 :     connectDefaultMIDI_Interface();
      29             : 
      30           0 :     FilteredAnalog<>::setupADC();
      31           0 :     ExtendedIOElement::beginAll();
      32           0 :     Updatable<MIDI_Interface>::beginAll();
      33           0 :     MIDIOutputOnly::beginAll();
      34           0 :     beginDisplays();
      35           0 :     MIDIInputElementNote::beginAll();
      36           0 :     MIDIInputElementKP::beginAll();
      37           0 :     MIDIInputElementCC::beginAll();
      38           0 :     MIDIInputElementPC::beginAll();
      39           0 :     MIDIInputElementCP::beginAll();
      40           0 :     MIDIInputElementPB::beginAll();
      41           0 :     MIDIInputElementSysEx::beginAll();
      42           0 :     Updatable<>::beginAll();
      43           0 :     Updatable<Display>::beginAll();
      44           0 :     displayTimer.begin();
      45           0 : }
      46             : 
      47          38 : bool Control_Surface_::connectDefaultMIDI_Interface() {
      48          38 :     if (hasSinkPipe() || hasSourcePipe())
      49           0 :         return false;
      50          38 :     auto def = MIDI_Interface::getDefault();
      51          38 :     if (def == nullptr) {
      52           0 :         FATAL_ERROR(F("No default MIDI Interface"), 0xF123);
      53             :         return false;
      54             :     }
      55          38 :     *this << inpipe << *def;
      56          38 :     *this >> outpipe >> *def;
      57          38 :     return true;
      58             : }
      59             : 
      60           0 : void Control_Surface_::disconnectMIDI_Interfaces() {
      61           0 :     disconnectSinkPipes();
      62           0 :     disconnectSourcePipes();
      63           0 : }
      64             : 
      65           0 : void Control_Surface_::loop() {
      66           0 :     ExtendedIOElement::updateAllBufferedInputs();
      67           0 :     Updatable<>::updateAll();
      68           0 :     updateMidiInput();
      69           0 :     updateInputs();
      70           0 :     if (displayTimer)
      71           0 :         updateDisplays();
      72           0 :     ExtendedIOElement::updateAllBufferedOutputs();
      73           0 : }
      74             : 
      75           0 : void Control_Surface_::updateMidiInput() {
      76           0 :     Updatable<MIDI_Interface>::updateAll();
      77           0 : }
      78             : 
      79         124 : void Control_Surface_::sendChannelMessageImpl(ChannelMessage msg) {
      80         124 :     this->sourceMIDItoPipe(msg);
      81         124 : }
      82           0 : void Control_Surface_::sendSysExImpl(SysExMessage msg) {
      83           0 :     this->sourceMIDItoPipe(msg);
      84           0 : }
      85           0 : void Control_Surface_::sendSysCommonImpl(SysCommonMessage msg) {
      86           0 :     this->sourceMIDItoPipe(msg);
      87           0 : }
      88           0 : void Control_Surface_::sendRealTimeImpl(RealTimeMessage msg) {
      89           0 :     this->sourceMIDItoPipe(msg);
      90           0 : }
      91             : 
      92           0 : void Control_Surface_::sinkMIDIfromPipe(ChannelMessage midimsg) {
      93             : #ifdef DEBUG_MIDI_PACKETS
      94             :     if (midimsg.hasTwoDataBytes())
      95             :         DEBUG(">>> " << hex << midimsg.header << ' ' << midimsg.data1 << ' '
      96             :                      << midimsg.data2 << " (" << midimsg.cable.getOneBased()
      97             :                      << ')' << dec);
      98             :     else
      99             :         DEBUG(">>> " << hex << midimsg.header << ' ' << midimsg.data1 << " ("
     100             :                      << midimsg.cable.getOneBased() << ')' << dec);
     101             : #endif
     102             : 
     103             :     // If the Channel Message callback exists, call it to see if we have to
     104             :     // continue handling it.
     105           0 :     if (channelMessageCallback && channelMessageCallback(midimsg))
     106           0 :         return;
     107             : 
     108           0 :     if (midimsg.getMessageType() == MIDIMessageType::CONTROL_CHANGE &&
     109           0 :         midimsg.getData1() == MIDI_CC::Reset_All_Controllers) {
     110             :         // Reset All Controllers
     111             :         DEBUG(F("Reset All Controllers"));
     112           0 :         MIDIInputElementCC::resetAll();
     113           0 :         MIDIInputElementCP::resetAll();
     114           0 :     } else if (midimsg.getMessageType() == MIDIMessageType::CONTROL_CHANGE &&
     115           0 :                midimsg.getData1() == MIDI_CC::All_Notes_Off) {
     116             :         // All Notes Off
     117           0 :         MIDIInputElementNote::resetAll();
     118             :     } else {
     119           0 :         switch (midimsg.getMessageType()) {
     120           0 :             case MIDIMessageType::NONE: break;
     121           0 :             case MIDIMessageType::NOTE_OFF: // fallthrough
     122             :             case MIDIMessageType::NOTE_ON:
     123             :                 DEBUGFN(F("Updating Note elements with new MIDI "
     124             :                           "message."));
     125           0 :                 MIDIInputElementNote::updateAllWith(midimsg);
     126           0 :                 break;
     127           0 :             case MIDIMessageType::KEY_PRESSURE:
     128             :                 DEBUGFN(F("Updating Key Pressure elements with new MIDI "
     129             :                           "message."));
     130           0 :                 MIDIInputElementKP::updateAllWith(midimsg);
     131           0 :                 break;
     132           0 :             case MIDIMessageType::CONTROL_CHANGE:
     133             :                 DEBUGFN(F("Updating CC elements with new MIDI "
     134             :                           "message."));
     135           0 :                 MIDIInputElementCC::updateAllWith(midimsg);
     136           0 :                 break;
     137           0 :             case MIDIMessageType::PROGRAM_CHANGE:
     138             :                 DEBUGFN(F("Updating Program Change elements with new MIDI "
     139             :                           "message."));
     140           0 :                 MIDIInputElementPC::updateAllWith(midimsg);
     141           0 :                 break;
     142           0 :             case MIDIMessageType::CHANNEL_PRESSURE:
     143             :                 DEBUGFN(F("Updating Channel Pressure elements with new MIDI "
     144             :                           "message."));
     145           0 :                 MIDIInputElementCP::updateAllWith(midimsg);
     146           0 :                 break;
     147           0 :             case MIDIMessageType::PITCH_BEND:
     148             :                 // Channel Pressure
     149             :                 DEBUGFN(F("Updating Pitch Bend elements with new MIDI "
     150             :                           "message."));
     151           0 :                 MIDIInputElementPB::updateAllWith(midimsg);
     152           0 :                 break;
     153             : 
     154             :             // These MIDI types are not channel messages, so aren't handled here
     155             :             // LCOV_EXCL_START
     156             :             case MIDIMessageType::SYSEX_START: break;
     157             :             case MIDIMessageType::MTC_QUARTER_FRAME: break;
     158             :             case MIDIMessageType::SONG_POSITION_POINTER: break;
     159             :             case MIDIMessageType::SONG_SELECT: break;
     160             :             case MIDIMessageType::UNDEFINED_SYSCOMMON_1: break;
     161             :             case MIDIMessageType::UNDEFINED_SYSCOMMON_2: break;
     162             :             case MIDIMessageType::TUNE_REQUEST: break;
     163             :             case MIDIMessageType::SYSEX_END: break;
     164             :             case MIDIMessageType::TIMING_CLOCK: break;
     165             :             case MIDIMessageType::UNDEFINED_REALTIME_1: break;
     166             :             case MIDIMessageType::START: break;
     167             :             case MIDIMessageType::CONTINUE: break;
     168             :             case MIDIMessageType::STOP: break;
     169             :             case MIDIMessageType::UNDEFINED_REALTIME_2: break;
     170             :             case MIDIMessageType::ACTIVE_SENSING: break;
     171             :             case MIDIMessageType::SYSTEM_RESET: break;
     172             :             default:
     173             :                 break;
     174             :                 // LCOV_EXCL_STOP
     175             :         }
     176             :     }
     177             : }
     178             : 
     179           0 : void Control_Surface_::sinkMIDIfromPipe(SysExMessage msg) {
     180             : #ifdef DEBUG_MIDI_PACKETS
     181             :     const uint8_t *data = msg.data;
     182             :     size_t len = msg.length;
     183             :     DEBUG_OUT << ">>> " << hex;
     184             :     for (size_t i = 0; i < len; i++)
     185             :         DEBUG_OUT << data[i] << ' ';
     186             :     DEBUG_OUT << " (" << msg.cable << ')' << dec << endl;
     187             : #endif
     188             :     // If the SysEx Message callback exists, call it to see if we have to
     189             :     // continue handling it.
     190           0 :     if (sysExMessageCallback && sysExMessageCallback(msg))
     191           0 :         return;
     192           0 :     MIDIInputElementSysEx::updateAllWith(msg);
     193             : }
     194             : 
     195           0 : void Control_Surface_::sinkMIDIfromPipe(SysCommonMessage msg) {
     196             : #ifdef DEBUG_MIDI_PACKETS
     197             :     DEBUG_OUT << ">>> " << hex << msg.getMessageType() << ' ' << msg.getData1()
     198             :               << ' ' << msg.getData2() << " (" << msg.cable << ')' << dec
     199             :               << endl;
     200             : #endif
     201             :     // If the SysEx Message callback exists, call it to see if we have to
     202             :     // continue handling it.
     203           0 :     if (sysCommonMessageCallback && sysCommonMessageCallback(msg))
     204           0 :         return;
     205             : }
     206             : 
     207           0 : void Control_Surface_::sinkMIDIfromPipe(RealTimeMessage rtMessage) {
     208             : #ifdef DEBUG_MIDI_PACKETS
     209             :     DEBUG(">>> " << hex << rtMessage.message << " ("
     210             :                  << rtMessage.cable.getOneBased() << ')' << dec);
     211             : #endif
     212             : 
     213             :     // If the Real-Time Message callback exists, call it to see if we have to
     214             :     // continue handling it.
     215           0 :     if (realTimeMessageCallback && realTimeMessageCallback(rtMessage))
     216           0 :         return;
     217             : }
     218             : 
     219           0 : void Control_Surface_::updateInputs() {
     220           0 :     MIDIInputElementNote::updateAll();
     221           0 :     MIDIInputElementKP::updateAll();
     222           0 :     MIDIInputElementCC::updateAll();
     223           0 :     MIDIInputElementPC::updateAll();
     224           0 :     MIDIInputElementCP::updateAll();
     225           0 :     MIDIInputElementPB::updateAll();
     226           0 :     MIDIInputElementSysEx::updateAll();
     227           0 : }
     228             : 
     229           0 : void Control_Surface_::beginDisplays() {
     230           0 :     auto &allElements = DisplayElement::getAll();
     231           0 :     auto it = allElements.begin();
     232           0 :     auto end = allElements.end();
     233           0 :     if (it == end)
     234           0 :         return;
     235           0 :     auto previousDisplay = &it->getDisplay();
     236             :     // Loop over all display elements
     237             :     while (true) {
     238           0 :         ++it;
     239             :         // If this is the first element on another display
     240           0 :         if (it == end || &it->getDisplay() != previousDisplay) {
     241             :             // Initialize the display
     242           0 :             previousDisplay->begin();
     243           0 :             if (it == end)
     244           0 :                 break;
     245           0 :             previousDisplay = &it->getDisplay();
     246             :         }
     247             :     }
     248             : }
     249             : 
     250           0 : void Control_Surface_::updateDisplays() {
     251           0 :     auto &allElements = DisplayElement::getAll();
     252           0 :     auto it = allElements.begin();
     253           0 :     auto end = allElements.end();
     254           0 :     if (it == end)
     255           0 :         return;
     256           0 :     auto prevIt = it;
     257           0 :     auto previousDisplay = &prevIt->getDisplay();
     258           0 :     bool dirty = false;
     259             :     // Loop over all display elements
     260             :     while (true) {
     261           0 :         dirty |= it->getDirty();
     262           0 :         ++it;
     263             :         // If this is the first element on another display
     264           0 :         if (it == end || &it->getDisplay() != previousDisplay) {
     265             :             // If there was at least one element on the previous display that
     266             :             // has to be redrawn
     267           0 :             if (dirty) {
     268             :                 // Clear the display
     269           0 :                 previousDisplay->clearAndDrawBackground();
     270             :                 // Update all elements on that display
     271           0 :                 for (auto drawIt = prevIt; drawIt != it; ++drawIt)
     272           0 :                     drawIt->draw();
     273             :                 // Write the buffer to the display
     274           0 :                 previousDisplay->display();
     275             :             }
     276           0 :             if (it == end)
     277           0 :                 break;
     278           0 :             prevIt = it;
     279           0 :             previousDisplay = &it->getDisplay();
     280           0 :             dirty = false;
     281             :         }
     282           0 :     }
     283             : }
     284             : 
     285             : #if CS_TRUE_CONTROL_SURFACE_INSTANCE || defined(DOXYGEN)
     286             : Control_Surface_ &Control_Surface = Control_Surface_::getInstance();
     287             : #endif
     288             : 
     289             : END_CS_NAMESPACE

Generated by: LCOV version 1.15