1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 /* 3 Rosegarden 4 A sequencer and musical notation editor. 5 Copyright 2020 the Rosegarden development team. 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the 10 License, or (at your option) any later version. See the file 11 COPYING included with this distribution for more information. 12 */ 13 14 #pragma once 15 16 #include "base/Instrument.h" 17 #include "KorgNanoKontrol2.h" 18 #include "base/MidiProgram.h" // For MidiByte 19 20 #include <QObject> 21 #include <QString> 22 23 #include <string> 24 25 26 namespace Rosegarden 27 { 28 29 30 class MappedEvent; 31 class RosegardenDocument; 32 class RosegardenMainWindow; 33 34 35 /// Support for the "external controller" port. 36 /** 37 * The external controller port allows MIDI control surfaces to control 38 * the main window, MIDI Mixer window, and Audio Mixer window. 39 * 40 * To use, be sure to enable the external controller port in the preferences: 41 * 42 * Edit > Preferences... > MIDI > General tab > External controller port 43 * checkbox. 44 * 45 * After a restart of Rosegarden, an "external controller" port will 46 * appear for MIDI control surfaces to connect to. 47 * 48 * The current window can be selected via CC81. See processEvent(). 49 * 50 * Depending on the current active window, the behavior of the external 51 * controller port will change. For the main window, the following features 52 * are available via control changes on *channel 1*: 53 * 54 * CC 82: select Track 55 * CC 7: Adjust volume on current Track 56 * CC 10: Adjust pan on current track 57 * CC x: Adjust that CC on current track 58 * 59 * See RosegardenMainViewWidget::slotExternalController() for details. 60 * 61 * For the MIDI Mixer window and Audio Mixer window, CCs can be sent on 62 * any of the 16 channels to control those channels on the mixer. See 63 * MidiMixerWindow::slotExternalController() and 64 * AudioMixerWindow2::slotExternalController() for details. 65 * 66 * CCs are also sent out the external controller port to allow motorized 67 * control surfaces to stay in sync with the current state of the CCs. 68 * 69 */ 70 class ExternalController : public QObject 71 { 72 Q_OBJECT 73 74 public: 75 /// The global instance. 76 static ExternalController &self(); 77 78 static bool isEnabled(); 79 80 enum ControllerType { CT_RosegardenNative, CT_KorgNanoKontrol2 }; 81 void setType(ControllerType controllerType); getType()82 ControllerType getType() const { return m_controllerType; } isNative()83 bool isNative() const { return m_controllerType == CT_RosegardenNative; } 84 85 /// Call this from RosegardenMainWindow's ctor. 86 /** 87 * This has to be called at the right moment, before the autoload 88 * occurs. Otherwise the very first RMW::documentLoaded() will not get 89 * in here. 90 */ 91 void connectRMW(RosegardenMainWindow *rmw); 92 93 /// The three windows that currently handle external controller events. 94 enum Window { Main, AudioMixer, MidiMixer }; 95 /// The currently active window for external controller events. 96 /** 97 * External controller events are forwarded to the currently active 98 * window. 99 * 100 * Set by the three windows that can handle external controller events. 101 */ 102 Window activeWindow; 103 104 /// Handle MappedEvent's from the external controller port. 105 /** 106 * This routine doesn't handle the events directly. Instead 107 * it passes the events on to the appropriate handler based 108 * on which control surface has been selected in the preferences. 109 * 110 * See processRGNative() and KorgNanoKontrol2. 111 */ 112 void processEvent(const MappedEvent *event); 113 114 /// Send a control change message out the external controller port. 115 static void send(MidiByte channel, MidiByte controlNumber, MidiByte value); 116 static void sendAllCCs( 117 const Instrument *instrument, MidiByte channel = MidiMaxValue); 118 119 /// Send SysEx from hex string. DO NOT include F0/F7. 120 static void sendSysExHex(const QString &hexString); 121 /// Send SysEx from raw string. DO NOT include F0/F7. 122 static void sendSysExRaw(const std::string &rawString); 123 /// Blocking with timeout. Returns false if timed out. 124 bool getSysEx(std::string &rawString); 125 126 signals: 127 128 /// Connected to RosegardenMainViewWidget::slotExternalController(). 129 void externalControllerRMVW(const MappedEvent *event); 130 /// Connected to MidiMixerWindow::slotExternalController(). 131 void externalControllerMMW(const MappedEvent *event); 132 /// Connected to AudioMixerWindow::slotExternalController(). 133 void externalControllerAMW2(const MappedEvent *event); 134 135 private slots: 136 137 /// Connected to RMW::documentLoaded() 138 void slotDocumentLoaded(RosegardenDocument *doc); 139 /// Connected to RD::documentModified() 140 void slotDocumentModified(bool); 141 142 /// Connected to InstrumentStaticSignals::controlChange(). 143 void slotControlChange(Instrument *instrument, int cc); 144 145 /// Connected to SequenceManager::signalPlaying(). 146 void slotPlaying(bool checked); 147 /// Connected to SequenceManager::signalRecording(). 148 void slotRecording(bool checked); 149 150 private: 151 152 // Access through self() only. 153 ExternalController(); 154 155 ControllerType m_controllerType; 156 157 /// Cache of the last Instrument we were tracking for RosegardenMainWindow. 158 InstrumentId m_instrumentId; 159 160 /// Handle Rosegarden's native control surface. 161 /** 162 * This routine handles remote control events received from a 163 * device connected to the "external controller" port. 164 * 165 * This routine handles controller 81 which opens or 166 * brings to the top various windows based on the value. 167 * 168 * All other events are forwarded to the active window. 169 * See m_activeWindow. 170 */ 171 void processRGNative(const MappedEvent *event); 172 173 bool m_playing; 174 bool m_recording; 175 176 KorgNanoKontrol2 korgNanoKontrol2; 177 178 }; 179 180 181 } 182