Something went wrong. Try again.
Mixxx DJ software with MCP, Subsonic/Navidrome streaming library support — browse and load tracks from your self-hosted music server mixxx.org
subsonic navidrome streaming audio dj mac linux midi
Something went wrong. Try again.
8.8 kB · 236 lines
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237#pragma once
#include <QElapsedTimer>
#include "controllers/controllermappinginfo.h"#include "controllers/legacycontrollermapping.h"#include "util/duration.h"#include "util/runtimeloggingcategory.h"
class ControllerJSProxy;class ControllerScriptEngineLegacy;
enum class PhysicalTransportProtocol { UNKNOWN, USB, BlueTooth, I2C, SPI, FireWire // IEEE 1394};
enum class DataRepresentationProtocol { MIDI, HID, USB_BULK_TRANSFER // Bulk is only one of the 4 USB transfer modes};
/// This is a base class representing a physical (or software) controller. It/// must be inherited by a class that implements it on some API. Note that the/// subclass' destructor should call close() at a minimum.class Controller : public QObject { Q_OBJECT public: explicit Controller(const QString& deviceName); ~Controller() override; // Subclass should call close() at minimum.
/// The object that is exposed to the JS scripts as the "controller" object. /// Subclasses of Controller can return a subclass of ControllerJSProxy to further /// customize their JS api. virtual ControllerJSProxy* jsProxy();
/// Returns the extension for the controller (type) mapping files. This is /// used by the ControllerManager to display only relevant mapping files for /// the controller (type.) virtual QString mappingExtension() = 0;
virtual void setMapping(std::shared_ptr<LegacyControllerMapping> pMapping) = 0; std::shared_ptr<LegacyControllerMapping> getMapping() { // return the unused mutable copy of the mapping, that can be edited in the GUI thread // and than adopted again via setMapping() return m_pMutableMapping; }
virtual QList<LegacyControllerMapping::ScriptFileInfo> getMappingScriptFiles() = 0; virtual QList<std::shared_ptr<AbstractLegacyControllerSetting>> getMappingSettings() = 0;#ifdef MIXXX_USE_QML virtual QList<LegacyControllerMapping::QMLModuleInfo> getMappingModules() = 0; virtual QList<LegacyControllerMapping::ScreenInfo> getMappingInfoScreens() = 0;#endif
inline bool isOpen() const { return m_bIsOpen; } inline bool isOutputDevice() const { return m_bIsOutputDevice; } inline bool isInputDevice() const { return m_bIsInputDevice; } inline const QString& getName() const { return m_sDeviceName; } virtual PhysicalTransportProtocol getPhysicalTransportProtocol() const = 0; static QString physicalTransport2String(PhysicalTransportProtocol protocol); virtual DataRepresentationProtocol getDataRepresentationProtocol() const = 0;
virtual QString getVendorString() const = 0; virtual QString getProductString() const = 0; virtual std::optional<uint16_t> getVendorId() const = 0; virtual std::optional<uint16_t> getProductId() const = 0; virtual QString getSerialNumber() const = 0; virtual std::optional<uint8_t> getUsbInterfaceNumber() const = 0;
virtual bool isMappable() const = 0; inline bool isLearning() const { return m_bLearning; }
inline std::shared_ptr<ControllerScriptEngineLegacy> getScriptEngine() const { return m_pScriptEngineLegacy; }
virtual bool matchMapping(const MappingInfo& mapping) = 0;
signals: /// Emitted when the controller is opened or closed. void openChanged(bool bOpen);
/// Emitted when the controller has started a new engine. void engineStarted(const ControllerScriptEngineLegacy* engine);
/// Emitted when the controller has stopped its engine. void engineStopped();
// Making these slots protected/private ensures that other parts of Mixxx can // only signal them which allows us to use no locks. protected slots: // TODO(XXX) move this into the inherited classes since is not called here // (via Controller) and re-implemented anyway in most cases.
// Handles packets of raw bytes and passes them to an ".incomingData" script // function that is assumed to exist. (Sub-classes may want to reimplement // this if they have an alternate way of handling such data.) virtual void receive(const QByteArray& data, mixxx::Duration timestamp); virtual void slotBeforeEngineShutdown();
// Puts the controller in and out of learning mode. void startLearning(); void stopLearning();
protected: virtual bool applyMapping(const QString& resourcePath);
template<typename SpecificMappingType> requires(std::is_final_v<SpecificMappingType> == true) std::unique_ptr<SpecificMappingType> downcastAndClone(const LegacyControllerMapping* pMapping) { // When unsetting a mapping (select 'No mapping') we receive a nullptr if (!pMapping) { return nullptr; } auto* pSpecifiedMapping = dynamic_cast<const SpecificMappingType*>(pMapping); VERIFY_OR_DEBUG_ASSERT(pSpecifiedMapping) { return nullptr; } // Controller cannot take ownership if pMapping is referenced elsewhere because // the controller polling thread needs exclusive accesses to the non-thread safe // LegacyControllerMapping. So we do a deep copy here. return std::make_unique<SpecificMappingType>(*pSpecifiedMapping); }
// The length parameter is here for backwards compatibility for when scripts // were required to specify it. virtual void send(const QList<int>& data, unsigned int length = 0);
// To be called in sub-class' open() functions after opening the device but // before starting any input polling/processing. virtual void startEngine();
// To be called in sub-class' close() functions after stopping any input // polling/processing but before closing the device. virtual void stopEngine();
// To be called when receiving events void triggerActivity();
inline void setOutputDevice(bool outputDevice) { m_bIsOutputDevice = outputDevice; } inline void setInputDevice(bool inputDevice) { m_bIsInputDevice = inputDevice; } inline void setOpen(bool open) { m_bIsOpen = open; emit openChanged(m_bIsOpen); }
const QString m_sDeviceName; const RuntimeLoggingCategory m_logBase; const RuntimeLoggingCategory m_logInput; const RuntimeLoggingCategory m_logOutput; std::shared_ptr<LegacyControllerMapping> m_pMutableMapping;
public: // This must be reimplemented by sub-classes desiring to send raw bytes to a // controller. Return true in case of successful completion, false in case // of partial completion or failure. virtual bool sendBytes(const QByteArray& data) = 0;
private: // but used by ControllerManager virtual int open(const QString& resourcePath) = 0; virtual int close() = 0; // Requests that the device poll if it is a polling device. Returns true // if events were handled. virtual bool poll() { return false; }
// Returns true if this device should receive polling signals via calls to // its poll() method. virtual bool isPolling() const { return false; }
private: /// Controllers have multiple ownership over an engine. /// A ControllerScriptEngine must not own a controller. std::shared_ptr<ControllerScriptEngineLegacy> m_pScriptEngineLegacy;
// Verbose and unique description of device type, defaults to empty QString m_sDeviceCategory; // Flag indicating if this device supports output (receiving data from // Mixxx) bool m_bIsOutputDevice; // Flag indicating if this device supports input (sending data to Mixxx) bool m_bIsInputDevice; // Indicates whether or not the device has been opened for input/output. bool m_bIsOpen; bool m_bLearning; QElapsedTimer m_userActivityInhibitTimer;
friend class ControllerJSProxy; // accesses lots of our stuff, but in the same thread friend class ControllerManager; // For testing friend class MappingTestFixture; friend class MidiControllerTest;};
// An object of this class gets exposed to the JS engine, so the methods of this class// constitute the api that is provided to scripts under "controller" object.// See comments on ControllerEngineJSProxy.class ControllerJSProxy : public QObject { Q_OBJECT public: explicit ControllerJSProxy(Controller* m_pController) : m_pController(m_pController) { }
// The length parameter is here for backwards compatibility for when scripts // were required to specify it. Q_INVOKABLE virtual void send(const QList<int>& data, unsigned int length = 0) { Q_UNUSED(length); m_pController->send(data, data.length()); }
private: Controller* const m_pController;};