// Copyright 2008-2020 David Robillard // SPDX-License-Identifier: GPL-3.0-or-later #ifndef PATCHAGE_PORTID_HPP #define PATCHAGE_PORTID_HPP #include "ClientID.hpp" #include "ClientType.hpp" #include "warnings.hpp" #include #include #include #include #include #include #include #include namespace patchage { /// An ID for some port on a client (program) struct PortID { using Type = ClientType; PortID(const PortID& copy) = default; PortID& operator=(const PortID& copy) = default; PortID(PortID&& id) = default; PortID& operator=(PortID&& id) = default; ~PortID() = default; /// Return an ID for a JACK port by full name (like "client:port") static PortID jack(std::string name) { return PortID{Type::jack, std::move(name)}; } /// Return an ID for a JACK port by separate client and port name static PortID jack(const std::string& client_name, const std::string& port_name) { return PortID{Type::jack, client_name + ":" + port_name}; } /// Return an ID for an ALSA Sequencer port by ID static PortID alsa(const uint8_t client_id, const uint8_t port, const bool is_input) { return PortID{Type::alsa, client_id, port, is_input}; } /// Return the ID of the client that hosts this port ClientID client() const { switch (_type) { case Type::jack: return ClientID::jack(_jack_name.substr(0, _jack_name.find(':'))); case Type::alsa: return ClientID::alsa(_alsa_client); } PATCHAGE_UNREACHABLE(); } Type type() const { return _type; } const std::string& jack_name() const { return _jack_name; } uint8_t alsa_client() const { return _alsa_client; } uint8_t alsa_port() const { return _alsa_port; } bool alsa_is_input() const { return _alsa_is_input; } private: PortID(const Type type, std::string jack_name) : _type{type} , _jack_name{std::move(jack_name)} { assert(_type == Type::jack); assert(_jack_name.find(':') != std::string::npos); assert(_jack_name.find(':') > 0); assert(_jack_name.find(':') < _jack_name.length() - 1); } PortID(const Type type, const uint8_t alsa_client, const uint8_t alsa_port, const bool is_input) : _type{type} , _alsa_client{alsa_client} , _alsa_port{alsa_port} , _alsa_is_input{is_input} { assert(_type == Type::alsa); } Type _type; ///< Determines which field is active std::string _jack_name; ///< Full port name for Type::jack uint8_t _alsa_client{}; ///< Client ID for Type::alsa uint8_t _alsa_port{}; ///< Port ID for Type::alsa bool _alsa_is_input{}; ///< Input flag for Type::alsa }; inline std::ostream& operator<<(std::ostream& os, const PortID& id) { switch (id.type()) { case PortID::Type::jack: return os << "jack:" << id.jack_name(); case PortID::Type::alsa: return os << "alsa:" << static_cast(id.alsa_client()) << ":" << static_cast(id.alsa_port()) << ":" << (id.alsa_is_input() ? "in" : "out"); } assert(false); return os; } inline bool operator==(const PortID& lhs, const PortID& rhs) { if (lhs.type() != rhs.type()) { return false; } switch (lhs.type()) { case PortID::Type::jack: return lhs.jack_name() == rhs.jack_name(); case PortID::Type::alsa: return std::make_tuple( lhs.alsa_client(), lhs.alsa_port(), lhs.alsa_is_input()) == std::make_tuple( rhs.alsa_client(), rhs.alsa_port(), rhs.alsa_is_input()); } assert(false); return false; } inline bool operator<(const PortID& lhs, const PortID& rhs) { if (lhs.type() != rhs.type()) { return lhs.type() < rhs.type(); } switch (lhs.type()) { case PortID::Type::jack: return lhs.jack_name() < rhs.jack_name(); case PortID::Type::alsa: return std::make_tuple( lhs.alsa_client(), lhs.alsa_port(), lhs.alsa_is_input()) < std::make_tuple( rhs.alsa_client(), rhs.alsa_port(), rhs.alsa_is_input()); } assert(false); return false; } } // namespace patchage namespace std { template<> struct hash { size_t operator()(const patchage::PortID::Type& v) const noexcept { return hash()(static_cast(v)); } }; } // namespace std template<> struct fmt::formatter : fmt::ostream_formatter {}; #endif // PATCHAGE_PORTID_HPP