#pragma once #include #include #include #if !__has_include() && !__has_include() #if defined(LIBREMIDI_JACK) #undef LIBREMIDI_JACK #endif #endif #if !defined(LIBREMIDI_ALSA) && !defined(LIBREMIDI_JACK) && !defined(LIBREMIDI_COREMIDI) \ && !defined(LIBREMIDI_WINMM) #define LIBREMIDI_DUMMY #endif #if defined(LIBREMIDI_ALSA) #include #include #if LIBREMIDI_ALSA_HAS_RAMWIDI #include #endif #if LIBREMIDI_ALSA_HAS_UMP #include #include #endif #endif #if defined(LIBREMIDI_JACK) #include #endif #if defined(LIBREMIDI_PIPEWIRE) #include #endif #if defined(LIBREMIDI_COREMIDI) #include #include #endif #if defined(LIBREMIDI_WINMM) #include #endif #if defined(LIBREMIDI_WINUWP) #include #endif #if defined(LIBREMIDI_WINMIDI) #include #endif #if defined(LIBREMIDI_EMSCRIPTEN) #include #endif #include #if defined(LIBREMIDI_KEYBOARD) #include #endif #if defined(LIBREMIDI_NETWORK) #include #include #endif namespace libremidi { // The order here will control the order of the API search in // the constructor. template constexpr auto make_tl(unused, Args...) { return std::tuple{}; } namespace midi1 { static constexpr auto available_backends = make_tl( 0 #if defined(LIBREMIDI_ALSA) , alsa_seq::backend{} #if LIBREMIDI_ALSA_HAS_RAMWIDI , alsa_raw::backend{} #endif #endif #if defined(LIBREMIDI_COREMIDI) , core_backend{} #endif #if defined(LIBREMIDI_WINMM) , winmm_backend{} #endif #if defined(LIBREMIDI_WINUWP) , winuwp_backend{} #endif #if defined(LIBREMIDI_EMSCRIPTEN) , emscripten_backend{} #endif #if defined(LIBREMIDI_JACK) , jack_backend{} #endif #if defined(LIBREMIDI_PIPEWIRE) , pipewire::backend{} #endif #if defined(LIBREMIDI_KEYBOARD) , kbd_backend{} #endif #if defined(LIBREMIDI_NETWORK) , net::backend{} #endif , dummy_backend{}); // There should always be at least one back-end. static_assert(std::tuple_size_v >= 1); template auto for_all_backends(F&& f) { std::apply([&](auto&&... x) { ((x.available() && (f(x), true)), ...); }, available_backends); } template auto for_backend(libremidi::API api, F&& f) { static constexpr auto is_api = [](auto& backend, libremidi::API api) { return backend.available() && backend.API == api; }; std::apply([&](auto&&... b) { ((is_api(b, api) && (f(b), true)) || ...); }, available_backends); } } namespace midi2 { static constexpr auto available_backends = make_tl( 0 #if defined(LIBREMIDI_ALSA) && LIBREMIDI_ALSA_HAS_UMP , alsa_seq_ump::backend{}, alsa_raw_ump::backend{} #endif #if defined(LIBREMIDI_COREMIDI) , coremidi_ump::backend{} #endif #if defined(LIBREMIDI_WINMIDI) , winmidi::backend{} #endif #if defined(LIBREMIDI_NETWORK) , net_ump::backend{} #endif , dummy_backend{}); // There should always be at least one back-end. static_assert(std::tuple_size_v >= 1); template auto for_all_backends(F&& f) { std::apply([&](auto&&... x) { (f(x), ...); }, available_backends); } template auto for_backend(libremidi::API api, F&& f) { static constexpr auto is_api = [](auto& backend, libremidi::API api) { return backend.API == api; }; std::apply([&](auto&&... b) { ((is_api(b, api) && (f(b), true)) || ...); }, available_backends); } } namespace midi_any { template auto for_all_backends(F&& f) { midi1::for_all_backends(f); midi2::for_all_backends(f); } template auto for_backend(libremidi::API api, F&& f) { midi1::for_backend(api, f); midi2::for_backend(api, f); } void for_input_configuration(auto f, std::any& api_conf) { auto from_api = [&](T& /*backend*/) mutable { if (auto conf = std::any_cast(&api_conf)) { f(*conf); return true; } return false; }; if (std::apply([&](auto&&... b) { return (from_api(b) || ...); }, midi1::available_backends)) return; std::apply([&](auto&&... b) { return (from_api(b) || ...); }, midi2::available_backends); } void for_output_configuration(auto f, std::any& api_conf) { auto from_api = [&](T& /*backend*/) mutable { if (auto conf = std::any_cast(&api_conf)) { f(*conf); return true; } return false; }; if (std::apply([&](auto&&... b) { return (from_api(b) || ...); }, midi1::available_backends)) return; std::apply([&](auto&&... b) { return (from_api(b) || ...); }, midi2::available_backends); } void for_observer_configuration(auto f, std::any& api_conf) { auto from_api = [&](T& /*backend*/) mutable { if (auto conf = std::any_cast(&api_conf)) { f(*conf); return true; } return false; }; if (std::apply([&](auto&&... b) { return (from_api(b) || ...); }, midi1::available_backends)) return; std::apply([&](auto&&... b) { return (from_api(b) || ...); }, midi2::available_backends); } } }